Skip to content

Conversation

@Keenuts
Copy link
Contributor

@Keenuts Keenuts commented Mar 6, 2025

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

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

llvmbot commented Mar 6, 2025

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

Author: Nathan Gauër (Keenuts)

Changes

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 --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 }
+
+@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
+}

@Keenuts Keenuts merged commit 0aba833 into llvm:main Mar 19, 2025
14 checks passed
@Keenuts Keenuts deleted the struct-load branch March 19, 2025 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants