Skip to content

Commit dfe8cc3

Browse files
committed
[HLSL][DXIL][SPIRV] Add user semantics to Clang
This commit adds initial support for user semantics. Those are generic cpp idenfier which translate differently than system semantics. Supporting user semantics will allows testing another side of semantics: shadowing and implicit indices. When a semantic is applied on a parent element (parameter or type definition), the semantics on its children declarations are ignored. Also, the semantic index is used to determine the index of the first element, but increases with each array element or struct field. See https://github.com/llvm/wg-hlsl/blob/main/proposals/0031-semantics.md
1 parent 29ea2a4 commit dfe8cc3

File tree

14 files changed

+357
-11
lines changed

14 files changed

+357
-11
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4967,6 +4967,10 @@ def HLSLUnparsedSemantic : HLSLAnnotationAttr {
49674967
let Documentation = [InternalOnly];
49684968
}
49694969

4970+
def HLSLUserSemantic : HLSLSemanticAttr</* Indexable= */ 1> {
4971+
let Documentation = [InternalOnly];
4972+
}
4973+
49704974
def HLSLSV_Position : HLSLSemanticAttr</* Indexable= */ 1> {
49714975
let Documentation = [HLSLSV_PositionDocs];
49724976
}

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13131,6 +13131,7 @@ def err_hlsl_semantic_indexing_not_supported
1313113131
: Error<"semantic %0 does not allow indexing">;
1313213132
def err_hlsl_init_priority_unsupported : Error<
1313313133
"initializer priorities are not supported in HLSL">;
13134+
def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;
1313413135

1313513136
def warn_hlsl_user_defined_type_missing_member: Warning<"binding type '%select{t|u|b|s|c}0' only applies to types containing %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric types}0">, InGroup<LegacyConstantRegisterBinding>;
1313613137
def err_hlsl_binding_type_mismatch: Error<"binding type '%select{t|u|b|s|c}0' only applies to %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric variables in the global scope}0">;

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
#include "clang/Basic/DiagnosticSema.h"
2121
#include "clang/Basic/SourceLocation.h"
2222
#include "clang/Sema/SemaBase.h"
23+
#include "llvm/ADT/DenseMap.h"
2324
#include "llvm/ADT/SmallVector.h"
25+
#include "llvm/ADT/StringSet.h"
2426
#include "llvm/TargetParser/Triple.h"
2527
#include <initializer_list>
28+
#include <unordered_set>
2629

2730
namespace clang {
2831
class AttributeCommonInfo;
@@ -243,6 +246,8 @@ class SemaHLSL : public SemaBase {
243246

244247
IdentifierInfo *RootSigOverrideIdent = nullptr;
245248

249+
llvm::DenseMap<FunctionDecl *, llvm::StringSet<>> ActiveInputSemantics;
250+
246251
struct SemanticInfo {
247252
HLSLSemanticAttr *Semantic;
248253
std::optional<uint32_t> Index;

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,16 @@ static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV,
553553
GV->addMetadata("spirv.Decorations", *Decoration);
554554
}
555555

556+
static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) {
557+
LLVMContext &Ctx = GV->getContext();
558+
IRBuilder<> B(GV->getContext());
559+
MDNode *Operands =
560+
MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)),
561+
ConstantAsMetadata::get(B.getInt32(Location))});
562+
MDNode *Decoration = MDNode::get(Ctx, {Operands});
563+
GV->addMetadata("spirv.Decorations", *Decoration);
564+
}
565+
556566
static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
557567
llvm::Type *Ty, const Twine &Name,
558568
unsigned BuiltInID) {
@@ -566,6 +576,69 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
566576
return B.CreateLoad(Ty, GV);
567577
}
568578

579+
static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M,
580+
llvm::Type *Ty, unsigned Location,
581+
StringRef Name = "") {
582+
auto *GV = new llvm::GlobalVariable(
583+
M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
584+
/* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
585+
llvm::GlobalVariable::GeneralDynamicTLSModel,
586+
/* AddressSpace */ 7, /* isExternallyInitialized= */ true);
587+
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
588+
addLocationDecoration(GV, Location);
589+
return B.CreateLoad(Ty, GV);
590+
}
591+
592+
llvm::Value *
593+
CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
594+
HLSLSemanticAttr *Semantic,
595+
std::optional<unsigned> Index) {
596+
Twine BaseName = Twine(Semantic->getAttrName()->getName());
597+
Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
598+
599+
unsigned Location = SPIRVLastAssignedInputSemanticLocation;
600+
601+
// DXC completely ignores the semantic/index pair. Location are assigned from
602+
// the first semantic to the last.
603+
llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
604+
unsigned ElementCount = AT ? AT->getNumElements() : 1;
605+
SPIRVLastAssignedInputSemanticLocation += ElementCount;
606+
return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location,
607+
VariableName.str());
608+
}
609+
610+
llvm::Value *
611+
CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
612+
HLSLSemanticAttr *Semantic,
613+
std::optional<unsigned> Index) {
614+
Twine BaseName = Twine(Semantic->getAttrName()->getName());
615+
Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
616+
617+
// DXIL packing rules etc shall be handled here.
618+
// FIXME: generate proper sigpoint, index, col, row values.
619+
// FIXME: also DXIL loads vectors element by element.
620+
SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
621+
B.getInt8(0),
622+
llvm::PoisonValue::get(B.getInt32Ty())};
623+
624+
llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
625+
llvm::Value *Value = B.CreateIntrinsic(/*ReturnType=*/Type, IntrinsicID, Args,
626+
nullptr, VariableName);
627+
return Value;
628+
}
629+
630+
llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
631+
IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
632+
HLSLSemanticAttr *Semantic, std::optional<unsigned> Index) {
633+
if (CGM.getTarget().getTriple().isSPIRV())
634+
return emitSPIRVUserSemanticLoad(B, Type, Semantic, Index);
635+
636+
if (CGM.getTarget().getTriple().isDXIL())
637+
return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
638+
639+
llvm_unreachable("Unsupported target for user-semantic load.");
640+
}
641+
569642
llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
570643
IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
571644
Attr *Semantic, std::optional<unsigned> Index) {
@@ -622,6 +695,9 @@ CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
622695
std::optional<unsigned> Index = std::nullopt;
623696
if (Semantic->isSemanticIndexExplicit())
624697
Index = Semantic->getSemanticIndex();
698+
699+
if (auto *UserSemantic = dyn_cast<HLSLUserSemanticAttr>(Semantic))
700+
return emitUserSemanticLoad(B, Type, Decl, Semantic, Index);
625701
return emitSystemSemanticLoad(B, Type, Decl, Semantic, Index);
626702
}
627703

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,22 @@ class CGHLSLRuntime {
199199
void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
200200
llvm::GlobalVariable *GV,
201201
HLSLResourceBindingAttr *RBA);
202+
203+
llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
204+
HLSLSemanticAttr *Semantic,
205+
std::optional<unsigned> Index);
206+
llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
207+
HLSLSemanticAttr *Semantic,
208+
std::optional<unsigned> Index);
209+
llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
210+
const clang::DeclaratorDecl *Decl,
211+
HLSLSemanticAttr *Semantic,
212+
std::optional<unsigned> Index);
213+
202214
llvm::Triple::ArchType getArch();
203215

204216
llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;
217+
unsigned SPIRVLastAssignedInputSemanticLocation = 0;
205218
};
206219

207220
} // namespace CodeGen

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,9 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
772772
HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info) {
773773
std::string SemanticName = Info.Semantic->getAttrName()->getName().upper();
774774

775+
if (dyn_cast<HLSLUserSemanticAttr>(Info.Semantic))
776+
return createSemanticAttr<HLSLUserSemanticAttr>(*Info.Semantic, Info.Index);
777+
775778
if (SemanticName == "SV_DISPATCHTHREADID") {
776779
return createSemanticAttr<HLSLSV_DispatchThreadIDAttr>(*Info.Semantic,
777780
Info.Index);
@@ -813,6 +816,33 @@ bool SemaHLSL::isSemanticOnScalarValid(FunctionDecl *FD, DeclaratorDecl *D,
813816
checkSemanticAnnotation(FD, D, A);
814817
D->dropAttrs<HLSLSemanticAttr>();
815818
D->addAttr(A);
819+
820+
unsigned Location = ActiveSemantic.Index.value_or(0);
821+
822+
const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType());
823+
unsigned ElementCount = AT ? AT->getZExtSize() : 1;
824+
ActiveSemantic.Index = Location + ElementCount;
825+
826+
Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
827+
for (unsigned I = 0; I < ElementCount; ++I) {
828+
Twine VariableName = BaseName.concat(Twine(Location + I));
829+
830+
auto It = ActiveInputSemantics.find(FD);
831+
if (It == ActiveInputSemantics.end()) {
832+
llvm::StringSet<> Set({VariableName.str()});
833+
auto Item = std::make_pair(FD, std::move(Set));
834+
ActiveInputSemantics.insert(std::move(Item));
835+
continue;
836+
}
837+
838+
auto [_, Inserted] = ActiveInputSemantics[FD].insert(VariableName.str());
839+
if (!Inserted) {
840+
Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap)
841+
<< VariableName.str();
842+
return false;
843+
}
844+
}
845+
816846
return true;
817847
}
818848

@@ -942,6 +972,8 @@ void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint,
942972
return;
943973
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
944974
break;
975+
case attr::HLSLUserSemantic:
976+
return;
945977
default:
946978
llvm_unreachable("Unknown SemanticAttr");
947979
}
@@ -1743,7 +1775,7 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) {
17431775
if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
17441776
diagnoseSystemSemanticAttr(D, AL, Index);
17451777
else
1746-
Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1778+
D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, Index));
17471779
}
17481780

17491781
void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) {

clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,3 @@ void foo(uint Idx : SV_DispatchThreadID) {}
2424
[shader("compute")]
2525
[numthreads(8,8,1)]
2626
void bar(uint2 Idx : SV_DispatchThreadID) {}
27-
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
3+
4+
// CHECK-SPIRV-DAG: @AAA0 = external hidden thread_local addrspace(7) externally_initialized constant float, !spirv.Decorations ![[#METADATA_0:]]
5+
// CHECK-SPIRV-DAG: @B0 = external hidden thread_local addrspace(7) externally_initialized constant i32, !spirv.Decorations ![[#METADATA_2:]]
6+
// CHECK-SPIRV-DAG: @CC0 = external hidden thread_local addrspace(7) externally_initialized constant <2 x float>, !spirv.Decorations ![[#METADATA_4:]]
7+
8+
9+
// FIXME: replace `float2 c` with a matrix when available.
10+
void main(float a : AAA, int b : B, float2 c : CC) {
11+
float tmp = a + b + c.x + c.y;
12+
}
13+
// CHECK-SPIRV: define internal spir_func void @_Z4mainfiDv2_f(float noundef nofpclass(nan inf) %a, i32 noundef %b, <2 x float> noundef nofpclass(nan inf) %c) #0 {
14+
15+
// CHECK: define void @main()
16+
17+
// CHECK-DXIL: %AAA0 = call float @llvm.dx.load.input.f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
18+
// CHECK-DXIL: %B0 = call i32 @llvm.dx.load.input.i32(i32 4, i32 0, i32 0, i8 0, i32 poison)
19+
// CHECK-DXIL %CC0 = call <2 x float> @llvm.dx.load.input.v2f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
20+
// CHECK-DXIL: call void @_Z4mainfiDv2_f(float %AAA0, i32 %B0, <2 x float> %CC0)
21+
22+
// CHECK-SPIRV: %[[#AAA0:]] = load float, ptr addrspace(7) @AAA0, align 4
23+
// CHECK-SPIRV: %[[#B0:]] = load i32, ptr addrspace(7) @B0, align 4
24+
// CHECK-SPIRV: %[[#CC0:]] = load <2 x float>, ptr addrspace(7) @CC0, align 8
25+
// CHECK-SPIRV: call spir_func void @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]]) [ "convergencectrl"(token %0) ]
26+
27+
// CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}
28+
// CHECK-SPIRV-DAG: ![[#METADATA_1]] = !{i32 30, i32 0}
29+
// CHECK-SPIRV-DAG: ![[#METADATA_2]] = !{![[#METADATA_3:]]}
30+
// CHECK-SPIRV-DAG: ![[#METADATA_3]] = !{i32 30, i32 1}
31+
// CHECK-SPIRV-DAG: ![[#METADATA_4]] = !{![[#METADATA_5:]]}
32+
// CHECK-SPIRV-DAG: ![[#METADATA_5]] = !{i32 30, i32 2}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// 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
2+
// RUN: %clang_cc1 -triple dxil-px-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
3+
4+
struct S0 {
5+
float4 position[2];
6+
float4 color;
7+
};
8+
9+
// CHECK: %struct.S0 = type { [2 x <4 x float>], <4 x float> }
10+
11+
// CHECK-SPIRV: @A0 = external hidden thread_local addrspace(7) externally_initialized constant [2 x <4 x float>], !spirv.Decorations ![[#MD_0:]]
12+
// CHECK-SPIRV: @A2 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]]
13+
14+
// CHECK: define void @main0()
15+
// CHECK-DXIL: %A0 = call [2 x <4 x float>] @llvm.dx.load.input.a2v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
16+
// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %A0, 0
17+
// CHECK-DXIL: %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
18+
// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1
19+
20+
// CHECK-SPIRV: %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 16
21+
// CHECK-SPIRV: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#A0]], 0
22+
// CHECK-SPIRV: %[[#A2:]] = load <4 x float>, ptr addrspace(7) @A2, align 16
23+
// CHECK-SPIRV: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %[[#A2]], 1
24+
25+
// CHECK: %[[#ARG:]] = alloca %struct.S0, align 16
26+
// CHECK: store %struct.S0 %[[#TMP1]], ptr %[[#ARG]], align 16
27+
// CHECK-DXIL: call void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
28+
// CHECK-SPIRV: call spir_func void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
29+
[shader("pixel")]
30+
void main0(S0 p : A) {
31+
float tmp = p.position[0] + p.position[1] + p.color;
32+
}
33+
34+
// CHECK-SPIRV: ![[#MD_0]] = !{![[#MD_1:]]}
35+
// CHECK-SPIRV: ![[#MD_1]] = !{i32 30, i32 0}
36+
// CHECK-SPIRV: ![[#MD_2]] = !{![[#MD_3:]]}
37+
// CHECK-SPIRV: ![[#MD_3]] = !{i32 30, i32 2}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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
3+
4+
struct S0 {
5+
uint Idx : SV_DispatchThreadID;
6+
};
7+
8+
// CHECK: define void @main0()
9+
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
10+
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
11+
// CHECK: %[[#TMP:]] = insertvalue %struct.S0 poison, i32 %[[#ID:]], 0
12+
// CHECK: %[[#ARG:]] = alloca %struct.S0, align 8
13+
// CHECK: store %struct.S0 %[[#TMP]], ptr %[[#ARG]], align 4
14+
// CHECK-DXIL: call void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
15+
// CHECK-SPIRV: call spir_func void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
16+
[shader("compute")]
17+
[numthreads(8,8,1)]
18+
void main0(S0 p) {}
19+
20+
struct S1 {
21+
uint a : SV_DispatchThreadID;
22+
uint3 b : SV_GroupThreadID;
23+
};
24+
25+
// CHECK: define void @main1()
26+
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
27+
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
28+
// CHECK: %[[#S1A_:]] = insertvalue %struct.S1 poison, i32 %[[#ID:]], 0
29+
// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0)
30+
// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0)
31+
// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0
32+
// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1)
33+
// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1)
34+
// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
35+
// CHECK-DXIL: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 2)
36+
// CHECK-SPIRV: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 2)
37+
// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2
38+
// CHECK: %[[#S1AB:]] = insertvalue %struct.S1 %[[#S1A_]], <3 x i32> %[[#ID_XYZ:]], 1
39+
// CHECK: %[[#ARG:]] = alloca %struct.S1, align 8
40+
// CHECK: store %struct.S1 %[[#S1AB]], ptr %[[#ARG]], align 1
41+
// CHECK-DXIL: call void @{{.*}}main1{{.*}}(ptr %[[#ARG]])
42+
// CHECK-SPIRV: call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]])
43+
[shader("compute")]
44+
[numthreads(8,8,1)]
45+
void main1(S1 p) {}
46+
47+
struct S2C {
48+
uint3 b : SV_GroupThreadID;
49+
};
50+
51+
struct S2 {
52+
uint a : SV_DispatchThreadID;
53+
S2C child;
54+
};
55+
56+
// CHECK: define void @main2()
57+
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
58+
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
59+
// CHECK: %[[#S2A_:]] = insertvalue %struct.S2 poison, i32 %[[#ID:]], 0
60+
61+
// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0)
62+
// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0)
63+
// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0
64+
// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1)
65+
// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1)
66+
// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
67+
// CHECK-DXIL: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 2)
68+
// CHECK-SPIRV: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 2)
69+
// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2
70+
// CHECK: %[[#S2C:]] = insertvalue %struct.S2C poison, <3 x i32> %[[#ID_XYZ:]], 0
71+
72+
// CHECK: %[[#S2AB:]] = insertvalue %struct.S2 %[[#S2A_]], %struct.S2C %[[#S2V:]], 1
73+
// CHECK: %[[#ARG:]] = alloca %struct.S2, align 8
74+
// CHECK: store %struct.S2 %[[#S2AB]], ptr %[[#ARG]], align 1
75+
// CHECK-DXIL: call void @{{.*}}main2{{.*}}(ptr %[[#ARG]])
76+
// CHECK-SPIRV: call spir_func void @{{.*}}main2{{.*}}(ptr %[[#ARG]])
77+
[shader("compute")]
78+
[numthreads(8,8,1)]
79+
void main2(S2 p) {}

0 commit comments

Comments
 (0)