[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