Author: Zhengxing li Date: 2025-01-04T14:02:39-08:00 New Revision: 7a761100960c0c9e2b2fa8a9ee233b137270bd73
URL: https://github.com/llvm/llvm-project/commit/7a761100960c0c9e2b2fa8a9ee233b137270bd73 DIFF: https://github.com/llvm/llvm-project/commit/7a761100960c0c9e2b2fa8a9ee233b137270bd73.diff LOG: [HLSL][SPIR-V] implement SV_GroupID semantic lowering (#121521) The HLSL SV_GroupID semantic attribute is lowered into @llvm.spv.group.id intrinsic in LLVM IR for SPIR-V target. In the SPIR-V backend, this is now translated to a `WorkgroupId` builtin variable. Fixes #118700 which's a follow-up work to #70120 Added: llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupID.ll Modified: clang/lib/CodeGen/CGHLSLRuntime.cpp clang/lib/CodeGen/CGHLSLRuntime.h clang/test/CodeGenHLSL/semantics/SV_GroupID.hlsl llvm/include/llvm/IR/IntrinsicsSPIRV.td llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index c354e58e15f4bb..5679bd71581795 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -395,7 +395,7 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, return buildVectorInput(B, GroupThreadIDIntrinsic, Ty); } if (D.hasAttr<HLSLSV_GroupIDAttr>()) { - llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_group_id); + llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic()); return buildVectorInput(B, GroupIDIntrinsic, Ty); } assert(false && "Unhandled parameter attribute"); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index edb87f9d5efdf9..3d5724118611cb 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -87,6 +87,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(Radians, radians) GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id) GENERATE_HLSL_INTRINSIC_FUNCTION(GroupThreadId, thread_id_in_group) + GENERATE_HLSL_INTRINSIC_FUNCTION(GroupId, group_id) GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) diff --git a/clang/test/CodeGenHLSL/semantics/SV_GroupID.hlsl b/clang/test/CodeGenHLSL/semantics/SV_GroupID.hlsl index 5e09f0fe06d4e6..3aa054afc90451 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_GroupID.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_GroupID.hlsl @@ -1,32 +1,36 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv -// Make sure SV_GroupID translated into dx.group.id. +// Make sure SV_GroupID translated into dx.group.id for directx target and spv.group.id for spirv target. -// CHECK: define void @foo() -// CHECK: %[[#ID:]] = call i32 @llvm.dx.group.id(i32 0) -// CHECK: call void @{{.*}}foo{{.*}}(i32 %[[#ID]]) +// CHECK: define void @foo() +// CHECK: %[[#ID:]] = call i32 @llvm.[[TARGET]].group.id(i32 0) +// CHECK-DXIL: call void @{{.*}}foo{{.*}}(i32 %[[#ID]]) +// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(i32 %[[#ID]]) [shader("compute")] [numthreads(8,8,1)] void foo(uint Idx : SV_GroupID) {} -// CHECK: define void @bar() -// CHECK: %[[#ID_X:]] = call i32 @llvm.dx.group.id(i32 0) -// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0 -// CHECK: %[[#ID_Y:]] = call i32 @llvm.dx.group.id(i32 1) -// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 -// CHECK: call void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]]) +// CHECK: define void @bar() +// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].group.id(i32 0) +// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0 +// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].group.id(i32 1) +// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 +// CHECK-DXIL: call void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]]) +// CHECK-SPIRV: call spir_func void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]]) [shader("compute")] [numthreads(8,8,1)] void bar(uint2 Idx : SV_GroupID) {} // CHECK: define void @test() -// CHECK: %[[#ID_X:]] = call i32 @llvm.dx.group.id(i32 0) +// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].group.id(i32 0) // CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0 -// CHECK: %[[#ID_Y:]] = call i32 @llvm.dx.group.id(i32 1) +// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].group.id(i32 1) // CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 -// CHECK: %[[#ID_Z:]] = call i32 @llvm.dx.group.id(i32 2) +// CHECK: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].group.id(i32 2) // CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2 -// CHECK: call void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]]) +// CHECK-DXIL: call void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]]) +// CHECK-SPIRV: call spir_func void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]]) [shader("compute")] [numthreads(8,8,1)] void test(uint3 Idx : SV_GroupID) {} diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index bcff0f20b985d4..8ebce408ff1380 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -59,6 +59,7 @@ let TargetPrefix = "spv" in { // The following intrinsic(s) are mirrored from IntrinsicsDirectX.td for HLSL support. 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_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>; def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>; diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 289d5f31664872..0fa0986a10c693 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -2881,6 +2881,14 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, // translated to a `LocalInvocationId` builtin variable return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg, ResType, I); + case Intrinsic::spv_group_id: + // The HLSL SV_GroupId semantic is lowered to + // llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend. + // + // In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId` + // builtin variable + return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType, + I); case Intrinsic::spv_fdot: return selectFloatDot(ResVReg, ResType, I); case Intrinsic::spv_udot: diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupID.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupID.ll new file mode 100644 index 00000000000000..92947f7865ced6 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/SV_GroupID.ll @@ -0,0 +1,52 @@ +; 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: %[[#v3int:]] = OpTypeVector %[[#int]] 3 +; CHECK-DAG: %[[#ptr_Input_v3int:]] = OpTypePointer Input %[[#v3int]] +; CHECK-DAG: %[[#tempvar:]] = OpUndef %[[#v3int]] +; CHECK-DAG: %[[#WorkgroupId:]] = OpVariable %[[#ptr_Input_v3int]] Input + +; CHECK-DAG: OpEntryPoint GLCompute {{.*}} %[[#WorkgroupId]] +; CHECK-DAG: OpName %[[#WorkgroupId]] "__spirv_BuiltInWorkgroupId" +; CHECK-DAG: OpDecorate %[[#WorkgroupId]] LinkageAttributes "__spirv_BuiltInWorkgroupId" Import +; CHECK-DAG: OpDecorate %[[#WorkgroupId]] BuiltIn WorkgroupId + +target triple = "spirv-unknown-vulkan-library" + +declare void @group_id_user(<3 x i32>) + +; Function Attrs: convergent noinline norecurse +define void @main() #1 { +entry: + +; CHECK: %[[#load:]] = OpLoad %[[#v3int]] %[[#WorkgroupId]] +; CHECK: %[[#load0:]] = OpCompositeExtract %[[#int]] %[[#load]] 0 + %1 = call i32 @llvm.spv.group.id(i32 0) + +; CHECK: %[[#tempvar:]] = OpCompositeInsert %[[#v3int]] %[[#load0]] %[[#tempvar]] + %2 = insertelement <3 x i32> poison, i32 %1, i64 0 + +; CHECK: %[[#load:]] = OpLoad %[[#v3int]] %[[#WorkgroupId]] +; CHECK: %[[#load1:]] = OpCompositeExtract %[[#int]] %[[#load]] 1 + %3 = call i32 @llvm.spv.group.id(i32 1) + +; CHECK: %[[#tempvar:]] = OpCompositeInsert %[[#v3int]] %[[#load1]] %[[#tempvar]] 1 + %4 = insertelement <3 x i32> %2, i32 %3, i64 1 + +; CHECK: %[[#load:]] = OpLoad %[[#v3int]] %[[#WorkgroupId]] +; CHECK: %[[#load2:]] = OpCompositeExtract %[[#int]] %[[#load]] 2 + %5 = call i32 @llvm.spv.group.id(i32 2) + +; CHECK: %[[#tempvar:]] = OpCompositeInsert %[[#v3int]] %[[#load2]] %[[#tempvar]] 2 + %6 = insertelement <3 x i32> %4, i32 %5, i64 2 + + call spir_func void @group_id_user(<3 x i32> %6) + ret void +} + +; Function Attrs: nounwind willreturn memory(none) +declare i32 @llvm.spv.group.id(i32) #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) } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits