Skip to content

Commit a983170

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 47d71b6 commit a983170

File tree

14 files changed

+349
-11
lines changed

14 files changed

+349
-11
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5017,6 +5017,10 @@ def HLSLUnparsedSemantic : HLSLAnnotationAttr {
50175017
let Documentation = [InternalOnly];
50185018
}
50195019

5020+
def HLSLUserSemantic : HLSLSemanticAttr</* Indexable= */ 1> {
5021+
let Documentation = [InternalOnly];
5022+
}
5023+
50205024
def HLSLSV_Position : HLSLSemanticAttr</* Indexable= */ 1> {
50215025
let Documentation = [HLSLSV_PositionDocs];
50225026
}

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13184,6 +13184,7 @@ def err_hlsl_semantic_indexing_not_supported
1318413184
: Error<"semantic %0 does not allow indexing">;
1318513185
def err_hlsl_init_priority_unsupported : Error<
1318613186
"initializer priorities are not supported in HLSL">;
13187+
def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;
1318713188

1318813189
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>;
1318913190
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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
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>
2628

@@ -244,6 +246,8 @@ class SemaHLSL : public SemaBase {
244246

245247
IdentifierInfo *RootSigOverrideIdent = nullptr;
246248

249+
llvm::DenseMap<FunctionDecl *, llvm::StringSet<>> ActiveInputSemantics;
250+
247251
struct SemanticInfo {
248252
HLSLSemanticAttr *Semantic;
249253
std::optional<uint32_t> Index;

clang/lib/CodeGen/CGHLSLRuntime.cpp

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

552+
static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) {
553+
LLVMContext &Ctx = GV->getContext();
554+
IRBuilder<> B(GV->getContext());
555+
MDNode *Operands =
556+
MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)),
557+
ConstantAsMetadata::get(B.getInt32(Location))});
558+
MDNode *Decoration = MDNode::get(Ctx, {Operands});
559+
GV->addMetadata("spirv.Decorations", *Decoration);
560+
}
561+
552562
static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
553563
llvm::Type *Ty, const Twine &Name,
554564
unsigned BuiltInID) {
@@ -562,6 +572,69 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
562572
return B.CreateLoad(Ty, GV);
563573
}
564574

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

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,25 @@ class CGHLSLRuntime {
200200
llvm::GlobalVariable *BufGV);
201201
void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
202202
llvm::GlobalVariable *GV);
203+
void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
204+
llvm::GlobalVariable *GV,
205+
HLSLResourceBindingAttr *RBA);
206+
207+
llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
208+
HLSLSemanticAttr *Semantic,
209+
std::optional<unsigned> Index);
210+
llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
211+
HLSLSemanticAttr *Semantic,
212+
std::optional<unsigned> Index);
213+
llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
214+
const clang::DeclaratorDecl *Decl,
215+
HLSLSemanticAttr *Semantic,
216+
std::optional<unsigned> Index);
217+
203218
llvm::Triple::ArchType getArch();
204219

205220
llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;
221+
unsigned SPIRVLastAssignedInputSemanticLocation = 0;
206222
};
207223

208224
} // namespace CodeGen

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,10 @@ HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info,
775775
DeclaratorDecl *TargetDecl) {
776776
std::string SemanticName = Info.Semantic->getAttrName()->getName().upper();
777777

778+
if (dyn_cast<HLSLUserSemanticAttr>(Info.Semantic))
779+
return createSemanticAttr<HLSLUserSemanticAttr>(*Info.Semantic, TargetDecl,
780+
Info.Index);
781+
778782
if (SemanticName == "SV_DISPATCHTHREADID") {
779783
return createSemanticAttr<HLSLSV_DispatchThreadIDAttr>(
780784
*Info.Semantic, TargetDecl, Info.Index);
@@ -818,6 +822,33 @@ bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
818822

819823
checkSemanticAnnotation(FD, D, A);
820824
FD->addAttr(A);
825+
826+
unsigned Location = ActiveSemantic.Index.value_or(0);
827+
828+
const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType());
829+
unsigned ElementCount = AT ? AT->getZExtSize() : 1;
830+
ActiveSemantic.Index = Location + ElementCount;
831+
832+
Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
833+
for (unsigned I = 0; I < ElementCount; ++I) {
834+
Twine VariableName = BaseName.concat(Twine(Location + I));
835+
836+
auto It = ActiveInputSemantics.find(FD);
837+
if (It == ActiveInputSemantics.end()) {
838+
llvm::StringSet<> Set({VariableName.str()});
839+
auto Item = std::make_pair(FD, std::move(Set));
840+
ActiveInputSemantics.insert(std::move(Item));
841+
continue;
842+
}
843+
844+
auto [_, Inserted] = ActiveInputSemantics[FD].insert(VariableName.str());
845+
if (!Inserted) {
846+
Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap)
847+
<< VariableName.str();
848+
return false;
849+
}
850+
}
851+
821852
return true;
822853
}
823854

@@ -947,6 +978,8 @@ void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint,
947978
return;
948979
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
949980
break;
981+
case attr::HLSLUserSemantic:
982+
return;
950983
default:
951984
llvm_unreachable("Unknown SemanticAttr");
952985
}
@@ -1766,7 +1799,7 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) {
17661799
if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
17671800
diagnoseSystemSemanticAttr(D, AL, Index);
17681801
else
1769-
Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1802+
D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, nullptr, Index));
17701803
}
17711804

17721805
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: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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+
uint2 a : SV_DispatchThreadID;
22+
uint2 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: %[[#AX_:]] = insertelement <2 x i32> poison, i32 %[[#ID]], i64 0
29+
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 1)
30+
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 1)
31+
// CHECK: %[[#AXY:]] = insertelement <2 x i32> %[[#AX_]], i32 %[[#ID]], i64 1
32+
// CHECK: %[[#S1A_:]] = insertvalue %struct.S1 poison, <2 x i32> %[[#AXY]], 0
33+
// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0)
34+
// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0)
35+
// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0
36+
// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1)
37+
// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1)
38+
// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
39+
// CHECK: %[[#S1AB:]] = insertvalue %struct.S1 %[[#S1A_]], <2 x i32> %[[#ID_XYZ:]], 1
40+
// CHECK: %[[#ARG:]] = alloca %struct.S1, align 8
41+
// CHECK: store %struct.S1 %[[#S1AB]], ptr %[[#ARG]], align 8
42+
// CHECK-DXIL: call void @{{.*}}main1{{.*}}(ptr %[[#ARG]])
43+
// CHECK-SPIRV: call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]])
44+
[shader("compute")]
45+
[numthreads(8,8,1)]
46+
void main1(S1 p) {}
47+
48+
struct S2C {
49+
uint2 b : SV_GroupThreadID;
50+
};
51+
52+
struct S2 {
53+
uint a : SV_DispatchThreadID;
54+
S2C child;
55+
};
56+
57+
// CHECK: define void @main2()
58+
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
59+
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
60+
// CHECK: %[[#S2A_:]] = insertvalue %struct.S2 poison, i32 %[[#ID:]], 0
61+
62+
// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0)
63+
// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0)
64+
// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0
65+
// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1)
66+
// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1)
67+
// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
68+
// CHECK: %[[#S2C:]] = insertvalue %struct.S2C poison, <2 x i32> %[[#ID_XY:]], 0
69+
70+
// CHECK: %[[#S2AB:]] = insertvalue %struct.S2 %[[#S2A_]], %struct.S2C %[[#S2V:]], 1
71+
// CHECK: %[[#ARG:]] = alloca %struct.S2, align 8
72+
// CHECK: store %struct.S2 %[[#S2AB]], ptr %[[#ARG]], align 1
73+
// CHECK-DXIL: call void @{{.*}}main2{{.*}}(ptr %[[#ARG]])
74+
// CHECK-SPIRV: call spir_func void @{{.*}}main2{{.*}}(ptr %[[#ARG]])
75+
[shader("compute")]
76+
[numthreads(8,8,1)]
77+
void main2(S2 p) {}

0 commit comments

Comments
 (0)