Skip to content

[SPIRV] Preserve implicit bitcast #151041

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 30, 2025
Merged

Conversation

farzonl
Copy link
Member

@farzonl farzonl commented Jul 28, 2025

fixes #146942

Issue

The cause of the bug is in InstCombine which is converting our load of float vec4 and bitcast to i32 vec4 into one load of i32 vec4. That means wr have to do a legalization in the spirv backend to convert back

 -  %3 = load <4 x i32>, ptr addrspace(11) %2, align 16
 +  %3 = load <4 x float>, ptr addrspace(11) %2, align 16
 +  %4 = bitcast <4 x float> %3 to <4 x i32>
Image

https://godbolt.org/z/K4GeM4fKT

The Fix

Just removing the assert isn't enough to fix this bug. If we do so we get an assert later
Assertion failed: (!storageClassRequiresExplictLayout(SC)), function getOrCreateSPIRVPointerType, file SPIRVGlobalRegistry.cpp, line 1806.

If we just remove the assert the CreateShuffleVector uses the source type via the NewLoad when the Output type needs to be the TargetType.

We also can't useCreateBitCast That will feed the right types for the ShuffleVector but it doesn't emit OpBitcast. the llvmIR isn't translated over to MIR.

The fix then is to emit spv_bitcast just like what SPIRVEmitIntrinsics::visitBitCastInst does.

@llvmbot
Copy link
Member

llvmbot commented Jul 28, 2025

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

Author: Farzon Lotfi (farzonl)

Changes

fixes #146942

Issue

The cause of the bug is in InstCombine which is converting hour load of float vec4 and bitcast to i32 vec4 into one load of i32 vec4. It seems like we will have to do a legalization in the spirv backent to convert

 -  %3 = load &lt;4 x i32&gt;, ptr addrspace(11) %2, align 16
 +  %3 = load &lt;4 x float&gt;, ptr addrspace(11) %2, align 16
 +  %4 = bitcast &lt;4 x float&gt; %3 to &lt;4 x i32&gt;

<img width="2566" height="548" alt="Image" src="https://github.com/user-attachments/assets/0bf8813c-70f8-47df-8207-ab7da54f5382" />

https://godbolt.org/z/K4GeM4fKT

The Fix

Just removing the assert isn't enough to fix this bug. If we do so we get an assert later
Assertion failed: (!storageClassRequiresExplictLayout(SC)), function getOrCreateSPIRVPointerType, file SPIRVGlobalRegistry.cpp, line 1806.

If we just remove the assert the CreateShuffleVector uses the source type via the NewLoad when the Output type needs to be the TargetType. CreateBitCast allows us to use the right type for the ShuffleVector even though we don't emit the bitcast.


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

2 Files Affected:

  • (modified) llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp (+6-6)
  • (added) llvm/test/CodeGen/SPIRV/hlsl-resources/issue-146942-ptr-cast.ll (+24)
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp
index 5cda6a07352d5..7e9c9c62cd889 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp
@@ -74,17 +74,17 @@ class SPIRVLegalizePointerCast : public FunctionPass {
   // Returns the loaded value.
   Value *loadVectorFromVector(IRBuilder<> &B, FixedVectorType *SourceType,
                               FixedVectorType *TargetType, Value *Source) {
-    // We expect the codegen to avoid doing implicit bitcast from a load.
-    assert(TargetType->getElementType() == SourceType->getElementType());
-    assert(TargetType->getNumElements() < SourceType->getNumElements());
-
+    assert(TargetType->getNumElements() <= SourceType->getNumElements());
     LoadInst *NewLoad = B.CreateLoad(SourceType, Source);
-    buildAssignType(B, SourceType, NewLoad);
+    Value *AssignType = NewLoad;
+    if (TargetType->getElementType() != SourceType->getElementType())
+      AssignType = B.CreateBitCast(NewLoad, TargetType);
+    buildAssignType(B, SourceType, AssignType);
 
     SmallVector<int> Mask(/* Size= */ TargetType->getNumElements());
     for (unsigned I = 0; I < TargetType->getNumElements(); ++I)
       Mask[I] = I;
-    Value *Output = B.CreateShuffleVector(NewLoad, NewLoad, Mask);
+    Value *Output = B.CreateShuffleVector(AssignType, AssignType, Mask);
     buildAssignType(B, TargetType, Output);
     return Output;
   }
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/issue-146942-ptr-cast.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/issue-146942-ptr-cast.ll
new file mode 100644
index 0000000000000..859b6eca8c084
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/issue-146942-ptr-cast.ll
@@ -0,0 +1,24 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %}
+
+@.str = private unnamed_addr constant [4 x i8] c"In3\00", align 1
+@.str.2 = private unnamed_addr constant [5 x i8] c"Out3\00", align 1
+
+; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
+define void @main() local_unnamed_addr #0 {
+  ; CHECK: %[[#INT32:]] = OpTypeInt 32 0
+  ; CHECK: %[[#INT4:]] = OpTypeVector %[[#INT32]] 4
+  ; CHECK: %[[#FLOAT:]] = OpTypeFloat 32
+  ; CHECK: %[[#FLOAT4:]] = OpTypeVector %[[#FLOAT]] 4
+  ; CHECK: %[[#BUFFER_LOAD:]] = OpLoad %[[#FLOAT4]] %{{[0-9]+}} Aligned 16
+  ; CHECK: %[[#VEC_SHUFFLE:]] = OpVectorShuffle %[[#INT4]] %[[#BUFFER_LOAD]] %[[#BUFFER_LOAD]] 0 1 2 3
+  %1 = tail call target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v4f32_12_0t(i32 0, i32 2, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %2 = tail call target("spirv.VulkanBuffer", [0 x <4 x i32>], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v4i32_12_1t(i32 0, i32 5, i32 1, i32 0, i1 false, ptr nonnull @.str.2)
+  %3 = tail call noundef align 16 dereferenceable(16) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v4f32_12_0t(target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 0) %1, i32 0)
+  %4 = load <4 x i32>, ptr addrspace(11) %3, align 16
+  %5 = tail call noundef align 16 dereferenceable(16) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v4i32_12_1t(target("spirv.VulkanBuffer", [0 x <4 x i32>], 12, 1) %2, i32 0)
+  store <4 x i32> %4, ptr addrspace(11) %5, align 16
+  ret void
+}
+
+attributes #0 = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) "approx-func-fp-math"="true" "frame-pointer"="all" "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
\ No newline at end of file

@farzonl farzonl force-pushed the bugfix/issue-146942 branch from 10e7c8b to 22bac98 Compare July 28, 2025 21:20
@farzonl farzonl changed the title [SPIRV] Preserve bitcast implicit bitcast [SPIRV] Preserve implicit bitcast Jul 28, 2025
@farzonl farzonl marked this pull request as draft July 28, 2025 23:16
@farzonl
Copy link
Member Author

farzonl commented Jul 28, 2025

Need to investigate spirv-val issue tomorrow.

farzonl added 2 commits July 29, 2025 08:49
…translated into MIR.

Instead we will do what `SPIRVEmitIntrinsics::visitBitCastInst` does and emit `spv_bitcast` instead of `BitCastInst`.
@farzonl farzonl force-pushed the bugfix/issue-146942 branch from 22bac98 to 52cc44e Compare July 29, 2025 16:00
@farzonl farzonl marked this pull request as ready for review July 29, 2025 16:03
Copy link
Contributor

@Keenuts Keenuts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix. LGTM, just an additional test to verify the interaction between both

@farzonl farzonl force-pushed the bugfix/issue-146942 branch from 98d43f2 to d06d08c Compare July 30, 2025 15:07
Copy link
Collaborator

@llvm-beanz llvm-beanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small comment formatting nit.

@farzonl farzonl merged commit 9de4970 into llvm:main Jul 30, 2025
10 checks passed
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.

[HLSL][SPIRV] Hitting assert when compiling program with 'asint' in HLSL
4 participants