[OpenACC] Implement 'collapse' for combined constructs.
[llvm-project.git] / clang / lib / CodeGen / CGHLSLRuntime.cpp
blob2c293523fca8cacef7d846019b1d175cdf8f21e1
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.
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;
33 using namespace llvm;
35 namespace {
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;
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,
63 // cbuffer A {
64 // float a;
65 // float b;
66 // }
67 // float foo() { return a + b; }
69 // will be translated into
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; }
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.
81 void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
82 if (Buf.Constants.empty())
83 return;
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) {
107 Value *GEP =
108 B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
110 assert(Buf.LayoutStruct->getElementType(Offset) == GV->getValueType() &&
111 "constant type mismatch");
113 // Replace.
114 GV->replaceAllUsesWith(GEP);
115 // Erase GV.
116 GV->removeDeadConstantUsers();
117 GV->eraseFromParent();
119 return CBGV;
122 } // namespace
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))
129 return TargetTy;
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.
142 CGM.EmitGlobal(D);
143 return;
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.
155 uint32_t Offset = 0;
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,
216 bool IsROV,
217 llvm::hlsl::ElementType ET,
218 BufferResBinding &Binding) {
219 llvm::Module &M = CGM.getModule();
221 NamedMDNode *ResourceMD = nullptr;
222 switch (RC) {
223 case llvm::hlsl::ResourceClass::UAV:
224 ResourceMD = M.getOrInsertNamedMetadata("hlsl.uavs");
225 break;
226 case llvm::hlsl::ResourceClass::SRV:
227 ResourceMD = M.getOrInsertNamedMetadata("hlsl.srvs");
228 break;
229 case llvm::hlsl::ResourceClass::CBuffer:
230 ResourceMD = M.getOrInsertNamedMetadata("hlsl.cbufs");
231 break;
232 default:
233 assert(false && "Unsupported buffer type!");
234 return;
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)) {
265 case 16:
266 return ElementType::I16;
267 case 32:
268 return ElementType::I32;
269 case 64:
270 return ElementType::I64;
272 } else if (ElTy->isUnsignedIntegerType()) {
273 switch (Context.getTypeSize(ElTy)) {
274 case 16:
275 return ElementType::U16;
276 case 32:
277 return ElementType::U32;
278 case 64:
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();
294 if (!Ty)
295 return;
296 const auto *RD = Ty->getAsCXXRecordDecl();
297 if (!RD)
298 return;
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)
306 continue;
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).
317 return;
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) {
330 if (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();
337 } else {
338 Space = 0;
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);
373 return Result;
375 return B.CreateCall(F, {B.getInt32(0)});
378 llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
379 const ParmVarDecl &D,
380 llvm::Type *Ty) {
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");
397 return nullptr;
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);
405 Function *EntryFn =
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);
419 IRBuilder<> B(BB);
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
438 SRetOffset = 1;
439 Args.emplace_back(PoisonValue::get(Param.getType()));
440 continue;
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
450 B.CreateRetVoid();
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,
462 bool CtorOrDtor) {
463 const auto *GV =
464 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
465 if (!GV)
466 return;
467 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
468 if (!CA)
469 return;
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))
477 continue;
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"))
500 continue;
501 auto *Token = getConvergenceToken(F.getEntryBlock());
502 Instruction *IP = &*F.getEntryBlock().begin();
503 SmallVector<OperandBundleDef, 1> OB;
504 if (Token) {
505 llvm::Value *bundleArgs[] = {Token};
506 OB.emplace_back("convergencectrl", bundleArgs);
507 IP = Token->getNextNode();
509 IRBuilder<> B(IP);
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>();
535 if (!RBA)
536 return;
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.
543 return;
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);
573 if (!RBA)
574 continue;
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())
617 return nullptr;
619 auto E = BB.end();
620 for (auto I = BB.begin(); I != E; ++I) {
621 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
622 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
623 return II;
626 llvm_unreachable("Convergence token should have been emitted.");
627 return nullptr;