Skip to content

Commit 7a76110

Browse files
authored
[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
1 parent 7db0a60 commit 7a76110

File tree

6 files changed

+82
-16
lines changed

6 files changed

+82
-16
lines changed

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
395395
return buildVectorInput(B, GroupThreadIDIntrinsic, Ty);
396396
}
397397
if (D.hasAttr<HLSLSV_GroupIDAttr>()) {
398-
llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_group_id);
398+
llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic());
399399
return buildVectorInput(B, GroupIDIntrinsic, Ty);
400400
}
401401
assert(false && "Unhandled parameter attribute");

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class CGHLSLRuntime {
8787
GENERATE_HLSL_INTRINSIC_FUNCTION(Radians, radians)
8888
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
8989
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupThreadId, thread_id_in_group)
90+
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupId, group_id)
9091
GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)
9192
GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)
9293
GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot)
Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
1+
// 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
2+
// 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
23

3-
// Make sure SV_GroupID translated into dx.group.id.
4+
// Make sure SV_GroupID translated into dx.group.id for directx target and spv.group.id for spirv target.
45

5-
// CHECK: define void @foo()
6-
// CHECK: %[[#ID:]] = call i32 @llvm.dx.group.id(i32 0)
7-
// CHECK: call void @{{.*}}foo{{.*}}(i32 %[[#ID]])
6+
// CHECK: define void @foo()
7+
// CHECK: %[[#ID:]] = call i32 @llvm.[[TARGET]].group.id(i32 0)
8+
// CHECK-DXIL: call void @{{.*}}foo{{.*}}(i32 %[[#ID]])
9+
// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(i32 %[[#ID]])
810
[shader("compute")]
911
[numthreads(8,8,1)]
1012
void foo(uint Idx : SV_GroupID) {}
1113

12-
// CHECK: define void @bar()
13-
// CHECK: %[[#ID_X:]] = call i32 @llvm.dx.group.id(i32 0)
14-
// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0
15-
// CHECK: %[[#ID_Y:]] = call i32 @llvm.dx.group.id(i32 1)
16-
// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
17-
// CHECK: call void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]])
14+
// CHECK: define void @bar()
15+
// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].group.id(i32 0)
16+
// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0
17+
// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].group.id(i32 1)
18+
// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
19+
// CHECK-DXIL: call void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]])
20+
// CHECK-SPIRV: call spir_func void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]])
1821
[shader("compute")]
1922
[numthreads(8,8,1)]
2023
void bar(uint2 Idx : SV_GroupID) {}
2124

2225
// CHECK: define void @test()
23-
// CHECK: %[[#ID_X:]] = call i32 @llvm.dx.group.id(i32 0)
26+
// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].group.id(i32 0)
2427
// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0
25-
// CHECK: %[[#ID_Y:]] = call i32 @llvm.dx.group.id(i32 1)
28+
// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].group.id(i32 1)
2629
// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
27-
// CHECK: %[[#ID_Z:]] = call i32 @llvm.dx.group.id(i32 2)
30+
// CHECK: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].group.id(i32 2)
2831
// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2
29-
// CHECK: call void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]])
32+
// CHECK-DXIL: call void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]])
33+
// CHECK-SPIRV: call spir_func void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]])
3034
[shader("compute")]
3135
[numthreads(8,8,1)]
3236
void test(uint3 Idx : SV_GroupID) {}

llvm/include/llvm/IR/IntrinsicsSPIRV.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ let TargetPrefix = "spv" in {
5959

6060
// The following intrinsic(s) are mirrored from IntrinsicsDirectX.td for HLSL support.
6161
def int_spv_thread_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
62+
def int_spv_group_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
6263
def int_spv_thread_id_in_group : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
6364
def int_spv_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;
6465
def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2881,6 +2881,14 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
28812881
// translated to a `LocalInvocationId` builtin variable
28822882
return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg,
28832883
ResType, I);
2884+
case Intrinsic::spv_group_id:
2885+
// The HLSL SV_GroupId semantic is lowered to
2886+
// llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend.
2887+
//
2888+
// In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId`
2889+
// builtin variable
2890+
return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType,
2891+
I);
28842892
case Intrinsic::spv_fdot:
28852893
return selectFloatDot(ResVReg, ResType, I);
28862894
case Intrinsic::spv_udot:
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK-DAG: %[[#int:]] = OpTypeInt 32 0
5+
; CHECK-DAG: %[[#v3int:]] = OpTypeVector %[[#int]] 3
6+
; CHECK-DAG: %[[#ptr_Input_v3int:]] = OpTypePointer Input %[[#v3int]]
7+
; CHECK-DAG: %[[#tempvar:]] = OpUndef %[[#v3int]]
8+
; CHECK-DAG: %[[#WorkgroupId:]] = OpVariable %[[#ptr_Input_v3int]] Input
9+
10+
; CHECK-DAG: OpEntryPoint GLCompute {{.*}} %[[#WorkgroupId]]
11+
; CHECK-DAG: OpName %[[#WorkgroupId]] "__spirv_BuiltInWorkgroupId"
12+
; CHECK-DAG: OpDecorate %[[#WorkgroupId]] LinkageAttributes "__spirv_BuiltInWorkgroupId" Import
13+
; CHECK-DAG: OpDecorate %[[#WorkgroupId]] BuiltIn WorkgroupId
14+
15+
target triple = "spirv-unknown-vulkan-library"
16+
17+
declare void @group_id_user(<3 x i32>)
18+
19+
; Function Attrs: convergent noinline norecurse
20+
define void @main() #1 {
21+
entry:
22+
23+
; CHECK: %[[#load:]] = OpLoad %[[#v3int]] %[[#WorkgroupId]]
24+
; CHECK: %[[#load0:]] = OpCompositeExtract %[[#int]] %[[#load]] 0
25+
%1 = call i32 @llvm.spv.group.id(i32 0)
26+
27+
; CHECK: %[[#tempvar:]] = OpCompositeInsert %[[#v3int]] %[[#load0]] %[[#tempvar]]
28+
%2 = insertelement <3 x i32> poison, i32 %1, i64 0
29+
30+
; CHECK: %[[#load:]] = OpLoad %[[#v3int]] %[[#WorkgroupId]]
31+
; CHECK: %[[#load1:]] = OpCompositeExtract %[[#int]] %[[#load]] 1
32+
%3 = call i32 @llvm.spv.group.id(i32 1)
33+
34+
; CHECK: %[[#tempvar:]] = OpCompositeInsert %[[#v3int]] %[[#load1]] %[[#tempvar]] 1
35+
%4 = insertelement <3 x i32> %2, i32 %3, i64 1
36+
37+
; CHECK: %[[#load:]] = OpLoad %[[#v3int]] %[[#WorkgroupId]]
38+
; CHECK: %[[#load2:]] = OpCompositeExtract %[[#int]] %[[#load]] 2
39+
%5 = call i32 @llvm.spv.group.id(i32 2)
40+
41+
; CHECK: %[[#tempvar:]] = OpCompositeInsert %[[#v3int]] %[[#load2]] %[[#tempvar]] 2
42+
%6 = insertelement <3 x i32> %4, i32 %5, i64 2
43+
44+
call spir_func void @group_id_user(<3 x i32> %6)
45+
ret void
46+
}
47+
48+
; Function Attrs: nounwind willreturn memory(none)
49+
declare i32 @llvm.spv.group.id(i32) #3
50+
51+
attributes #1 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
52+
attributes #3 = { nounwind willreturn memory(none) }

0 commit comments

Comments
 (0)