xref: /llvm-project/clang/lib/CodeGen/CGHLSLRuntime.cpp (revision d92bac8a3ebb19106f6bca6b7613a27c52cb48ab)
1 //===----- CGHLSLRuntime.cpp - Interface to HLSL Runtimes -----------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This provides an abstract class for HLSL code generation.  Concrete
10 // subclasses of this implement code generation for specific HLSL
11 // runtime libraries.
12 //
13 //===----------------------------------------------------------------------===//
14 
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"
27 
28 #include "llvm/Support/FormatVariadic.h"
29 
30 using namespace clang;
31 using namespace CodeGen;
32 using namespace clang::hlsl;
33 using namespace llvm;
34 
35 namespace {
36 
37 void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
38   // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
39   // Assume ValVersionStr is legal here.
40   VersionTuple Version;
41   if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
42       Version.getSubminor() || !Version.getMinor()) {
43     return;
44   }
45 
46   uint64_t Major = Version.getMajor();
47   uint64_t Minor = *Version.getMinor();
48 
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);
56 }
57 void addDisableOptimizations(llvm::Module &M) {
58   StringRef Key = "dx.disable_optimizations";
59   M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
60 }
61 // cbuffer will be translated into global variable in special address space.
62 // If translate into C,
63 // cbuffer A {
64 //   float a;
65 //   float b;
66 // }
67 // float foo() { return a + b; }
68 //
69 // will be translated into
70 //
71 // struct A {
72 //   float a;
73 //   float b;
74 // } cbuffer_A __attribute__((address_space(4)));
75 // float foo() { return cbuffer_A.a + cbuffer_A.b; }
76 //
77 // layoutBuffer will create the struct A type.
78 // replaceBuffer will replace use of global variable a and b with cbuffer_A.a
79 // and cbuffer_A.b.
80 //
81 void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
82   if (Buf.Constants.empty())
83     return;
84 
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);
91   }
92   Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
93 }
94 
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);
102 
103   return CBGV;
104 }
105 
106 } // namespace
107 
108 llvm::Type *CGHLSLRuntime::convertHLSLSpecificType(const Type *T) {
109   assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
110 
111   // Check if the target has a specific translation for this type first.
112   if (llvm::Type *TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, T))
113     return TargetTy;
114 
115   llvm_unreachable("Generic handling of HLSL types is not supported.");
116 }
117 
118 llvm::Triple::ArchType CGHLSLRuntime::getArch() {
119   return CGM.getTarget().getTriple().getArch();
120 }
121 
122 void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
123   if (D->getStorageClass() == SC_Static) {
124     // For static inside cbuffer, take as global static.
125     // Don't add to cbuffer.
126     CGM.EmitGlobal(D);
127     return;
128   }
129 
130   auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
131   GV->setExternallyInitialized(true);
132   // Add debug info for constVal.
133   if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
134     if (CGM.getCodeGenOpts().getDebugInfo() >=
135         codegenoptions::DebugInfoKind::LimitedDebugInfo)
136       DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
137 
138   // FIXME: support packoffset.
139   // See https://github.com/llvm/llvm-project/issues/57914.
140   uint32_t Offset = 0;
141   bool HasUserOffset = false;
142 
143   unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
144   CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
145 }
146 
147 void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
148   for (Decl *it : DC->decls()) {
149     if (auto *ConstDecl = dyn_cast<VarDecl>(it)) {
150       addConstant(ConstDecl, CB);
151     } else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
152       // Nothing to do for this declaration.
153     } else if (isa<FunctionDecl>(it)) {
154       // A function within an cbuffer is effectively a top-level function,
155       // as it only refers to globally scoped declarations.
156       CGM.EmitTopLevelDecl(it);
157     }
158   }
159 }
160 
161 void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
162   Buffers.emplace_back(Buffer(D));
163   addBufferDecls(D, Buffers.back());
164 }
165 
166 void CGHLSLRuntime::finishCodeGen() {
167   auto &TargetOpts = CGM.getTarget().getTargetOpts();
168   llvm::Module &M = CGM.getModule();
169   Triple T(M.getTargetTriple());
170   if (T.getArch() == Triple::ArchType::dxil)
171     addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
172 
173   generateGlobalCtorDtorCalls();
174   if (CGM.getCodeGenOpts().OptimizationLevel == 0)
175     addDisableOptimizations(M);
176 
177   const DataLayout &DL = M.getDataLayout();
178 
179   for (auto &Buf : Buffers) {
180     layoutBuffer(Buf, DL);
181     GlobalVariable *GV = replaceBuffer(Buf);
182     M.insertGlobalVariable(GV);
183     llvm::hlsl::ResourceClass RC = Buf.IsCBuffer
184                                        ? llvm::hlsl::ResourceClass::CBuffer
185                                        : llvm::hlsl::ResourceClass::SRV;
186     llvm::hlsl::ResourceKind RK = Buf.IsCBuffer
187                                       ? llvm::hlsl::ResourceKind::CBuffer
188                                       : llvm::hlsl::ResourceKind::TBuffer;
189     addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false,
190                                 llvm::hlsl::ElementType::Invalid, Buf.Binding);
191   }
192 }
193 
194 CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
195     : Name(D->getName()), IsCBuffer(D->isCBuffer()),
196       Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
197 
198 void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
199                                                 llvm::hlsl::ResourceClass RC,
200                                                 llvm::hlsl::ResourceKind RK,
201                                                 bool IsROV,
202                                                 llvm::hlsl::ElementType ET,
203                                                 BufferResBinding &Binding) {
204   llvm::Module &M = CGM.getModule();
205 
206   NamedMDNode *ResourceMD = nullptr;
207   switch (RC) {
208   case llvm::hlsl::ResourceClass::UAV:
209     ResourceMD = M.getOrInsertNamedMetadata("hlsl.uavs");
210     break;
211   case llvm::hlsl::ResourceClass::SRV:
212     ResourceMD = M.getOrInsertNamedMetadata("hlsl.srvs");
213     break;
214   case llvm::hlsl::ResourceClass::CBuffer:
215     ResourceMD = M.getOrInsertNamedMetadata("hlsl.cbufs");
216     break;
217   default:
218     assert(false && "Unsupported buffer type!");
219     return;
220   }
221   assert(ResourceMD != nullptr &&
222          "ResourceMD must have been set by the switch above.");
223 
224   llvm::hlsl::FrontendResource Res(
225       GV, RK, ET, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
226   ResourceMD->addOperand(Res.getMetadata());
227 }
228 
229 static llvm::hlsl::ElementType
230 calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy) {
231   using llvm::hlsl::ElementType;
232 
233   // TODO: We may need to update this when we add things like ByteAddressBuffer
234   // that don't have a template parameter (or, indeed, an element type).
235   const auto *TST = ResourceTy->getAs<TemplateSpecializationType>();
236   assert(TST && "Resource types must be template specializations");
237   ArrayRef<TemplateArgument> Args = TST->template_arguments();
238   assert(!Args.empty() && "Resource has no element type");
239 
240   // At this point we have a resource with an element type, so we can assume
241   // that it's valid or we would have diagnosed the error earlier.
242   QualType ElTy = Args[0].getAsType();
243 
244   // We should either have a basic type or a vector of a basic type.
245   if (const auto *VecTy = ElTy->getAs<clang::VectorType>())
246     ElTy = VecTy->getElementType();
247 
248   if (ElTy->isSignedIntegerType()) {
249     switch (Context.getTypeSize(ElTy)) {
250     case 16:
251       return ElementType::I16;
252     case 32:
253       return ElementType::I32;
254     case 64:
255       return ElementType::I64;
256     }
257   } else if (ElTy->isUnsignedIntegerType()) {
258     switch (Context.getTypeSize(ElTy)) {
259     case 16:
260       return ElementType::U16;
261     case 32:
262       return ElementType::U32;
263     case 64:
264       return ElementType::U64;
265     }
266   } else if (ElTy->isSpecificBuiltinType(BuiltinType::Half))
267     return ElementType::F16;
268   else if (ElTy->isSpecificBuiltinType(BuiltinType::Float))
269     return ElementType::F32;
270   else if (ElTy->isSpecificBuiltinType(BuiltinType::Double))
271     return ElementType::F64;
272 
273   // TODO: We need to handle unorm/snorm float types here once we support them
274   llvm_unreachable("Invalid element type for resource");
275 }
276 
277 void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
278   const Type *Ty = D->getType()->getPointeeOrArrayElementType();
279   if (!Ty)
280     return;
281   const auto *RD = Ty->getAsCXXRecordDecl();
282   if (!RD)
283     return;
284   // the resource related attributes are on the handle member
285   // inside the record decl
286   for (auto *FD : RD->fields()) {
287     const auto *HLSLResAttr = FD->getAttr<HLSLResourceAttr>();
288     const HLSLAttributedResourceType *AttrResType =
289         dyn_cast<HLSLAttributedResourceType>(FD->getType().getTypePtr());
290     if (!HLSLResAttr || !AttrResType)
291       continue;
292 
293     llvm::hlsl::ResourceClass RC = AttrResType->getAttrs().ResourceClass;
294     if (RC == llvm::hlsl::ResourceClass::UAV ||
295         RC == llvm::hlsl::ResourceClass::SRV)
296       // UAVs and SRVs have already been converted to use LLVM target types,
297       // we can disable generating of these resource annotations. This will
298       // enable progress on structured buffers with user defined types this
299       // resource annotations code does not handle and it crashes.
300       // This whole function is going to be removed as soon as cbuffers are
301       // converted to target types (llvm/llvm-project #114126).
302       return;
303 
304     bool IsROV = AttrResType->getAttrs().IsROV;
305     llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind();
306     llvm::hlsl::ElementType ET = calculateElementType(CGM.getContext(), Ty);
307 
308     BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>());
309     addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
310   }
311 }
312 
313 CGHLSLRuntime::BufferResBinding::BufferResBinding(
314     HLSLResourceBindingAttr *Binding) {
315   if (Binding) {
316     llvm::APInt RegInt(64, 0);
317     Binding->getSlot().substr(1).getAsInteger(10, RegInt);
318     Reg = RegInt.getLimitedValue();
319     llvm::APInt SpaceInt(64, 0);
320     Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
321     Space = SpaceInt.getLimitedValue();
322   } else {
323     Space = 0;
324   }
325 }
326 
327 void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes(
328     const FunctionDecl *FD, llvm::Function *Fn) {
329   const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
330   assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
331   const StringRef ShaderAttrKindStr = "hlsl.shader";
332   Fn->addFnAttr(ShaderAttrKindStr,
333                 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
334   if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
335     const StringRef NumThreadsKindStr = "hlsl.numthreads";
336     std::string NumThreadsStr =
337         formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
338                 NumThreadsAttr->getZ());
339     Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
340   }
341   if (HLSLWaveSizeAttr *WaveSizeAttr = FD->getAttr<HLSLWaveSizeAttr>()) {
342     const StringRef WaveSizeKindStr = "hlsl.wavesize";
343     std::string WaveSizeStr =
344         formatv("{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
345                 WaveSizeAttr->getPreferred());
346     Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
347   }
348   Fn->addFnAttr(llvm::Attribute::NoInline);
349 }
350 
351 static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
352   if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
353     Value *Result = PoisonValue::get(Ty);
354     for (unsigned I = 0; I < VT->getNumElements(); ++I) {
355       Value *Elt = B.CreateCall(F, {B.getInt32(I)});
356       Result = B.CreateInsertElement(Result, Elt, I);
357     }
358     return Result;
359   }
360   return B.CreateCall(F, {B.getInt32(0)});
361 }
362 
363 llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
364                                               const ParmVarDecl &D,
365                                               llvm::Type *Ty) {
366   assert(D.hasAttrs() && "Entry parameter missing annotation attribute!");
367   if (D.hasAttr<HLSLSV_GroupIndexAttr>()) {
368     llvm::Function *DxGroupIndex =
369         CGM.getIntrinsic(Intrinsic::dx_flattened_thread_id_in_group);
370     return B.CreateCall(FunctionCallee(DxGroupIndex));
371   }
372   if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
373     llvm::Function *ThreadIDIntrinsic =
374         CGM.getIntrinsic(getThreadIdIntrinsic());
375     return buildVectorInput(B, ThreadIDIntrinsic, Ty);
376   }
377   if (D.hasAttr<HLSLSV_GroupThreadIDAttr>()) {
378     llvm::Function *GroupThreadIDIntrinsic =
379         CGM.getIntrinsic(getGroupThreadIdIntrinsic());
380     return buildVectorInput(B, GroupThreadIDIntrinsic, Ty);
381   }
382   if (D.hasAttr<HLSLSV_GroupIDAttr>()) {
383     llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic());
384     return buildVectorInput(B, GroupIDIntrinsic, Ty);
385   }
386   assert(false && "Unhandled parameter attribute");
387   return nullptr;
388 }
389 
390 void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
391                                       llvm::Function *Fn) {
392   llvm::Module &M = CGM.getModule();
393   llvm::LLVMContext &Ctx = M.getContext();
394   auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
395   Function *EntryFn =
396       Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
397 
398   // Copy function attributes over, we have no argument or return attributes
399   // that can be valid on the real entry.
400   AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
401                                               Fn->getAttributes().getFnAttrs());
402   EntryFn->setAttributes(NewAttrs);
403   setHLSLEntryAttributes(FD, EntryFn);
404 
405   // Set the called function as internal linkage.
406   Fn->setLinkage(GlobalValue::InternalLinkage);
407 
408   BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
409   IRBuilder<> B(BB);
410   llvm::SmallVector<Value *> Args;
411 
412   SmallVector<OperandBundleDef, 1> OB;
413   if (CGM.shouldEmitConvergenceTokens()) {
414     assert(EntryFn->isConvergent());
415     llvm::Value *I = B.CreateIntrinsic(
416         llvm::Intrinsic::experimental_convergence_entry, {}, {});
417     llvm::Value *bundleArgs[] = {I};
418     OB.emplace_back("convergencectrl", bundleArgs);
419   }
420 
421   // FIXME: support struct parameters where semantics are on members.
422   // See: https://github.com/llvm/llvm-project/issues/57874
423   unsigned SRetOffset = 0;
424   for (const auto &Param : Fn->args()) {
425     if (Param.hasStructRetAttr()) {
426       // FIXME: support output.
427       // See: https://github.com/llvm/llvm-project/issues/57874
428       SRetOffset = 1;
429       Args.emplace_back(PoisonValue::get(Param.getType()));
430       continue;
431     }
432     const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
433     Args.push_back(emitInputSemantic(B, *PD, Param.getType()));
434   }
435 
436   CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
437   CI->setCallingConv(Fn->getCallingConv());
438   // FIXME: Handle codegen for return type semantics.
439   // See: https://github.com/llvm/llvm-project/issues/57875
440   B.CreateRetVoid();
441 }
442 
443 void CGHLSLRuntime::setHLSLFunctionAttributes(const FunctionDecl *FD,
444                                               llvm::Function *Fn) {
445   if (FD->isInExportDeclContext()) {
446     const StringRef ExportAttrKindStr = "hlsl.export";
447     Fn->addFnAttr(ExportAttrKindStr);
448   }
449 }
450 
451 static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
452                             bool CtorOrDtor) {
453   const auto *GV =
454       M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
455   if (!GV)
456     return;
457   const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
458   if (!CA)
459     return;
460   // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
461   // HLSL neither supports priorities or COMDat values, so we will check those
462   // in an assert but not handle them.
463 
464   llvm::SmallVector<Function *> CtorFns;
465   for (const auto &Ctor : CA->operands()) {
466     if (isa<ConstantAggregateZero>(Ctor))
467       continue;
468     ConstantStruct *CS = cast<ConstantStruct>(Ctor);
469 
470     assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
471            "HLSL doesn't support setting priority for global ctors.");
472     assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
473            "HLSL doesn't support COMDat for global ctors.");
474     Fns.push_back(cast<Function>(CS->getOperand(1)));
475   }
476 }
477 
478 void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
479   llvm::Module &M = CGM.getModule();
480   SmallVector<Function *> CtorFns;
481   SmallVector<Function *> DtorFns;
482   gatherFunctions(CtorFns, M, true);
483   gatherFunctions(DtorFns, M, false);
484 
485   // Insert a call to the global constructor at the beginning of the entry block
486   // to externally exported functions. This is a bit of a hack, but HLSL allows
487   // global constructors, but doesn't support driver initialization of globals.
488   for (auto &F : M.functions()) {
489     if (!F.hasFnAttribute("hlsl.shader"))
490       continue;
491     auto *Token = getConvergenceToken(F.getEntryBlock());
492     Instruction *IP = &*F.getEntryBlock().begin();
493     SmallVector<OperandBundleDef, 1> OB;
494     if (Token) {
495       llvm::Value *bundleArgs[] = {Token};
496       OB.emplace_back("convergencectrl", bundleArgs);
497       IP = Token->getNextNode();
498     }
499     IRBuilder<> B(IP);
500     for (auto *Fn : CtorFns) {
501       auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
502       CI->setCallingConv(Fn->getCallingConv());
503     }
504 
505     // Insert global dtors before the terminator of the last instruction
506     B.SetInsertPoint(F.back().getTerminator());
507     for (auto *Fn : DtorFns) {
508       auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
509       CI->setCallingConv(Fn->getCallingConv());
510     }
511   }
512 
513   // No need to keep global ctors/dtors for non-lib profile after call to
514   // ctors/dtors added for entry.
515   Triple T(M.getTargetTriple());
516   if (T.getEnvironment() != Triple::EnvironmentType::Library) {
517     if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
518       GV->eraseFromParent();
519     if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
520       GV->eraseFromParent();
521   }
522 }
523 
524 // Returns true if the type is an HLSL resource class
525 static bool isResourceRecordType(const clang::Type *Ty) {
526   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
527 }
528 
529 static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD,
530                                  llvm::GlobalVariable *GV, unsigned Slot,
531                                  unsigned Space) {
532   LLVMContext &Ctx = CGM.getLLVMContext();
533   llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);
534 
535   llvm::Function *InitResFunc = llvm::Function::Create(
536       llvm::FunctionType::get(CGM.VoidTy, false),
537       llvm::GlobalValue::InternalLinkage,
538       ("_init_resource_" + VD->getName()).str(), CGM.getModule());
539   InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
540 
541   llvm::BasicBlock *EntryBB =
542       llvm::BasicBlock::Create(Ctx, "entry", InitResFunc);
543   CGBuilderTy Builder(CGM, Ctx);
544   const DataLayout &DL = CGM.getModule().getDataLayout();
545   Builder.SetInsertPoint(EntryBB);
546 
547   const HLSLAttributedResourceType *AttrResType =
548       HLSLAttributedResourceType::findHandleTypeOnResource(
549           VD->getType().getTypePtr());
550 
551   // FIXME: Only simple declarations of resources are supported for now.
552   // Arrays of resources or resources in user defined classes are
553   // not implemented yet.
554   assert(AttrResType != nullptr &&
555          "Resource class must have a handle of HLSLAttributedResourceType");
556 
557   llvm::Type *TargetTy =
558       CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
559   assert(TargetTy != nullptr &&
560          "Failed to convert resource handle to target type");
561 
562   llvm::Value *Args[] = {
563       llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
564       llvm::ConstantInt::get(CGM.IntTy, Slot),  /* lower_bound */
565       // FIXME: resource arrays are not yet implemented
566       llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */
567       llvm::ConstantInt::get(CGM.IntTy, 0), /* index */
568       // FIXME: NonUniformResourceIndex bit is not yet implemented
569       llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
570   };
571   llvm::Value *CreateHandle = Builder.CreateIntrinsic(
572       /*ReturnType=*/TargetTy,
573       CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), Args, nullptr,
574       Twine(VD->getName()).concat("_h"));
575 
576   llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
577   Builder.CreateAlignedStore(CreateHandle, HandleRef,
578                              HandleRef->getPointerAlignment(DL));
579   Builder.CreateRetVoid();
580 
581   CGM.AddCXXGlobalInit(InitResFunc);
582 }
583 
584 void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
585                                               llvm::GlobalVariable *GV) {
586 
587   // If the global variable has resource binding, create an init function
588   // for the resource
589   const HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
590   if (!RBA)
591     // FIXME: collect unbound resources for implicit binding resolution later
592     // on?
593     return;
594 
595   if (!isResourceRecordType(VD->getType().getTypePtr()))
596     // FIXME: Only simple declarations of resources are supported for now.
597     // Arrays of resources or resources in user defined classes are
598     // not implemented yet.
599     return;
600 
601   createResourceInitFn(CGM, VD, GV, RBA->getSlotNumber(),
602                        RBA->getSpaceNumber());
603 }
604 
605 llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
606   if (!CGM.shouldEmitConvergenceTokens())
607     return nullptr;
608 
609   auto E = BB.end();
610   for (auto I = BB.begin(); I != E; ++I) {
611     auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
612     if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
613       return II;
614     }
615   }
616   llvm_unreachable("Convergence token should have been emitted.");
617   return nullptr;
618 }
619