Skip to content

Commit 6cae241

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 fe5f499 commit 6cae241

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
@@ -13181,6 +13181,7 @@ def err_hlsl_semantic_indexing_not_supported
1318113181
: Error<"semantic %0 does not allow indexing">;
1318213182
def err_hlsl_init_priority_unsupported : Error<
1318313183
"initializer priorities are not supported in HLSL">;
13184+
def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;
1318413185

1318513186
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>;
1318613187
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
@@ -774,6 +774,10 @@ HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info,
774774
DeclaratorDecl *TargetDecl) {
775775
std::string SemanticName = Info.Semantic->getAttrName()->getName().upper();
776776

777+
if (dyn_cast<HLSLUserSemanticAttr>(Info.Semantic))
778+
return createSemanticAttr<HLSLUserSemanticAttr>(*Info.Semantic, TargetDecl,
779+
Info.Index);
780+
777781
if (SemanticName == "SV_DISPATCHTHREADID") {
778782
return createSemanticAttr<HLSLSV_DispatchThreadIDAttr>(
779783
*Info.Semantic, TargetDecl, Info.Index);
@@ -817,6 +821,33 @@ bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
817821

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

@@ -946,6 +977,8 @@ void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint,
946977
return;
947978
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
948979
break;
980+
case attr::HLSLUserSemantic:
981+
return;
949982
default:
950983
llvm_unreachable("Unknown SemanticAttr");
951984
}
@@ -1765,7 +1798,7 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) {
17651798
if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
17661799
diagnoseSystemSemanticAttr(D, AL, Index);
17671800
else
1768-
Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1801+
D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, nullptr, Index));
17691802
}
17701803

17711804
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)