Skip to content

Commit a3b3ba8

Browse files
committed
[HLSL] Make explicit _init_resource_bindings call for each entry point function
1 parent 0e70289 commit a3b3ba8

File tree

7 files changed

+111
-57
lines changed

7 files changed

+111
-57
lines changed

clang/lib/CodeGen/CGDeclCXX.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,14 +1127,6 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
11271127
if (Decls[i])
11281128
EmitRuntimeCall(Decls[i]);
11291129

1130-
if (getLangOpts().HLSL) {
1131-
CGHLSLRuntime &CGHLSL = CGM.getHLSLRuntime();
1132-
if (CGHLSL.needsResourceBindingInitFn()) {
1133-
llvm::Function *ResInitFn = CGHLSL.createResourceBindingInitFn();
1134-
Builder.CreateCall(llvm::FunctionCallee(ResInitFn), {});
1135-
}
1136-
}
1137-
11381130
Scope.ForceCleanup();
11391131

11401132
if (ExitBlock) {

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ void CGHLSLRuntime::finishCodeGen() {
204204
addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false,
205205
llvm::hlsl::ElementType::Invalid, Buf.Binding);
206206
}
207+
generateInitResBindingsFuncBody();
207208
}
208209

209210
CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
@@ -510,6 +511,10 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
510511
for (auto *Fn : CtorFns)
511512
B.CreateCall(FunctionCallee(Fn), {}, OB);
512513

514+
// Insert a call to initialize resource handles from bindings
515+
Function *ResInitFn = getOrCreateResourceBindingInitFn();
516+
B.CreateCall(ResInitFn);
517+
513518
// Insert global dtors before the terminator of the last instruction
514519
B.SetInsertPoint(F.back().getTerminator());
515520
for (auto *Fn : DtorFns)
@@ -545,46 +550,80 @@ void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
545550
ResourcesToBind.emplace_back(VD, GV);
546551
}
547552

548-
bool CGHLSLRuntime::needsResourceBindingInitFn() {
549-
return !ResourcesToBind.empty();
553+
// Creates a declaration of _init_resource_bindings function. It will later be
554+
// populated with calls to initialize resource handles from bindings.
555+
llvm::Function *CGHLSLRuntime::getOrCreateResourceBindingInitFn() {
556+
if (InitResBindingsFunc == nullptr) {
557+
InitResBindingsFunc =
558+
llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, false),
559+
llvm::GlobalValue::InternalLinkage,
560+
"_init_resource_bindings", CGM.getModule());
561+
}
562+
return InitResBindingsFunc;
563+
}
564+
565+
void CGHLSLRuntime::removeInitResBindingsFunc() {
566+
if (!InitResBindingsFunc)
567+
return;
568+
while (InitResBindingsFunc->user_begin() != InitResBindingsFunc->user_end()) {
569+
User *U = *InitResBindingsFunc->user_begin();
570+
assert(isa<llvm::CallInst>(U));
571+
llvm::CallInst *CI = cast<llvm::CallInst>(U);
572+
CI->eraseFromParent();
573+
}
574+
InitResBindingsFunc->eraseFromParent();
575+
InitResBindingsFunc = nullptr;
550576
}
551577

552-
llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
553-
// No resources to bind
554-
assert(needsResourceBindingInitFn() && "no resources to bind");
578+
// Populates the body of _init_resource_bindings function with calls to
579+
// initialize resource handles from bindings. If there are no resources to bind
580+
// it will remove the function and all of its calls.
581+
void CGHLSLRuntime::generateInitResBindingsFuncBody() {
582+
if (ResourcesToBind.empty()) {
583+
removeInitResBindingsFunc();
584+
return;
585+
}
586+
587+
if (InitResBindingsFunc == nullptr) {
588+
// FIXME: resource init function did not get created in shader entry point.
589+
// Is this a library or just a shader without an entry function?
590+
// llvm-project/llvm#119260
591+
return;
592+
}
555593

556594
LLVMContext &Ctx = CGM.getLLVMContext();
557595
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);
558596

559-
llvm::Function *InitResBindingsFunc =
560-
llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, false),
561-
llvm::GlobalValue::InternalLinkage,
562-
"_init_resource_bindings", CGM.getModule());
563-
564597
llvm::BasicBlock *EntryBB =
565598
llvm::BasicBlock::Create(Ctx, "entry", InitResBindingsFunc);
566599
CGBuilderTy Builder(CGM, Ctx);
567600
const DataLayout &DL = CGM.getModule().getDataLayout();
568601
Builder.SetInsertPoint(EntryBB);
569602

570-
for (const auto &[VD, GV] : ResourcesToBind) {
571-
for (Attr *A : VD->getAttrs()) {
603+
for (const auto &[Decl, GV] : ResourcesToBind) {
604+
for (Attr *A : Decl->getAttrs()) {
572605
HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
573606
if (!RBA)
574607
continue;
575608

576-
const HLSLAttributedResourceType *AttrResType =
577-
HLSLAttributedResourceType::findHandleTypeOnResource(
578-
VD->getType().getTypePtr());
579-
580-
// FIXME: Only simple declarations of resources are supported for now.
581-
// Arrays of resources or resources in user defined classes are
582-
// not implemented yet.
583-
assert(AttrResType != nullptr &&
584-
"Resource class must have a handle of HLSLAttributedResourceType");
585-
586-
llvm::Type *TargetTy =
587-
CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
609+
llvm::Type *TargetTy = nullptr;
610+
if (const VarDecl *VD = dyn_cast<VarDecl>(Decl)) {
611+
const HLSLAttributedResourceType *AttrResType =
612+
HLSLAttributedResourceType::findHandleTypeOnResource(
613+
VD->getType().getTypePtr());
614+
615+
// FIXME: Only simple declarations of resources are supported for now.
616+
// Arrays of resources or resources in user defined classes are
617+
// not implemented yet.
618+
assert(
619+
AttrResType != nullptr &&
620+
"Resource class must have a handle of HLSLAttributedResourceType");
621+
622+
TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
623+
} else {
624+
assert(isa<HLSLBufferDecl>(Decl));
625+
llvm_unreachable("CBuffer codegen is not supported yet");
626+
}
588627
assert(TargetTy != nullptr &&
589628
"Failed to convert resource handle to target type");
590629

@@ -599,7 +638,7 @@ llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
599638

600639
llvm::Value *CreateHandle = Builder.CreateIntrinsic(
601640
/*ReturnType=*/TargetTy, getCreateHandleFromBindingIntrinsic(), Args,
602-
nullptr, Twine(VD->getName()).concat("_h"));
641+
nullptr, Twine(Decl->getName()).concat("_h"));
603642

604643
llvm::Value *HandleRef =
605644
Builder.CreateStructGEP(GV->getValueType(), GV, 0);
@@ -609,7 +648,6 @@ llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
609648
}
610649

611650
Builder.CreateRetVoid();
612-
return InitResBindingsFunc;
613651
}
614652

615653
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class StructType;
5454

5555
namespace clang {
5656
class VarDecl;
57+
class NamedDecl;
5758
class ParmVarDecl;
5859
class HLSLBufferDecl;
5960
class HLSLResourceBindingAttr;
@@ -136,7 +137,7 @@ class CGHLSLRuntime {
136137
llvm::Type *Ty);
137138

138139
public:
139-
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
140+
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM), InitResBindingsFunc(nullptr) {}
140141
virtual ~CGHLSLRuntime() {}
141142

142143
llvm::Type *convertHLSLSpecificType(const Type *T);
@@ -153,8 +154,6 @@ class CGHLSLRuntime {
153154
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);
154155
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var);
155156

156-
bool needsResourceBindingInitFn();
157-
llvm::Function *createResourceBindingInitFn();
158157
llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
159158

160159
private:
@@ -165,10 +164,15 @@ class CGHLSLRuntime {
165164
BufferResBinding &Binding);
166165
void addConstant(VarDecl *D, Buffer &CB);
167166
void addBufferDecls(const DeclContext *DC, Buffer &CB);
167+
168+
llvm::Function *getOrCreateResourceBindingInitFn();
169+
void generateInitResBindingsFuncBody();
170+
void removeInitResBindingsFunc();
171+
168172
llvm::Triple::ArchType getArch();
169173
llvm::SmallVector<Buffer> Buffers;
170-
171-
llvm::SmallVector<std::pair<const VarDecl *, llvm::GlobalVariable *>>
174+
llvm::Function *InitResBindingsFunc;
175+
llvm::SmallVector<std::pair<const NamedDecl *, llvm::GlobalVariable *>>
172176
ResourcesToBind;
173177
};
174178

clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
2-
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-compute -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
2+
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-compute -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
33

44
// NOTE: SPIRV codegen for resource types is not yet implemented
55

@@ -15,9 +15,12 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4);
1515
// CHECK: @Buffer1 = global %"class.hlsl::RWByteAddressBuffer" zeroinitializer, align 4
1616
// CHECK: @Buffer2 = global %"class.hlsl::RasterizerOrderedByteAddressBuffer" zeroinitializer, align 4
1717

18-
// CHECK: define internal void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl()
19-
// CHECK: entry:
20-
// CHECK: call void @_init_resource_bindings()
18+
// CHECK: define void @main()
19+
// CHECK-NEXT: entry:
20+
// CHECK-NEXT: call void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl()
21+
// CHECK-NEXT: call void @_init_resource_bindings()
22+
// CHECK-NEXT: call void @_Z4mainv()
23+
// CHECK-NEXT: ret void
2124

2225
// CHECK: define internal void @_init_resource_bindings() {
2326
// CHECK-NEXT: entry:
@@ -27,3 +30,6 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4);
2730
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 0) %Buffer1_h, ptr @Buffer1, align 4
2831
// CHECK-DXIL-NEXT: %Buffer2_h = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false)
2932
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 1) %Buffer2_h, ptr @Buffer2, align 4
33+
34+
[numthreads(4,1,1)]
35+
void main() {}
Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-compute -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
22
// FIXME: SPIR-V codegen of llvm.spv.handle.fromBinding is not yet implemented
3-
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
3+
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-compute -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
44

55
// NOTE: SPIRV codegen for resource types is not yet implemented
66

@@ -9,17 +9,22 @@ RWBuffer<float> Buf : register(u5, space3);
99
// CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0) }
1010
// CHECK: @Buf = global %"class.hlsl::RWBuffer" zeroinitializer, align 4
1111

12-
// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
12+
// CHECK: define void @main()
1313
// CHECK-NEXT: entry:
14+
// CHECK-NEXT: call void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
15+
// CHECK-NEXT: call void @_init_resource_bindings()
16+
// CHECK-NEXT: call void @_Z4mainv()
17+
// CHECK-NEXT: ret void
1418

15-
// CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
19+
// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
1620
// CHECK-NEXT: entry:
17-
// CHECK-NEXT: call void @__cxx_global_var_init()
18-
// CHECK-NEXT: call void @_init_resource_bindings()
1921

2022
// CHECK: define internal void @_init_resource_bindings() {
2123
// CHECK-NEXT: entry:
2224
// CHECK-DXIL-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
2325
// CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4
2426
// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.spv.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
2527
// CHECK-SPIRV-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4
28+
29+
[numthreads(4,1,1)]
30+
void main() {}

clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
2-
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-compute -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
2+
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-compute -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
33

44
// NOTE: SPIRV codegen for resource types is not yet implemented
55

@@ -21,6 +21,13 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
2121
// CHECK: @Buf4 = global %"class.hlsl::ConsumeStructuredBuffer" zeroinitializer, align 4
2222
// CHECK: @Buf5 = global %"class.hlsl::RasterizerOrderedStructuredBuffer" zeroinitializer, align 4
2323

24+
// CHECK: define void @main()
25+
// CHECK-NEXT: entry:
26+
// CHECK-NEXT: call void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
27+
// CHECK-NEXT: call void @_init_resource_bindings()
28+
// CHECK-NEXT: call void @_Z4mainv()
29+
// CHECK-NEXT: ret void
30+
2431
// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
2532
// CHECK-NEXT: entry:
2633
// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
@@ -31,10 +38,6 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
3138
// CHECK: define linkonce_odr void @_ZN4hlsl33RasterizerOrderedStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
3239
// CHECK-NEXT: entry:
3340

34-
// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
35-
// CHECK: entry:
36-
// CHECK: call void @_init_resource_bindings()
37-
3841
// CHECK: define internal void @_init_resource_bindings() {
3942
// CHECK-NEXT: entry:
4043
// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
@@ -58,3 +61,6 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
5861
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf4_h, ptr @Buf4, align 4
5962
// CHECK-SPIRV-NEXT: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false)
6063
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 1) %Buf5_h, ptr @Buf5, align 4
64+
65+
[numthreads(4,1,1)]
66+
void main() {}

clang/test/CodeGenHLSL/resource-bindings.hlsl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple dxil--shadermodel6.6-compute -x hlsl -finclude-default-header -emit-llvm -o - %s | FileCheck %s
1+
// RUN: %clang_cc1 -triple dxil--shadermodel6.6-compute -finclude-default-header -emit-llvm -o - %s | FileCheck %s
22

33
// CHECK: define internal void @_init_resource_bindings() {
44

@@ -17,3 +17,6 @@ struct S {
1717

1818
// CHECK: %T3S0_h = call target("dx.RawBuffer", %struct.S = type { <4 x float>, i32, [12 x i8] }, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false)
1919
StructuredBuffer<S> T3S0 : register(t3);
20+
21+
[numthreads(4,1,1)]
22+
void main() {}

0 commit comments

Comments
 (0)