1 //===----- CGHLSLRuntime.cpp - Interface to HLSL Runtimes -----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This provides an abstract class for HLSL code generation. Concrete
10 // subclasses of this implement code generation for specific HLSL
13 //===----------------------------------------------------------------------===//
15 #include "CGHLSLRuntime.h"
16 #include "CGDebugInfo.h"
17 #include "CodeGenModule.h"
18 #include "TargetInfo.h"
19 #include "clang/AST/Decl.h"
20 #include "clang/Basic/TargetOptions.h"
21 #include "llvm/IR/GlobalVariable.h"
22 #include "llvm/IR/LLVMContext.h"
23 #include "llvm/IR/Metadata.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/IR/Value.h"
26 #include "llvm/Support/Alignment.h"
28 #include "llvm/Support/FormatVariadic.h"
30 using namespace clang
;
31 using namespace CodeGen
;
32 using namespace clang::hlsl
;
37 void addDxilValVersion(StringRef ValVersionStr
, llvm::Module
&M
) {
38 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
39 // Assume ValVersionStr is legal here.
41 if (Version
.tryParse(ValVersionStr
) || Version
.getBuild() ||
42 Version
.getSubminor() || !Version
.getMinor()) {
46 uint64_t Major
= Version
.getMajor();
47 uint64_t Minor
= *Version
.getMinor();
49 auto &Ctx
= M
.getContext();
50 IRBuilder
<> B(M
.getContext());
51 MDNode
*Val
= MDNode::get(Ctx
, {ConstantAsMetadata::get(B
.getInt32(Major
)),
52 ConstantAsMetadata::get(B
.getInt32(Minor
))});
53 StringRef DXILValKey
= "dx.valver";
54 auto *DXILValMD
= M
.getOrInsertNamedMetadata(DXILValKey
);
55 DXILValMD
->addOperand(Val
);
57 void addDisableOptimizations(llvm::Module
&M
) {
58 StringRef Key
= "dx.disable_optimizations";
59 M
.addModuleFlag(llvm::Module::ModFlagBehavior::Override
, Key
, 1);
61 // cbuffer will be translated into global variable in special address space.
62 // If translate into C,
67 // float foo() { return a + b; }
69 // will be translated into
74 // } cbuffer_A __attribute__((address_space(4)));
75 // float foo() { return cbuffer_A.a + cbuffer_A.b; }
77 // layoutBuffer will create the struct A type.
78 // replaceBuffer will replace use of global variable a and b with cbuffer_A.a
81 void layoutBuffer(CGHLSLRuntime::Buffer
&Buf
, const DataLayout
&DL
) {
82 if (Buf
.Constants
.empty())
85 std::vector
<llvm::Type
*> EltTys
;
86 for (auto &Const
: Buf
.Constants
) {
87 GlobalVariable
*GV
= Const
.first
;
88 Const
.second
= EltTys
.size();
89 llvm::Type
*Ty
= GV
->getValueType();
90 EltTys
.emplace_back(Ty
);
92 Buf
.LayoutStruct
= llvm::StructType::get(EltTys
[0]->getContext(), EltTys
);
95 GlobalVariable
*replaceBuffer(CGHLSLRuntime::Buffer
&Buf
) {
96 // Create global variable for CB.
97 GlobalVariable
*CBGV
= new GlobalVariable(
98 Buf
.LayoutStruct
, /*isConstant*/ true,
99 GlobalValue::LinkageTypes::ExternalLinkage
, nullptr,
100 llvm::formatv("{0}{1}", Buf
.Name
, Buf
.IsCBuffer
? ".cb." : ".tb."),
101 GlobalValue::NotThreadLocal
);
103 IRBuilder
<> B(CBGV
->getContext());
104 Value
*ZeroIdx
= B
.getInt32(0);
105 // Replace Const use with CB use.
106 for (auto &[GV
, Offset
] : Buf
.Constants
) {
108 B
.CreateGEP(Buf
.LayoutStruct
, CBGV
, {ZeroIdx
, B
.getInt32(Offset
)});
110 assert(Buf
.LayoutStruct
->getElementType(Offset
) == GV
->getValueType() &&
111 "constant type mismatch");
114 GV
->replaceAllUsesWith(GEP
);
116 GV
->removeDeadConstantUsers();
117 GV
->eraseFromParent();
124 llvm::Type
*CGHLSLRuntime::convertHLSLSpecificType(const Type
*T
) {
125 assert(T
->isHLSLSpecificType() && "Not an HLSL specific type!");
127 // Check if the target has a specific translation for this type first.
128 if (llvm::Type
*TargetTy
= CGM
.getTargetCodeGenInfo().getHLSLType(CGM
, T
))
131 llvm_unreachable("Generic handling of HLSL types is not supported.");
134 llvm::Triple::ArchType
CGHLSLRuntime::getArch() {
135 return CGM
.getTarget().getTriple().getArch();
138 void CGHLSLRuntime::addConstant(VarDecl
*D
, Buffer
&CB
) {
139 if (D
->getStorageClass() == SC_Static
) {
140 // For static inside cbuffer, take as global static.
141 // Don't add to cbuffer.
146 auto *GV
= cast
<GlobalVariable
>(CGM
.GetAddrOfGlobalVar(D
));
147 // Add debug info for constVal.
148 if (CGDebugInfo
*DI
= CGM
.getModuleDebugInfo())
149 if (CGM
.getCodeGenOpts().getDebugInfo() >=
150 codegenoptions::DebugInfoKind::LimitedDebugInfo
)
151 DI
->EmitGlobalVariable(cast
<GlobalVariable
>(GV
), D
);
153 // FIXME: support packoffset.
154 // See https://github.com/llvm/llvm-project/issues/57914.
156 bool HasUserOffset
= false;
158 unsigned LowerBound
= HasUserOffset
? Offset
: UINT_MAX
;
159 CB
.Constants
.emplace_back(std::make_pair(GV
, LowerBound
));
162 void CGHLSLRuntime::addBufferDecls(const DeclContext
*DC
, Buffer
&CB
) {
163 for (Decl
*it
: DC
->decls()) {
164 if (auto *ConstDecl
= dyn_cast
<VarDecl
>(it
)) {
165 addConstant(ConstDecl
, CB
);
166 } else if (isa
<CXXRecordDecl
, EmptyDecl
>(it
)) {
167 // Nothing to do for this declaration.
168 } else if (isa
<FunctionDecl
>(it
)) {
169 // A function within an cbuffer is effectively a top-level function,
170 // as it only refers to globally scoped declarations.
171 CGM
.EmitTopLevelDecl(it
);
176 void CGHLSLRuntime::addBuffer(const HLSLBufferDecl
*D
) {
177 Buffers
.emplace_back(Buffer(D
));
178 addBufferDecls(D
, Buffers
.back());
181 void CGHLSLRuntime::finishCodeGen() {
182 auto &TargetOpts
= CGM
.getTarget().getTargetOpts();
183 llvm::Module
&M
= CGM
.getModule();
184 Triple
T(M
.getTargetTriple());
185 if (T
.getArch() == Triple::ArchType::dxil
)
186 addDxilValVersion(TargetOpts
.DxilValidatorVersion
, M
);
188 generateGlobalCtorDtorCalls();
189 if (CGM
.getCodeGenOpts().OptimizationLevel
== 0)
190 addDisableOptimizations(M
);
192 const DataLayout
&DL
= M
.getDataLayout();
194 for (auto &Buf
: Buffers
) {
195 layoutBuffer(Buf
, DL
);
196 GlobalVariable
*GV
= replaceBuffer(Buf
);
197 M
.insertGlobalVariable(GV
);
198 llvm::hlsl::ResourceClass RC
= Buf
.IsCBuffer
199 ? llvm::hlsl::ResourceClass::CBuffer
200 : llvm::hlsl::ResourceClass::SRV
;
201 llvm::hlsl::ResourceKind RK
= Buf
.IsCBuffer
202 ? llvm::hlsl::ResourceKind::CBuffer
203 : llvm::hlsl::ResourceKind::TBuffer
;
204 addBufferResourceAnnotation(GV
, RC
, RK
, /*IsROV=*/false,
205 llvm::hlsl::ElementType::Invalid
, Buf
.Binding
);
209 CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl
*D
)
210 : Name(D
->getName()), IsCBuffer(D
->isCBuffer()),
211 Binding(D
->getAttr
<HLSLResourceBindingAttr
>()) {}
213 void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable
*GV
,
214 llvm::hlsl::ResourceClass RC
,
215 llvm::hlsl::ResourceKind RK
,
217 llvm::hlsl::ElementType ET
,
218 BufferResBinding
&Binding
) {
219 llvm::Module
&M
= CGM
.getModule();
221 NamedMDNode
*ResourceMD
= nullptr;
223 case llvm::hlsl::ResourceClass::UAV
:
224 ResourceMD
= M
.getOrInsertNamedMetadata("hlsl.uavs");
226 case llvm::hlsl::ResourceClass::SRV
:
227 ResourceMD
= M
.getOrInsertNamedMetadata("hlsl.srvs");
229 case llvm::hlsl::ResourceClass::CBuffer
:
230 ResourceMD
= M
.getOrInsertNamedMetadata("hlsl.cbufs");
233 assert(false && "Unsupported buffer type!");
236 assert(ResourceMD
!= nullptr &&
237 "ResourceMD must have been set by the switch above.");
239 llvm::hlsl::FrontendResource
Res(
240 GV
, RK
, ET
, IsROV
, Binding
.Reg
.value_or(UINT_MAX
), Binding
.Space
);
241 ResourceMD
->addOperand(Res
.getMetadata());
244 static llvm::hlsl::ElementType
245 calculateElementType(const ASTContext
&Context
, const clang::Type
*ResourceTy
) {
246 using llvm::hlsl::ElementType
;
248 // TODO: We may need to update this when we add things like ByteAddressBuffer
249 // that don't have a template parameter (or, indeed, an element type).
250 const auto *TST
= ResourceTy
->getAs
<TemplateSpecializationType
>();
251 assert(TST
&& "Resource types must be template specializations");
252 ArrayRef
<TemplateArgument
> Args
= TST
->template_arguments();
253 assert(!Args
.empty() && "Resource has no element type");
255 // At this point we have a resource with an element type, so we can assume
256 // that it's valid or we would have diagnosed the error earlier.
257 QualType ElTy
= Args
[0].getAsType();
259 // We should either have a basic type or a vector of a basic type.
260 if (const auto *VecTy
= ElTy
->getAs
<clang::VectorType
>())
261 ElTy
= VecTy
->getElementType();
263 if (ElTy
->isSignedIntegerType()) {
264 switch (Context
.getTypeSize(ElTy
)) {
266 return ElementType::I16
;
268 return ElementType::I32
;
270 return ElementType::I64
;
272 } else if (ElTy
->isUnsignedIntegerType()) {
273 switch (Context
.getTypeSize(ElTy
)) {
275 return ElementType::U16
;
277 return ElementType::U32
;
279 return ElementType::U64
;
281 } else if (ElTy
->isSpecificBuiltinType(BuiltinType::Half
))
282 return ElementType::F16
;
283 else if (ElTy
->isSpecificBuiltinType(BuiltinType::Float
))
284 return ElementType::F32
;
285 else if (ElTy
->isSpecificBuiltinType(BuiltinType::Double
))
286 return ElementType::F64
;
288 // TODO: We need to handle unorm/snorm float types here once we support them
289 llvm_unreachable("Invalid element type for resource");
292 void CGHLSLRuntime::annotateHLSLResource(const VarDecl
*D
, GlobalVariable
*GV
) {
293 const Type
*Ty
= D
->getType()->getPointeeOrArrayElementType();
296 const auto *RD
= Ty
->getAsCXXRecordDecl();
299 // the resource related attributes are on the handle member
300 // inside the record decl
301 for (auto *FD
: RD
->fields()) {
302 const auto *HLSLResAttr
= FD
->getAttr
<HLSLResourceAttr
>();
303 const HLSLAttributedResourceType
*AttrResType
=
304 dyn_cast
<HLSLAttributedResourceType
>(FD
->getType().getTypePtr());
305 if (!HLSLResAttr
|| !AttrResType
)
308 llvm::hlsl::ResourceClass RC
= AttrResType
->getAttrs().ResourceClass
;
309 if (RC
== llvm::hlsl::ResourceClass::UAV
||
310 RC
== llvm::hlsl::ResourceClass::SRV
)
311 // UAVs and SRVs have already been converted to use LLVM target types,
312 // we can disable generating of these resource annotations. This will
313 // enable progress on structured buffers with user defined types this
314 // resource annotations code does not handle and it crashes.
315 // This whole function is going to be removed as soon as cbuffers are
316 // converted to target types (llvm/llvm-project #114126).
319 bool IsROV
= AttrResType
->getAttrs().IsROV
;
320 llvm::hlsl::ResourceKind RK
= HLSLResAttr
->getResourceKind();
321 llvm::hlsl::ElementType ET
= calculateElementType(CGM
.getContext(), Ty
);
323 BufferResBinding
Binding(D
->getAttr
<HLSLResourceBindingAttr
>());
324 addBufferResourceAnnotation(GV
, RC
, RK
, IsROV
, ET
, Binding
);
328 CGHLSLRuntime::BufferResBinding::BufferResBinding(
329 HLSLResourceBindingAttr
*Binding
) {
331 llvm::APInt
RegInt(64, 0);
332 Binding
->getSlot().substr(1).getAsInteger(10, RegInt
);
333 Reg
= RegInt
.getLimitedValue();
334 llvm::APInt
SpaceInt(64, 0);
335 Binding
->getSpace().substr(5).getAsInteger(10, SpaceInt
);
336 Space
= SpaceInt
.getLimitedValue();
342 void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes(
343 const FunctionDecl
*FD
, llvm::Function
*Fn
) {
344 const auto *ShaderAttr
= FD
->getAttr
<HLSLShaderAttr
>();
345 assert(ShaderAttr
&& "All entry functions must have a HLSLShaderAttr");
346 const StringRef ShaderAttrKindStr
= "hlsl.shader";
347 Fn
->addFnAttr(ShaderAttrKindStr
,
348 llvm::Triple::getEnvironmentTypeName(ShaderAttr
->getType()));
349 if (HLSLNumThreadsAttr
*NumThreadsAttr
= FD
->getAttr
<HLSLNumThreadsAttr
>()) {
350 const StringRef NumThreadsKindStr
= "hlsl.numthreads";
351 std::string NumThreadsStr
=
352 formatv("{0},{1},{2}", NumThreadsAttr
->getX(), NumThreadsAttr
->getY(),
353 NumThreadsAttr
->getZ());
354 Fn
->addFnAttr(NumThreadsKindStr
, NumThreadsStr
);
356 if (HLSLWaveSizeAttr
*WaveSizeAttr
= FD
->getAttr
<HLSLWaveSizeAttr
>()) {
357 const StringRef WaveSizeKindStr
= "hlsl.wavesize";
358 std::string WaveSizeStr
=
359 formatv("{0},{1},{2}", WaveSizeAttr
->getMin(), WaveSizeAttr
->getMax(),
360 WaveSizeAttr
->getPreferred());
361 Fn
->addFnAttr(WaveSizeKindStr
, WaveSizeStr
);
363 Fn
->addFnAttr(llvm::Attribute::NoInline
);
366 static Value
*buildVectorInput(IRBuilder
<> &B
, Function
*F
, llvm::Type
*Ty
) {
367 if (const auto *VT
= dyn_cast
<FixedVectorType
>(Ty
)) {
368 Value
*Result
= PoisonValue::get(Ty
);
369 for (unsigned I
= 0; I
< VT
->getNumElements(); ++I
) {
370 Value
*Elt
= B
.CreateCall(F
, {B
.getInt32(I
)});
371 Result
= B
.CreateInsertElement(Result
, Elt
, I
);
375 return B
.CreateCall(F
, {B
.getInt32(0)});
378 llvm::Value
*CGHLSLRuntime::emitInputSemantic(IRBuilder
<> &B
,
379 const ParmVarDecl
&D
,
381 assert(D
.hasAttrs() && "Entry parameter missing annotation attribute!");
382 if (D
.hasAttr
<HLSLSV_GroupIndexAttr
>()) {
383 llvm::Function
*DxGroupIndex
=
384 CGM
.getIntrinsic(Intrinsic::dx_flattened_thread_id_in_group
);
385 return B
.CreateCall(FunctionCallee(DxGroupIndex
));
387 if (D
.hasAttr
<HLSLSV_DispatchThreadIDAttr
>()) {
388 llvm::Function
*ThreadIDIntrinsic
=
389 CGM
.getIntrinsic(getThreadIdIntrinsic());
390 return buildVectorInput(B
, ThreadIDIntrinsic
, Ty
);
392 if (D
.hasAttr
<HLSLSV_GroupIDAttr
>()) {
393 llvm::Function
*GroupIDIntrinsic
= CGM
.getIntrinsic(Intrinsic::dx_group_id
);
394 return buildVectorInput(B
, GroupIDIntrinsic
, Ty
);
396 assert(false && "Unhandled parameter attribute");
400 void CGHLSLRuntime::emitEntryFunction(const FunctionDecl
*FD
,
401 llvm::Function
*Fn
) {
402 llvm::Module
&M
= CGM
.getModule();
403 llvm::LLVMContext
&Ctx
= M
.getContext();
404 auto *EntryTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx
), false);
406 Function::Create(EntryTy
, Function::ExternalLinkage
, FD
->getName(), &M
);
408 // Copy function attributes over, we have no argument or return attributes
409 // that can be valid on the real entry.
410 AttributeList NewAttrs
= AttributeList::get(Ctx
, AttributeList::FunctionIndex
,
411 Fn
->getAttributes().getFnAttrs());
412 EntryFn
->setAttributes(NewAttrs
);
413 setHLSLEntryAttributes(FD
, EntryFn
);
415 // Set the called function as internal linkage.
416 Fn
->setLinkage(GlobalValue::InternalLinkage
);
418 BasicBlock
*BB
= BasicBlock::Create(Ctx
, "entry", EntryFn
);
420 llvm::SmallVector
<Value
*> Args
;
422 SmallVector
<OperandBundleDef
, 1> OB
;
423 if (CGM
.shouldEmitConvergenceTokens()) {
424 assert(EntryFn
->isConvergent());
425 llvm::Value
*I
= B
.CreateIntrinsic(
426 llvm::Intrinsic::experimental_convergence_entry
, {}, {});
427 llvm::Value
*bundleArgs
[] = {I
};
428 OB
.emplace_back("convergencectrl", bundleArgs
);
431 // FIXME: support struct parameters where semantics are on members.
432 // See: https://github.com/llvm/llvm-project/issues/57874
433 unsigned SRetOffset
= 0;
434 for (const auto &Param
: Fn
->args()) {
435 if (Param
.hasStructRetAttr()) {
436 // FIXME: support output.
437 // See: https://github.com/llvm/llvm-project/issues/57874
439 Args
.emplace_back(PoisonValue::get(Param
.getType()));
442 const ParmVarDecl
*PD
= FD
->getParamDecl(Param
.getArgNo() - SRetOffset
);
443 Args
.push_back(emitInputSemantic(B
, *PD
, Param
.getType()));
446 CallInst
*CI
= B
.CreateCall(FunctionCallee(Fn
), Args
, OB
);
447 CI
->setCallingConv(Fn
->getCallingConv());
448 // FIXME: Handle codegen for return type semantics.
449 // See: https://github.com/llvm/llvm-project/issues/57875
453 void CGHLSLRuntime::setHLSLFunctionAttributes(const FunctionDecl
*FD
,
454 llvm::Function
*Fn
) {
455 if (FD
->isInExportDeclContext()) {
456 const StringRef ExportAttrKindStr
= "hlsl.export";
457 Fn
->addFnAttr(ExportAttrKindStr
);
461 static void gatherFunctions(SmallVectorImpl
<Function
*> &Fns
, llvm::Module
&M
,
464 M
.getNamedGlobal(CtorOrDtor
? "llvm.global_ctors" : "llvm.global_dtors");
467 const auto *CA
= dyn_cast
<ConstantArray
>(GV
->getInitializer());
470 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
471 // HLSL neither supports priorities or COMDat values, so we will check those
472 // in an assert but not handle them.
474 llvm::SmallVector
<Function
*> CtorFns
;
475 for (const auto &Ctor
: CA
->operands()) {
476 if (isa
<ConstantAggregateZero
>(Ctor
))
478 ConstantStruct
*CS
= cast
<ConstantStruct
>(Ctor
);
480 assert(cast
<ConstantInt
>(CS
->getOperand(0))->getValue() == 65535 &&
481 "HLSL doesn't support setting priority for global ctors.");
482 assert(isa
<ConstantPointerNull
>(CS
->getOperand(2)) &&
483 "HLSL doesn't support COMDat for global ctors.");
484 Fns
.push_back(cast
<Function
>(CS
->getOperand(1)));
488 void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
489 llvm::Module
&M
= CGM
.getModule();
490 SmallVector
<Function
*> CtorFns
;
491 SmallVector
<Function
*> DtorFns
;
492 gatherFunctions(CtorFns
, M
, true);
493 gatherFunctions(DtorFns
, M
, false);
495 // Insert a call to the global constructor at the beginning of the entry block
496 // to externally exported functions. This is a bit of a hack, but HLSL allows
497 // global constructors, but doesn't support driver initialization of globals.
498 for (auto &F
: M
.functions()) {
499 if (!F
.hasFnAttribute("hlsl.shader"))
501 auto *Token
= getConvergenceToken(F
.getEntryBlock());
502 Instruction
*IP
= &*F
.getEntryBlock().begin();
503 SmallVector
<OperandBundleDef
, 1> OB
;
505 llvm::Value
*bundleArgs
[] = {Token
};
506 OB
.emplace_back("convergencectrl", bundleArgs
);
507 IP
= Token
->getNextNode();
510 for (auto *Fn
: CtorFns
)
511 B
.CreateCall(FunctionCallee(Fn
), {}, OB
);
513 // Insert global dtors before the terminator of the last instruction
514 B
.SetInsertPoint(F
.back().getTerminator());
515 for (auto *Fn
: DtorFns
)
516 B
.CreateCall(FunctionCallee(Fn
), {}, OB
);
519 // No need to keep global ctors/dtors for non-lib profile after call to
520 // ctors/dtors added for entry.
521 Triple
T(M
.getTargetTriple());
522 if (T
.getEnvironment() != Triple::EnvironmentType::Library
) {
523 if (auto *GV
= M
.getNamedGlobal("llvm.global_ctors"))
524 GV
->eraseFromParent();
525 if (auto *GV
= M
.getNamedGlobal("llvm.global_dtors"))
526 GV
->eraseFromParent();
530 void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl
*VD
,
531 llvm::GlobalVariable
*GV
) {
532 // If the global variable has resource binding, add it to the list of globals
533 // that need resource binding initialization.
534 const HLSLResourceBindingAttr
*RBA
= VD
->getAttr
<HLSLResourceBindingAttr
>();
538 if (!HLSLAttributedResourceType::findHandleTypeOnResource(
539 VD
->getType().getTypePtr()))
540 // FIXME: Only simple declarations of resources are supported for now.
541 // Arrays of resources or resources in user defined classes are
542 // not implemented yet.
545 ResourcesToBind
.emplace_back(VD
, GV
);
548 bool CGHLSLRuntime::needsResourceBindingInitFn() {
549 return !ResourcesToBind
.empty();
552 llvm::Function
*CGHLSLRuntime::createResourceBindingInitFn() {
553 // No resources to bind
554 assert(needsResourceBindingInitFn() && "no resources to bind");
556 LLVMContext
&Ctx
= CGM
.getLLVMContext();
557 llvm::Type
*Int1Ty
= llvm::Type::getInt1Ty(Ctx
);
559 llvm::Function
*InitResBindingsFunc
=
560 llvm::Function::Create(llvm::FunctionType::get(CGM
.VoidTy
, false),
561 llvm::GlobalValue::InternalLinkage
,
562 "_init_resource_bindings", CGM
.getModule());
564 llvm::BasicBlock
*EntryBB
=
565 llvm::BasicBlock::Create(Ctx
, "entry", InitResBindingsFunc
);
566 CGBuilderTy
Builder(CGM
, Ctx
);
567 const DataLayout
&DL
= CGM
.getModule().getDataLayout();
568 Builder
.SetInsertPoint(EntryBB
);
570 for (const auto &[VD
, GV
] : ResourcesToBind
) {
571 for (Attr
*A
: VD
->getAttrs()) {
572 HLSLResourceBindingAttr
*RBA
= dyn_cast
<HLSLResourceBindingAttr
>(A
);
576 const HLSLAttributedResourceType
*AttrResType
=
577 HLSLAttributedResourceType::findHandleTypeOnResource(
578 VD
->getType().getTypePtr());
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");
586 llvm::Type
*TargetTy
=
587 CGM
.getTargetCodeGenInfo().getHLSLType(CGM
, AttrResType
);
588 assert(TargetTy
!= nullptr &&
589 "Failed to convert resource handle to target type");
591 auto *Space
= llvm::ConstantInt::get(CGM
.IntTy
, RBA
->getSpaceNumber());
592 auto *Slot
= llvm::ConstantInt::get(CGM
.IntTy
, RBA
->getSlotNumber());
593 // FIXME: resource arrays are not yet implemented
594 auto *Range
= llvm::ConstantInt::get(CGM
.IntTy
, 1);
595 auto *Index
= llvm::ConstantInt::get(CGM
.IntTy
, 0);
596 // FIXME: NonUniformResourceIndex bit is not yet implemented
597 auto *NonUniform
= llvm::ConstantInt::get(Int1Ty
, false);
598 llvm::Value
*Args
[] = {Space
, Slot
, Range
, Index
, NonUniform
};
600 llvm::Value
*CreateHandle
= Builder
.CreateIntrinsic(
601 /*ReturnType=*/TargetTy
, getCreateHandleFromBindingIntrinsic(), Args
,
602 nullptr, Twine(VD
->getName()).concat("_h"));
604 llvm::Value
*HandleRef
=
605 Builder
.CreateStructGEP(GV
->getValueType(), GV
, 0);
606 Builder
.CreateAlignedStore(CreateHandle
, HandleRef
,
607 HandleRef
->getPointerAlignment(DL
));
611 Builder
.CreateRetVoid();
612 return InitResBindingsFunc
;
615 llvm::Instruction
*CGHLSLRuntime::getConvergenceToken(BasicBlock
&BB
) {
616 if (!CGM
.shouldEmitConvergenceTokens())
620 for (auto I
= BB
.begin(); I
!= E
; ++I
) {
621 auto *II
= dyn_cast
<llvm::IntrinsicInst
>(&*I
);
622 if (II
&& llvm::isConvergenceControlIntrinsic(II
->getIntrinsicID())) {
626 llvm_unreachable("Convergence token should have been emitted.");