From 76245d410e39761ce9ccd39e222a77da50c8199a Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Mon, 10 Mar 2025 14:08:23 -0700 Subject: [PATCH 1/3] [SPIR-V] Add support for HLSL SV_GroupIndex This PR lowers the llvm.spv.flattened.thread.id.in.group intrinsic as a `LocalInvocationIndex` builtin variable. --- llvm/docs/SPIRVUsage.rst | 4 ++ llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 44 +++++++++++++++++++ .../SPIRV/hlsl-intrinsics/SV_GroupIndex.ll | 32 ++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index 3e19ff881dffc..ec842db586f77 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -405,6 +405,10 @@ SPIR-V backend, along with their descriptions and argument details. - 32-bit Integer - `[32-bit Integer]` - Retrieves the thread ID within a workgroup. Essential for identifying execution context in parallel compute operations. + * - `int_spv_flattened_thread_id_in_group` + - 32-bit Integer + - `[32-bit Integer]` + - Provides a flattened index for a given thread within a given group (SV_GroupIndex) * - `int_spv_create_handle` - Pointer - `[8-bit Integer]` diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index df3e137c80980..4a0e10db2f1e4 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -61,6 +61,7 @@ let TargetPrefix = "spv" in { def int_spv_thread_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>; def int_spv_group_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>; def int_spv_thread_id_in_group : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>; + def int_spv_flattened_thread_id_in_group : Intrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrWillReturn]>; def int_spv_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>; def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>; def int_spv_cross : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index b188f36ca9a9e..94c6b1960a02b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -341,6 +341,9 @@ class SPIRVInstructionSelector : public InstructionSelector { bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const; + bool loadBuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue, + Register ResVReg, const SPIRVType *ResType, + MachineInstr &I) const; bool loadHandleBeforePosition(Register &HandleReg, const SPIRVType *ResType, GIntrinsic &HandleDef, MachineInstr &Pos) const; }; @@ -3059,6 +3062,15 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, // builtin variable return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType, I); + case Intrinsic::spv_flattened_thread_id_in_group: + // The HLSL SV_GroupIndex semantic is lowered to + // llvm.spv.flattened.thread.id.in.group() intrinsic in LLVM IR for SPIR-V + // backend. + // + // In SPIR-V backend, llvm.spv.flattened.thread.id.in.group is translated to + // a `LocalInvocationIndex` builtin variable + return loadBuiltinInputID(SPIRV::BuiltIn::LocalInvocationIndex, ResVReg, + ResType, I); case Intrinsic::spv_fdot: return selectFloatDot(ResVReg, ResType, I); case Intrinsic::spv_udot: @@ -4005,6 +4017,38 @@ bool SPIRVInstructionSelector::loadVec3BuiltinInputID( return Result && MIB.constrainAllUses(TII, TRI, RBI); } +// Generate the instructions to load 32-bit integer builtin input IDs/Indices. +// Like LocalInvocationIndex +bool SPIRVInstructionSelector::loadBuiltinInputID( + SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg, + const SPIRVType *ResType, MachineInstr &I) const { + MachineIRBuilder MIRBuilder(I); + const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder); + const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType( + U32Type, MIRBuilder, SPIRV::StorageClass::Input); + + // Create new register for the input ID builtin variable. + Register NewRegister = + MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass); + MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64)); + GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF()); + + // Build global variable with the necessary decorations for the input ID + // builtin variable. + Register Variable = GR.buildGlobalVariable( + NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr, + SPIRV::StorageClass::Input, nullptr, true, true, + SPIRV::LinkageType::Import, MIRBuilder, false); + + // Load uint value from the global variable. + auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) + .addDef(ResVReg) + .addUse(GR.getSPIRVTypeID(U32Type)) + .addUse(Variable); + + return MIB.constrainAllUses(TII, TRI, RBI); +} + SPIRVType *SPIRVInstructionSelector::widenTypeToVec4(const SPIRVType *Type, MachineInstr &I) const { MachineIRBuilder MIRBuilder(I); diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll new file mode 100644 index 0000000000000..f21780c7576ca --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll @@ -0,0 +1,32 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: %[[#int:]] = OpTypeInt 32 0 +; CHECK-DAG: %[[#ptr_Input_int:]] = OpTypePointer Input %[[#int]] +; CHECK-DAG: %[[#LocalInvocationIndex:]] = OpVariable %[[#ptr_Input_int]] Input + +; CHECK-DAG: OpEntryPoint GLCompute {{.*}} %[[#LocalInvocationIndex]] +; CHECK-DAG: OpName %[[#LocalInvocationIndex]] "__spirv_BuiltInLocalInvocationIndex" +; CHECK-DAG: OpDecorate %[[#LocalInvocationIndex]] LinkageAttributes "__spirv_BuiltInLocalInvocationIndex" Import +; CHECK-DAG: OpDecorate %[[#LocalInvocationIndex]] BuiltIn LocalInvocationIndex + +target triple = "spirv-unknown-vulkan-library" + +declare void @local_index_user(i32) + +; Function Attrs: convergent noinline norecurse +define void @main() #1 { +entry: + +; CHECK: %[[#load:]] = OpLoad %[[#int]] %[[#LocalInvocationIndex]] + %1 = call i32 @llvm.spv.flattened.thread.id.in.group() + + call spir_func void @local_index_user(i32 %1) + ret void +} + +; Function Attrs: nounwind willreturn memory(none) +declare i32 @llvm.spv.flattened.thread.id.in.group() #3 + +attributes #1 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #3 = { nounwind willreturn memory(none) } From ef3f5fcb510f5720d8e3798ff04803aba960a6b5 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Mon, 17 Mar 2025 14:49:36 -0700 Subject: [PATCH 2/3] PR feedback --- llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 12 +++++++----- .../CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 94c6b1960a02b..d82675d4b8ef5 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -4023,14 +4023,16 @@ bool SPIRVInstructionSelector::loadBuiltinInputID( SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const { MachineIRBuilder MIRBuilder(I); - const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder); const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType( - U32Type, MIRBuilder, SPIRV::StorageClass::Input); + ResType, MIRBuilder, SPIRV::StorageClass::Input); // Create new register for the input ID builtin variable. Register NewRegister = - MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass); - MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64)); + MIRBuilder.getMRI()->createVirtualRegister(GR.getRegClass(PtrType)); + MIRBuilder.getMRI()->setType( + NewRegister, + LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Input), + GR.getPointerSize())); GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF()); // Build global variable with the necessary decorations for the input ID @@ -4043,7 +4045,7 @@ bool SPIRVInstructionSelector::loadBuiltinInputID( // Load uint value from the global variable. auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) .addDef(ResVReg) - .addUse(GR.getSPIRVTypeID(U32Type)) + .addUse(GR.getSPIRVTypeID(ResType)) .addUse(Variable); return MIB.constrainAllUses(TII, TRI, RBI); diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll index f21780c7576ca..ba70a7f1c63d1 100644 --- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll @@ -1,5 +1,5 @@ ; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s -; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %} ; CHECK-DAG: %[[#int:]] = OpTypeInt 32 0 ; CHECK-DAG: %[[#ptr_Input_int:]] = OpTypePointer Input %[[#int]] From e75c5ee2a6490855ad82cdde73489b5350bdae80 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Tue, 18 Mar 2025 11:08:18 -0700 Subject: [PATCH 3/3] Remove check for linkage attributes --- llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll index ba70a7f1c63d1..83caa62150cda 100644 --- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupIndex.ll @@ -7,7 +7,6 @@ ; CHECK-DAG: OpEntryPoint GLCompute {{.*}} %[[#LocalInvocationIndex]] ; CHECK-DAG: OpName %[[#LocalInvocationIndex]] "__spirv_BuiltInLocalInvocationIndex" -; CHECK-DAG: OpDecorate %[[#LocalInvocationIndex]] LinkageAttributes "__spirv_BuiltInLocalInvocationIndex" Import ; CHECK-DAG: OpDecorate %[[#LocalInvocationIndex]] BuiltIn LocalInvocationIndex target triple = "spirv-unknown-vulkan-library"