[llvm] [SPIR-V] Handle struct member loading from ptrcast (PR #130089)

via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 6 04:26:53 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-spir-v

Author: Nathan Gauër (Keenuts)

<details>
<summary>Changes</summary>

Adds support for loading the first element of an aggregate from a GEP instruction & load to the member type.

---
Full diff: https://github.com/llvm/llvm-project/pull/130089.diff


2 Files Affected:

- (modified) llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp (+13-10) 
- (added) llvm/test/CodeGen/SPIRV/pointers/load-struct.ll (+64) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp
index ec419d25cd317..2ccff9dd321ec 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp
@@ -103,12 +103,8 @@ class SPIRVLegalizePointerCast : public FunctionPass {
     auto *GEP = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
     GR->buildAssignPtr(B, ElementType, GEP);
 
-    const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
-    MachineMemOperand::Flags Flags = TLI->getLoadMemOperandFlags(
-        *BadLoad, BadLoad->getFunction()->getDataLayout());
-    Instruction *LI = B.CreateIntrinsic(
-        Intrinsic::spv_load, {BadLoad->getOperand(0)->getType()},
-        {GEP, B.getInt16(Flags), B.getInt8(BadLoad->getAlign().value())});
+    LoadInst *LI = B.CreateLoad(ElementType, GEP);
+    LI->setAlignment(BadLoad->getAlign());
     buildAssignType(B, ElementType, LI);
     return LI;
   }
@@ -123,6 +119,7 @@ class SPIRVLegalizePointerCast : public FunctionPass {
 
     auto *SAT = dyn_cast<ArrayType>(FromTy);
     auto *SVT = dyn_cast<FixedVectorType>(FromTy);
+    auto *SST = dyn_cast<StructType>(FromTy);
     auto *DVT = dyn_cast<FixedVectorType>(ToTy);
 
     B.SetInsertPoint(LI);
@@ -144,6 +141,11 @@ class SPIRVLegalizePointerCast : public FunctionPass {
     // - float3 v3 = vector4;
     else if (SVT && DVT)
       Output = loadVectorFromVector(B, SVT, DVT, OriginalOperand);
+    // Destination is the scalar type stored at the start of an aggregate.
+    // - struct S { float m };
+    // - float v = s.m;
+    else if (SST && SST->getTypeAtIndex(0u) == ToTy)
+      Output = loadFirstValueFromAggregate(B, ToTy, OriginalOperand, LI);
     else
       llvm_unreachable("Unimplemented implicit down-cast from load.");
 
@@ -166,10 +168,11 @@ class SPIRVLegalizePointerCast : public FunctionPass {
         continue;
       }
 
-      IntrinsicInst *Intrin = dyn_cast<IntrinsicInst>(User);
-      if (Intrin->getIntrinsicID() == Intrinsic::spv_assign_ptr_type) {
-        DeadInstructions.push_back(Intrin);
-        continue;
+      if (IntrinsicInst *Intrin = dyn_cast<IntrinsicInst>(User)) {
+        if (Intrin->getIntrinsicID() == Intrinsic::spv_assign_ptr_type) {
+          DeadInstructions.push_back(Intrin);
+          continue;
+        }
       }
 
       llvm_unreachable("Unsupported ptrcast user. Please fix.");
diff --git a/llvm/test/CodeGen/SPIRV/pointers/load-struct.ll b/llvm/test/CodeGen/SPIRV/pointers/load-struct.ll
new file mode 100644
index 0000000000000..280a7e4f9053b
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/load-struct.ll
@@ -0,0 +1,64 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG:     %[[#uint:]] = OpTypeInt 32 0
+; CHECK-DAG:    %[[#float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_fp:]] = OpTypePointer Function %[[#float]]
+; CHECK-DAG: %[[#float_pp:]] = OpTypePointer Private %[[#float]]
+; CHECK-DAG:  %[[#uint_fp:]] = OpTypePointer Function %[[#uint]]
+; CHECK-DAG:   %[[#uint_0:]] = OpConstant %[[#uint]] 0
+; CHECK-DAG:       %[[#sf:]] = OpTypeStruct %[[#float]]
+; CHECK-DAG:       %[[#su:]] = OpTypeStruct %[[#uint]]
+; CHECK-DAG:       %[[#sfuf:]] = OpTypeStruct %[[#float]] %[[#uint]] %[[#float]]
+; CHECK-DAG:    %[[#sf_fp:]] = OpTypePointer Function %[[#sf]]
+; CHECK-DAG:    %[[#su_fp:]] = OpTypePointer Function %[[#su]]
+; CHECK-DAG:    %[[#sfuf_fp:]] = OpTypePointer Function %[[#sfuf]]
+; CHECK-DAG:    %[[#sfuf_pp:]] = OpTypePointer Private %[[#sfuf]]
+
+%struct.SF = type { float }
+%struct.SU = type { i32 }
+%struct.SFUF = type { float, i32, float }
+
+ at gsfuf = external addrspace(10) global %struct.SFUF
+; CHECK: %[[#gsfuf:]] = OpVariable %[[#sfuf_pp]] Private
+
+define internal spir_func float @foo() {
+  %1 = alloca %struct.SF, align 4
+; CHECK: %[[#var:]]  = OpVariable %[[#sf_fp]] Function
+
+  %2 = load float, ptr %1, align 4
+; CHECK: %[[#tmp:]]  = OpAccessChain %[[#float_fp]] %[[#var]] %[[#uint_0]]
+; CHECK: %[[#val:]]  = OpLoad %[[#float]] %[[#tmp]] Aligned 4
+
+  ret float %2
+}
+
+define internal spir_func i32 @bar() {
+  %1 = alloca %struct.SU, align 4
+; CHECK: %[[#var:]]  = OpVariable %[[#su_fp]] Function
+
+  %2 = load i32, ptr %1, align 4
+; CHECK: %[[#tmp:]]  = OpAccessChain %[[#uint_fp]] %[[#var]] %[[#uint_0]]
+; CHECK: %[[#val:]]  = OpLoad %[[#uint]] %[[#tmp]] Aligned 4
+
+  ret i32 %2
+}
+
+define internal spir_func float @baz() {
+  %1 = alloca %struct.SFUF, align 4
+; CHECK: %[[#var:]]  = OpVariable %[[#sfuf_fp]] Function
+
+  %2 = load float, ptr %1, align 4
+; CHECK: %[[#tmp:]]  = OpAccessChain %[[#float_fp]] %[[#var]] %[[#uint_0]]
+; CHECK: %[[#val:]]  = OpLoad %[[#float]] %[[#tmp]] Aligned 4
+
+  ret float %2
+}
+
+define internal spir_func float @biz() {
+  %2 = load float, ptr addrspace(10) @gsfuf, align 4
+; CHECK: %[[#tmp:]]  = OpAccessChain %[[#float_pp]] %[[#gsfuf]] %[[#uint_0]]
+; CHECK: %[[#val:]]  = OpLoad %[[#float]] %[[#tmp]] Aligned 4
+
+  ret float %2
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/130089


More information about the llvm-commits mailing list