clang 20.0.0git
CGHLSLRuntime.cpp
Go to the documentation of this file.
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"
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
30using namespace clang;
31using namespace CodeGen;
32using namespace clang::hlsl;
33using namespace llvm;
34
35namespace {
36
37void 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}
57void 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//
81void 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
95GlobalVariable *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
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
118llvm::Triple::ArchType CGHLSLRuntime::getArch() {
119 return CGM.getTarget().getTriple().getArch();
120}
121
122void 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.
127 return;
128 }
129
130 auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
131 GV->setExternallyInitialized(true);
132 // Add debug info for constVal.
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
147void 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.
157 }
158 }
159}
160
162 Buffers.emplace_back(Buffer(D));
163 addBufferDecls(D, Buffers.back());
164}
165
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
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
195 : Name(D->getName()), IsCBuffer(D->isCBuffer()),
196 Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
197
198void 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
229static llvm::hlsl::ElementType
230calculateElementType(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
277void 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
313CGHLSLRuntime::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
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
351static 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
363llvm::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
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);
411
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
444 llvm::Function *Fn) {
445 if (FD->isInExportDeclContext()) {
446 const StringRef ExportAttrKindStr = "hlsl.export";
447 Fn->addFnAttr(ExportAttrKindStr);
448 }
449}
450
451static 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
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
479 llvm::Module &M = CGM.getModule();
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();
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
525static bool isResourceRecordType(const clang::Type *Ty) {
527}
528
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 =
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
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
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
605llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
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}
static llvm::hlsl::ElementType calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy)
static void gatherFunctions(SmallVectorImpl< Function * > &Fns, llvm::Module &M, bool CtorOrDtor)
static Value * buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty)
static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD, llvm::GlobalVariable *GV, unsigned Slot, unsigned Space)
static bool isResourceRecordType(const clang::Type *Ty)
const Decl * D
Expr * E
static std::string getName(const CallEvent &Call)
Defines the clang::TargetOptions class.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2489
This class gathers all debug information during compilation and is responsible for emitting to llvm g...
Definition: CGDebugInfo.h:58
llvm::Instruction * getConvergenceToken(llvm::BasicBlock &BB)
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var)
llvm::Type * convertHLSLSpecificType(const Type *T)
llvm::Value * emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D, llvm::Type *Ty)
void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV)
void addBuffer(const HLSLBufferDecl *D)
This class organizes the cross-function state that is used while generating LLVM code.
CGHLSLRuntime & getHLSLRuntime()
Return a reference to the configured HLSL runtime.
llvm::Module & getModule() const
CGDebugInfo * getModuleDebugInfo()
void AddCXXGlobalInit(llvm::Function *F)
const TargetInfo & getTarget() const
void EmitGlobal(GlobalDecl D)
Emit code for a single global function or var decl.
bool shouldEmitConvergenceTokens() const
ASTContext & getContext() const
llvm::Constant * GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty=nullptr, ForDefinition_t IsForDefinition=NotForDefinition)
Return the llvm::Constant for the address of the given global variable.
const TargetCodeGenInfo & getTargetCodeGenInfo()
const CodeGenOptions & getCodeGenOpts() const
llvm::LLVMContext & getLLVMContext()
llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys={})
void EmitTopLevelDecl(Decl *D)
Emit code for a single top level declaration.
virtual llvm::Type * getHLSLType(CodeGenModule &CGM, const Type *T) const
Return an LLVM type that corresponds to a HLSL type.
Definition: TargetInfo.h:442
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1439
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2364
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
T * getAttr() const
Definition: DeclBase.h:576
bool hasAttrs() const
Definition: DeclBase.h:521
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
Definition: DeclBase.cpp:1118
bool hasAttr() const
Definition: DeclBase.h:580
Represents a function declaration or definition.
Definition: Decl.h:1935
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2672
static const HLSLAttributedResourceType * findHandleTypeOnResource(const Type *RT)
Definition: Type.cpp:5431
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition: Decl.h:5026
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:280
Represents a parameter to a function.
Definition: Decl.h:1725
A (possibly-)qualified type.
Definition: Type.h:929
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:7937
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition: TargetInfo.h:311
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1262
Represents a type template specialization; the template must be a class template, a type alias templa...
Definition: Type.h:6667
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
The base class of the type hierarchy.
Definition: Type.h:1828
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1916
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition: Type.cpp:2180
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
Definition: Type.h:8485
bool isHLSLSpecificType() const
Definition: Type.h:8473
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition: Type.cpp:2230
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8741
QualType getType() const
Definition: Decl.h:682
Represents a variable declaration or definition.
Definition: Decl.h:882
Represents a GCC generic vector type.
Definition: Type.h:4035
#define UINT_MAX
Definition: limits.h:64
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:1243
The JSON file list parser is used to communicate input to InstallAPI.
@ SC_Static
Definition: Specifiers.h:252
@ Result
The result type of a method or function.
const FunctionProtoType * T
unsigned long uint64_t
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
std::vector< std::pair< llvm::GlobalVariable *, unsigned > > Constants
llvm::IntegerType * IntTy
int