[llvm] [SPIRV] Fix inconsistent operand order for counter resource intrinsic (PR #221646)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 09:51:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Helena Kotas (hekota)

<details>
<summary>Changes</summary>

The `llvm.spv.resource.handlefrombinding` intrinsic stores its binding operands in the order (DescriptorSet, BindingNo, ...). The `llvm.spv.resource.counterhandlefrombinding` intrinsic should use the same order.

The `llvm.spv.resource.counterhandlefrombinding` intrinsic is currently emitted only by the `SPIRVLegalizeImplicitBinding` pass. The pass previously built its operands in the wrong order, and the instruction selector repeated the same inversion when emitting decorations.

This change makes the operand order consistent with `llvm.spv.resource.handlefrombinding`.

Test update closes a coverage gap - there were no tests for explicit `llvm.spv.resource.counterhandlefrombinding` calls.

Assisted by GPT-5.6 Sol.

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


3 Files Affected:

- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+2-2) 
- (modified) llvm/lib/Target/SPIRV/SPIRVLegalizeImplicitBinding.cpp (+7-5) 
- (modified) llvm/test/CodeGen/SPIRV/hlsl-resources/ImplicitBinding.ll (+30-3) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 35242809b76b1..41e4dc290c099 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -5872,8 +5872,8 @@ bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
   assert(MainHandleDef->getIntrinsicID() ==
          Intrinsic::spv_resource_handlefrombinding);
 
-  uint32_t Set = getIConstVal(Intr.getOperand(4).getReg(), MRI);
-  uint32_t Binding = getIConstVal(Intr.getOperand(3).getReg(), MRI);
+  uint32_t Set = getIConstVal(Intr.getOperand(3).getReg(), MRI);
+  uint32_t Binding = getIConstVal(Intr.getOperand(4).getReg(), MRI);
   uint32_t ArraySize = getIConstVal(MainHandleDef->getOperand(4).getReg(), MRI);
   Register IndexReg = MainHandleDef->getOperand(5).getReg();
   std::string CounterName =
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizeImplicitBinding.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizeImplicitBinding.cpp
index 4009b2872d624..738ba182bd273 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizeImplicitBinding.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizeImplicitBinding.cpp
@@ -93,9 +93,9 @@ struct BindingInfoCollector : public InstVisitor<BindingInfoCollector> {
     } else if (CI.getIntrinsicID() ==
                Intrinsic::spv_resource_counterhandlefrombinding) {
       const uint32_t DescSet =
-          cast<ConstantInt>(CI.getArgOperand(2))->getZExtValue();
-      const uint32_t Binding =
           cast<ConstantInt>(CI.getArgOperand(1))->getZExtValue();
+      const uint32_t Binding =
+          cast<ConstantInt>(CI.getArgOperand(2))->getZExtValue();
       addBinding(DescSet, Binding);
     } else if (CI.getIntrinsicID() ==
                Intrinsic::spv_resource_counterhandlefromimplicitbinding) {
@@ -122,12 +122,14 @@ static uint32_t getOrderId(const CallInst *CI) {
 static uint32_t getDescSet(const CallInst *CI) {
   uint32_t DescSetArgIdx;
   switch (CI->getIntrinsicID()) {
-  case Intrinsic::spv_resource_handlefromimplicitbinding:
   case Intrinsic::spv_resource_handlefrombinding:
+    DescSetArgIdx = 0;
+    break;
+  case Intrinsic::spv_resource_handlefromimplicitbinding:
+  case Intrinsic::spv_resource_counterhandlefrombinding:
     DescSetArgIdx = 1;
     break;
   case Intrinsic::spv_resource_counterhandlefromimplicitbinding:
-  case Intrinsic::spv_resource_counterhandlefrombinding:
     DescSetArgIdx = 2;
     break;
   default:
@@ -269,8 +271,8 @@ void SPIRVLegalizeImplicitBindingImpl::replaceCounterHandleCall(
 
   SmallVector<Value *, 8> Args;
   Args.push_back(OldCI->getArgOperand(0));
-  Args.push_back(Builder.getInt32(NewBinding));
   Args.push_back(Builder.getInt32(DescSet));
+  Args.push_back(Builder.getInt32(NewBinding));
 
   Type *Tys[] = {OldCI->getType(), OldCI->getArgOperand(0)->getType()};
   Function *NewFunc = Intrinsic::getOrInsertDeclaration(
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImplicitBinding.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImplicitBinding.ll
index 2964da9058104..07c803dcdcd01 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImplicitBinding.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImplicitBinding.ll
@@ -9,6 +9,8 @@
 @.str.10 = private unnamed_addr constant [2 x i8] c"g\00", align 1
 @.str.12 = private unnamed_addr constant [2 x i8] c"h\00", align 1
 @.str.14 = private unnamed_addr constant [2 x i8] c"i\00", align 1
+ at .str.15 = private unnamed_addr constant [2 x i8] c"j\00", align 1
+ at .str.16 = private unnamed_addr constant [2 x i8] c"k\00", align 1
 
 ; CHECK-DAG: OpName [[b:%[0-9]+]] "b"
 ; CHECK-DAG: OpName [[c:%[0-9]+]] "c"
@@ -18,6 +20,10 @@
 ; CHECK-DAG: OpName [[g:%[0-9]+]] "g"
 ; CHECK-DAG: OpName [[h:%[0-9]+]] "h"
 ; CHECK-DAG: OpName [[i:%[0-9]+]] "i"
+; CHECK-DAG: OpName [[j:%[0-9]+]] "j"
+; CHECK-DAG: OpName [[j_counter:%[0-9]+]] "j.counter"
+; CHECK-DAG: OpName [[k:%[0-9]+]] "k"
+; CHECK-DAG: OpName [[k_counter:%[0-9]+]] "k.counter"
 ; CHECK-DAG: OpDecorate [[b]] DescriptorSet 0
 ; CHECK-DAG: OpDecorate [[b]] Binding 1
 ; CHECK-DAG: OpDecorate [[c]] DescriptorSet 0
@@ -35,7 +41,14 @@
 ; CHECK-NOT: OpDecorate [[h]] Binding 4
 ; CHECK-DAG: OpDecorate [[i]] DescriptorSet 10
 ; CHECK-DAG: OpDecorate [[i]] Binding 2
-
+; CHECK-DAG: OpDecorate [[j]] DescriptorSet 0
+; CHECK-DAG: OpDecorate [[j]] Binding 4
+; CHECK-DAG: OpDecorate [[j_counter]] DescriptorSet 0
+; CHECK-DAG: OpDecorate [[j_counter]] Binding 6
+; CHECK-DAG: OpDecorate [[k]] DescriptorSet 0
+; CHECK-DAG: OpDecorate [[k]] Binding 5
+; CHECK-DAG: OpDecorate [[k_counter]] DescriptorSet 0
+; CHECK-DAG: OpDecorate [[k_counter]] Binding 7
 
 define void @main() local_unnamed_addr #0 {
 entry:
@@ -72,9 +85,23 @@ entry:
   %24 = load i32, ptr addrspace(11) %23, align 4
   %add14.i = add nsw i32 %add12.i, %24
   %25 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.SignedImage_i32_5_2_0_0_2_0t(target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 0) %0, i32 0)
-  store i32 %add14.i, ptr addrspace(11) %25, align 4
+
+  %handle1 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) @llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 4, i32 0, i32 1, i32 0, ptr nonnull @.str.15)
+  %counter_handle1 = call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefrombinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0f32_12_1t(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %handle1, i32 0, i32 6)
+  %counter1 = tail call noundef i32 @llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer", i32, 12, 1) %counter_handle1, i8 1)
+  %ptr1 = call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %handle1, i32 0)
+  %value1 = load i32, ptr addrspace(11) %ptr1, align 4
+  %add15.i = add nsw i32 %add14.i, %value1
+
+  %handle2 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) @llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 5, i32 0, i32 1, i32 0, ptr nonnull @.str.16)
+  %counter_handle2 = call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefromimplicitbinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0f32_12_1t(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %handle2, i32 6, i32 0)
+  %counter2 = tail call noundef i32 @llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer", i32, 12, 1) %counter_handle2, i8 1)
+  %ptr2 = call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %handle2, i32 0)
+  %value2 = load i32, ptr addrspace(11) %ptr2, align 4
+  %add16.i = add nsw i32 %add15.i, %value2
+
+  store i32 %add16.i, ptr addrspace(11) %25, align 4
   ret void
 }
 
-
 attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }

``````````

</details>


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


More information about the llvm-commits mailing list