clang 22.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 "Address.h"
17#include "CGDebugInfo.h"
18#include "CodeGenFunction.h"
19#include "CodeGenModule.h"
20#include "TargetInfo.h"
22#include "clang/AST/Attrs.inc"
23#include "clang/AST/Decl.h"
26#include "clang/AST/Type.h"
29#include "llvm/ADT/SmallString.h"
30#include "llvm/ADT/SmallVector.h"
31#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
32#include "llvm/IR/Constants.h"
33#include "llvm/IR/DerivedTypes.h"
34#include "llvm/IR/GlobalVariable.h"
35#include "llvm/IR/LLVMContext.h"
36#include "llvm/IR/Metadata.h"
37#include "llvm/IR/Module.h"
38#include "llvm/IR/Type.h"
39#include "llvm/IR/Value.h"
40#include "llvm/Support/Alignment.h"
41#include "llvm/Support/ErrorHandling.h"
42#include "llvm/Support/FormatVariadic.h"
43#include <cstdint>
44#include <optional>
45
46using namespace clang;
47using namespace CodeGen;
48using namespace clang::hlsl;
49using namespace llvm;
50
51using llvm::hlsl::CBufferRowSizeInBytes;
52
53namespace {
54
55void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
56 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
57 // Assume ValVersionStr is legal here.
58 VersionTuple Version;
59 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
60 Version.getSubminor() || !Version.getMinor()) {
61 return;
62 }
63
64 uint64_t Major = Version.getMajor();
65 uint64_t Minor = *Version.getMinor();
66
67 auto &Ctx = M.getContext();
68 IRBuilder<> B(M.getContext());
69 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
70 ConstantAsMetadata::get(B.getInt32(Minor))});
71 StringRef DXILValKey = "dx.valver";
72 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
73 DXILValMD->addOperand(Val);
74}
75
76void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
78 llvm::Function *Fn, llvm::Module &M) {
79 auto &Ctx = M.getContext();
80
81 llvm::hlsl::rootsig::MetadataBuilder RSBuilder(Ctx, Elements);
82 MDNode *RootSignature = RSBuilder.BuildRootSignature();
83
84 ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get(
85 llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer)));
86 ValueAsMetadata *EntryFunc = Fn ? ValueAsMetadata::get(Fn) : nullptr;
87 MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version});
88
89 StringRef RootSignatureValKey = "dx.rootsignatures";
90 auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey);
91 RootSignatureValMD->addOperand(MDVals);
92}
93
94// Find array variable declaration from nested array subscript AST nodes
95static const ValueDecl *getArrayDecl(const ArraySubscriptExpr *ASE) {
96 const Expr *E = nullptr;
97 while (ASE != nullptr) {
98 E = ASE->getBase()->IgnoreImpCasts();
99 if (!E)
100 return nullptr;
101 ASE = dyn_cast<ArraySubscriptExpr>(E);
102 }
103 if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
104 return DRE->getDecl();
105 return nullptr;
106}
107
108// Get the total size of the array, or -1 if the array is unbounded.
109static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) {
111 assert(Ty->isArrayType() && "expected array type");
112 if (Ty->isIncompleteArrayType())
113 return -1;
115}
116
117static Value *buildNameForResource(llvm::StringRef BaseName,
118 CodeGenModule &CGM) {
119 llvm::SmallString<64> GlobalName = {BaseName, ".str"};
120 return CGM.GetAddrOfConstantCString(BaseName.str(), GlobalName.c_str())
121 .getPointer();
122}
123
124static CXXMethodDecl *lookupMethod(CXXRecordDecl *Record, StringRef Name,
125 StorageClass SC = SC_None) {
126 for (auto *Method : Record->methods()) {
127 if (Method->getStorageClass() == SC && Method->getName() == Name)
128 return Method;
129 }
130 return nullptr;
131}
132
133static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
134 CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range,
135 llvm::Value *Index, StringRef Name, ResourceBindingAttrs &Binding,
136 CallArgList &Args) {
137 assert(Binding.hasBinding() && "at least one binding attribute expected");
138
139 ASTContext &AST = CGM.getContext();
140 CXXMethodDecl *CreateMethod = nullptr;
141 Value *NameStr = buildNameForResource(Name, CGM);
142 Value *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
143
144 if (Binding.isExplicit()) {
145 // explicit binding
146 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
147 Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
148 const char *Name = Binding.hasCounterImplicitOrderID()
149 ? "__createFromBindingWithImplicitCounter"
150 : "__createFromBinding";
151 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
152 } else {
153 // implicit binding
154 auto *OrderID =
155 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
156 Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
157 const char *Name = Binding.hasCounterImplicitOrderID()
158 ? "__createFromImplicitBindingWithImplicitCounter"
159 : "__createFromImplicitBinding";
160 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
161 }
162 Args.add(RValue::get(Space), AST.UnsignedIntTy);
163 Args.add(RValue::get(Range), AST.IntTy);
164 Args.add(RValue::get(Index), AST.UnsignedIntTy);
165 Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst()));
166 if (Binding.hasCounterImplicitOrderID()) {
167 uint32_t CounterBinding = Binding.getCounterImplicitOrderID();
168 auto *CounterOrderID = llvm::ConstantInt::get(CGM.IntTy, CounterBinding);
169 Args.add(RValue::get(CounterOrderID), AST.UnsignedIntTy);
170 }
171
172 return CreateMethod;
173}
174
175static void callResourceInitMethod(CodeGenFunction &CGF,
176 CXXMethodDecl *CreateMethod,
177 CallArgList &Args, Address ReturnAddress) {
178 llvm::Constant *CalleeFn = CGF.CGM.GetAddrOfFunction(CreateMethod);
179 const FunctionProtoType *Proto =
180 CreateMethod->getType()->getAs<FunctionProtoType>();
181 const CGFunctionInfo &FnInfo =
182 CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, Proto, false);
183 ReturnValueSlot ReturnValue(ReturnAddress, false);
184 CGCallee Callee(CGCalleeInfo(Proto), CalleeFn);
185 CGF.EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr);
186}
187
188// Initializes local resource array variable. For multi-dimensional arrays it
189// calls itself recursively to initialize its sub-arrays. The Index used in the
190// resource constructor calls will begin at StartIndex and will be incremented
191// for each array element. The last used resource Index is returned to the
192// caller. If the function returns std::nullopt, it indicates an error.
193static std::optional<llvm::Value *> initializeLocalResourceArray(
194 CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl,
195 const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot,
196 llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
197 ResourceBindingAttrs &Binding, ArrayRef<llvm::Value *> PrevGEPIndices,
198 SourceLocation ArraySubsExprLoc) {
199
200 ASTContext &AST = CGF.getContext();
201 llvm::IntegerType *IntTy = CGF.CGM.IntTy;
202 llvm::Value *Index = StartIndex;
203 llvm::Value *One = llvm::ConstantInt::get(IntTy, 1);
204 const uint64_t ArraySize = ArrayTy->getSExtSize();
205 QualType ElemType = ArrayTy->getElementType();
206 Address TmpArrayAddr = ValueSlot.getAddress();
207
208 // Add additional index to the getelementptr call indices.
209 // This index will be updated for each array element in the loops below.
210 SmallVector<llvm::Value *> GEPIndices(PrevGEPIndices);
211 GEPIndices.push_back(llvm::ConstantInt::get(IntTy, 0));
212
213 // For array of arrays, recursively initialize the sub-arrays.
214 if (ElemType->isArrayType()) {
215 const ConstantArrayType *SubArrayTy = cast<ConstantArrayType>(ElemType);
216 for (uint64_t I = 0; I < ArraySize; I++) {
217 if (I > 0) {
218 Index = CGF.Builder.CreateAdd(Index, One);
219 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
220 }
221 std::optional<llvm::Value *> MaybeIndex = initializeLocalResourceArray(
222 CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index, ResourceName,
223 Binding, GEPIndices, ArraySubsExprLoc);
224 if (!MaybeIndex)
225 return std::nullopt;
226 Index = *MaybeIndex;
227 }
228 return Index;
229 }
230
231 // For array of resources, initialize each resource in the array.
232 llvm::Type *Ty = CGF.ConvertTypeForMem(ElemType);
233 CharUnits ElemSize = AST.getTypeSizeInChars(ElemType);
234 CharUnits Align =
235 TmpArrayAddr.getAlignment().alignmentOfArrayElement(ElemSize);
236
237 for (uint64_t I = 0; I < ArraySize; I++) {
238 if (I > 0) {
239 Index = CGF.Builder.CreateAdd(Index, One);
240 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
241 }
242 Address ReturnAddress =
243 CGF.Builder.CreateGEP(TmpArrayAddr, GEPIndices, Ty, Align);
244
245 CallArgList Args;
246 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
247 CGF.CGM, ResourceDecl, Range, Index, ResourceName, Binding, Args);
248
249 if (!CreateMethod)
250 // This can happen if someone creates an array of structs that looks like
251 // an HLSL resource record array but it does not have the required static
252 // create method. No binding will be generated for it.
253 return std::nullopt;
254
255 callResourceInitMethod(CGF, CreateMethod, Args, ReturnAddress);
256 }
257 return Index;
258}
259
260} // namespace
261
262llvm::Type *
264 SmallVector<int32_t> *Packoffsets) {
265 assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
266
267 // Check if the target has a specific translation for this type first.
268 if (llvm::Type *TargetTy =
269 CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, Packoffsets))
270 return TargetTy;
271
272 llvm_unreachable("Generic handling of HLSL types is not supported.");
273}
274
275llvm::Triple::ArchType CGHLSLRuntime::getArch() {
276 return CGM.getTarget().getTriple().getArch();
277}
278
279// Emits constant global variables for buffer constants declarations
280// and creates metadata linking the constant globals with the buffer global.
281void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
282 llvm::GlobalVariable *BufGV) {
283 LLVMContext &Ctx = CGM.getLLVMContext();
284
285 // get the layout struct from constant buffer target type
286 llvm::Type *BufType = BufGV->getValueType();
287 llvm::Type *BufLayoutType =
288 cast<llvm::TargetExtType>(BufType)->getTypeParameter(0);
289 llvm::StructType *LayoutStruct = cast<llvm::StructType>(
290 cast<llvm::TargetExtType>(BufLayoutType)->getTypeParameter(0));
291
292 // Start metadata list associating the buffer global variable with its
293 // constatns
295 BufGlobals.push_back(ValueAsMetadata::get(BufGV));
296
297 const auto *ElemIt = LayoutStruct->element_begin();
298 for (Decl *D : BufDecl->buffer_decls()) {
300 // Nothing to do for this declaration.
301 continue;
302 if (isa<FunctionDecl>(D)) {
303 // A function within an cbuffer is effectively a top-level function.
305 continue;
306 }
307 VarDecl *VD = dyn_cast<VarDecl>(D);
308 if (!VD)
309 continue;
310
311 QualType VDTy = VD->getType();
313 if (VD->getStorageClass() == SC_Static ||
316 // Emit static and groupshared variables and resource classes inside
317 // cbuffer as regular globals
318 CGM.EmitGlobal(VD);
319 } else {
320 // Anything else that is not in the hlsl_constant address space must be
321 // an empty struct or a zero-sized array and can be ignored
322 assert(BufDecl->getASTContext().getTypeSize(VDTy) == 0 &&
323 "constant buffer decl with non-zero sized type outside of "
324 "hlsl_constant address space");
325 }
326 continue;
327 }
328
329 assert(ElemIt != LayoutStruct->element_end() &&
330 "number of elements in layout struct does not match");
331 llvm::Type *LayoutType = *ElemIt++;
332
333 // FIXME: handle resources inside user defined structs
334 // (llvm/wg-hlsl#175)
335
336 // create global variable for the constant and to metadata list
337 GlobalVariable *ElemGV =
338 cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
339 BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
340 }
341 assert(ElemIt == LayoutStruct->element_end() &&
342 "number of elements in layout struct does not match");
343
344 // add buffer metadata to the module
345 CGM.getModule()
346 .getOrInsertNamedMetadata("hlsl.cbs")
347 ->addOperand(MDNode::get(Ctx, BufGlobals));
348}
349
350// Creates resource handle type for the HLSL buffer declaration
351static const clang::HLSLAttributedResourceType *
353 ASTContext &AST = BufDecl->getASTContext();
355 AST.HLSLResourceTy, AST.getCanonicalTagType(BufDecl->getLayoutStruct()),
356 HLSLAttributedResourceType::Attributes(ResourceClass::CBuffer));
358}
359
360// Iterates over all declarations in the HLSL buffer and based on the
361// packoffset or register(c#) annotations it fills outs the Layout
362// vector with the user-specified layout offsets.
363// The buffer offsets can be specified 2 ways:
364// 1. declarations in cbuffer {} block can have a packoffset annotation
365// (translates to HLSLPackOffsetAttr)
366// 2. default constant buffer declarations at global scope can have
367// register(c#) annotations (translates to HLSLResourceBindingAttr with
368// RegisterType::C)
369// It is not guaranteed that all declarations in a buffer have an annotation.
370// For those where it is not specified a -1 value is added to the Layout
371// vector. In the final layout these declarations will be placed at the end
372// of the HLSL buffer after all of the elements with specified offset.
373static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl,
374 SmallVector<int32_t> &Layout) {
375 assert(Layout.empty() && "expected empty vector for layout");
376 assert(BufDecl->hasValidPackoffset());
377
378 for (Decl *D : BufDecl->buffer_decls()) {
380 continue;
381 }
382 VarDecl *VD = dyn_cast<VarDecl>(D);
383 if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
384 continue;
385
386 if (!VD->hasAttrs()) {
387 Layout.push_back(-1);
388 continue;
389 }
390
391 int32_t Offset = -1;
392 for (auto *Attr : VD->getAttrs()) {
393 if (auto *POA = dyn_cast<HLSLPackOffsetAttr>(Attr)) {
394 Offset = POA->getOffsetInBytes();
395 break;
396 }
397 auto *RBA = dyn_cast<HLSLResourceBindingAttr>(Attr);
398 if (RBA &&
399 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
400 Offset = RBA->getSlotNumber() * CBufferRowSizeInBytes;
401 break;
402 }
403 }
404 Layout.push_back(Offset);
405 }
406}
407
408// Codegen for HLSLBufferDecl
410
411 assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
412
413 // create resource handle type for the buffer
414 const clang::HLSLAttributedResourceType *ResHandleTy =
415 createBufferHandleType(BufDecl);
416
417 // empty constant buffer is ignored
418 if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
419 return;
420
421 // create global variable for the constant buffer
423 if (BufDecl->hasValidPackoffset())
424 fillPackoffsetLayout(BufDecl, Layout);
425
426 llvm::TargetExtType *TargetTy =
428 ResHandleTy, BufDecl->hasValidPackoffset() ? &Layout : nullptr));
429 llvm::GlobalVariable *BufGV = new GlobalVariable(
430 TargetTy, /*isConstant*/ false,
431 GlobalValue::LinkageTypes::ExternalLinkage, PoisonValue::get(TargetTy),
432 llvm::formatv("{0}{1}", BufDecl->getName(),
433 BufDecl->isCBuffer() ? ".cb" : ".tb"),
434 GlobalValue::NotThreadLocal);
435 CGM.getModule().insertGlobalVariable(BufGV);
436
437 // Add globals for constant buffer elements and create metadata nodes
438 emitBufferGlobalsAndMetadata(BufDecl, BufGV);
439
440 // Initialize cbuffer from binding (implicit or explicit)
441 initializeBufferFromBinding(BufDecl, BufGV);
442}
443
445 const HLSLRootSignatureDecl *SignatureDecl) {
446 llvm::Module &M = CGM.getModule();
447 Triple T(M.getTargetTriple());
448
449 // Generated later with the function decl if not targeting root signature
450 if (T.getEnvironment() != Triple::EnvironmentType::RootSignature)
451 return;
452
453 addRootSignatureMD(SignatureDecl->getVersion(),
454 SignatureDecl->getRootElements(), nullptr, M);
455}
456
457llvm::TargetExtType *
458CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
459 const auto Entry = LayoutTypes.find(StructType);
460 if (Entry != LayoutTypes.end())
461 return Entry->getSecond();
462 return nullptr;
463}
464
465void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
466 llvm::TargetExtType *LayoutTy) {
467 assert(getHLSLBufferLayoutType(StructType) == nullptr &&
468 "layout type for this struct already exist");
469 LayoutTypes[StructType] = LayoutTy;
470}
471
473 auto &TargetOpts = CGM.getTarget().getTargetOpts();
474 auto &CodeGenOpts = CGM.getCodeGenOpts();
475 auto &LangOpts = CGM.getLangOpts();
476 llvm::Module &M = CGM.getModule();
477 Triple T(M.getTargetTriple());
478 if (T.getArch() == Triple::ArchType::dxil)
479 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
480 if (CodeGenOpts.ResMayAlias)
481 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.resmayalias", 1);
482
483 // NativeHalfType corresponds to the -fnative-half-type clang option which is
484 // aliased by clang-dxc's -enable-16bit-types option. This option is used to
485 // set the UseNativeLowPrecision DXIL module flag in the DirectX backend
486 if (LangOpts.NativeHalfType)
487 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.nativelowprec",
488 1);
489
491}
492
494 const FunctionDecl *FD, llvm::Function *Fn) {
495 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
496 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
497 const StringRef ShaderAttrKindStr = "hlsl.shader";
498 Fn->addFnAttr(ShaderAttrKindStr,
499 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
500 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
501 const StringRef NumThreadsKindStr = "hlsl.numthreads";
502 std::string NumThreadsStr =
503 formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
504 NumThreadsAttr->getZ());
505 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
506 }
507 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->getAttr<HLSLWaveSizeAttr>()) {
508 const StringRef WaveSizeKindStr = "hlsl.wavesize";
509 std::string WaveSizeStr =
510 formatv("{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
511 WaveSizeAttr->getPreferred());
512 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
513 }
514 // HLSL entry functions are materialized for module functions with
515 // HLSLShaderAttr attribute. SetLLVMFunctionAttributesForDefinition called
516 // later in the compiler-flow for such module functions is not aware of and
517 // hence not able to set attributes of the newly materialized entry functions.
518 // So, set attributes of entry function here, as appropriate.
519 if (CGM.getCodeGenOpts().OptimizationLevel == 0)
520 Fn->addFnAttr(llvm::Attribute::OptimizeNone);
521 Fn->addFnAttr(llvm::Attribute::NoInline);
522}
523
524static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
525 if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
526 Value *Result = PoisonValue::get(Ty);
527 for (unsigned I = 0; I < VT->getNumElements(); ++I) {
528 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
529 Result = B.CreateInsertElement(Result, Elt, I);
530 }
531 return Result;
532 }
533 return B.CreateCall(F, {B.getInt32(0)});
534}
535
536static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV,
537 unsigned BuiltIn) {
538 LLVMContext &Ctx = GV->getContext();
539 IRBuilder<> B(GV->getContext());
540 MDNode *Operands = MDNode::get(
541 Ctx,
542 {ConstantAsMetadata::get(B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)),
543 ConstantAsMetadata::get(B.getInt32(BuiltIn))});
544 MDNode *Decoration = MDNode::get(Ctx, {Operands});
545 GV->addMetadata("spirv.Decorations", *Decoration);
546}
547
548static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
549 llvm::Type *Ty, const Twine &Name,
550 unsigned BuiltInID) {
551 auto *GV = new llvm::GlobalVariable(
552 M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
553 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
554 llvm::GlobalVariable::GeneralDynamicTLSModel,
555 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
556 addSPIRVBuiltinDecoration(GV, BuiltInID);
557 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
558 return B.CreateLoad(Ty, GV);
559}
560
561llvm::Value *
562CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
564 SemanticInfo &ActiveSemantic) {
565 if (isa<HLSLSV_GroupIndexAttr>(ActiveSemantic.Semantic)) {
566 llvm::Function *GroupIndex =
567 CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
568 return B.CreateCall(FunctionCallee(GroupIndex));
569 }
570
571 if (isa<HLSLSV_DispatchThreadIDAttr>(ActiveSemantic.Semantic)) {
572 llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
573 llvm::Function *ThreadIDIntrinsic =
574 llvm::Intrinsic::isOverloaded(IntrinID)
575 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
576 : CGM.getIntrinsic(IntrinID);
577 return buildVectorInput(B, ThreadIDIntrinsic, Type);
578 }
579
580 if (isa<HLSLSV_GroupThreadIDAttr>(ActiveSemantic.Semantic)) {
581 llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
582 llvm::Function *GroupThreadIDIntrinsic =
583 llvm::Intrinsic::isOverloaded(IntrinID)
584 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
585 : CGM.getIntrinsic(IntrinID);
586 return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
587 }
588
589 if (isa<HLSLSV_GroupIDAttr>(ActiveSemantic.Semantic)) {
590 llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
591 llvm::Function *GroupIDIntrinsic =
592 llvm::Intrinsic::isOverloaded(IntrinID)
593 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
594 : CGM.getIntrinsic(IntrinID);
595 return buildVectorInput(B, GroupIDIntrinsic, Type);
596 }
597
598 if (HLSLSV_PositionAttr *S =
599 dyn_cast<HLSLSV_PositionAttr>(ActiveSemantic.Semantic)) {
600 if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
601 return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
602 S->getAttrName()->getName(),
603 /* BuiltIn::FragCoord */ 15);
604 }
605
606 llvm_unreachable("non-handled system semantic. FIXME.");
607}
608
609llvm::Value *
612 SemanticInfo &ActiveSemantic) {
613
614 if (!ActiveSemantic.Semantic) {
615 ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
616 if (!ActiveSemantic.Semantic) {
617 CGM.getDiags().Report(Decl->getInnerLocStart(),
618 diag::err_hlsl_semantic_missing);
619 return nullptr;
620 }
621 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
622 }
623
624 return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic);
625}
626
627llvm::Value *
628CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
630 SemanticInfo &ActiveSemantic) {
631 assert(!Type->isStructTy());
632 return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic);
633}
634
636 llvm::Function *Fn) {
637 llvm::Module &M = CGM.getModule();
638 llvm::LLVMContext &Ctx = M.getContext();
639 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
640 Function *EntryFn =
641 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
642
643 // Copy function attributes over, we have no argument or return attributes
644 // that can be valid on the real entry.
645 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
646 Fn->getAttributes().getFnAttrs());
647 EntryFn->setAttributes(NewAttrs);
648 setHLSLEntryAttributes(FD, EntryFn);
649
650 // Set the called function as internal linkage.
651 Fn->setLinkage(GlobalValue::InternalLinkage);
652
653 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
654 IRBuilder<> B(BB);
656
658 if (CGM.shouldEmitConvergenceTokens()) {
659 assert(EntryFn->isConvergent());
660 llvm::Value *I =
661 B.CreateIntrinsic(llvm::Intrinsic::experimental_convergence_entry, {});
662 llvm::Value *bundleArgs[] = {I};
663 OB.emplace_back("convergencectrl", bundleArgs);
664 }
665
666 // FIXME: support struct parameters where semantics are on members.
667 // See: https://github.com/llvm/llvm-project/issues/57874
668 unsigned SRetOffset = 0;
669 for (const auto &Param : Fn->args()) {
670 if (Param.hasStructRetAttr()) {
671 // FIXME: support output.
672 // See: https://github.com/llvm/llvm-project/issues/57874
673 SRetOffset = 1;
674 Args.emplace_back(PoisonValue::get(Param.getType()));
675 continue;
676 }
677
678 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
679 SemanticInfo ActiveSemantic = {nullptr, 0};
680 Args.push_back(handleSemanticLoad(B, Param.getType(), PD, ActiveSemantic));
681 }
682
683 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
684 CI->setCallingConv(Fn->getCallingConv());
685 // FIXME: Handle codegen for return type semantics.
686 // See: https://github.com/llvm/llvm-project/issues/57875
687 B.CreateRetVoid();
688
689 // Add and identify root signature to function, if applicable
690 for (const Attr *Attr : FD->getAttrs()) {
691 if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) {
692 auto *RSDecl = RSAttr->getSignatureDecl();
693 addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
694 EntryFn, M);
695 }
696 }
697}
698
699static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
700 bool CtorOrDtor) {
701 const auto *GV =
702 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
703 if (!GV)
704 return;
705 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
706 if (!CA)
707 return;
708 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
709 // HLSL neither supports priorities or COMDat values, so we will check those
710 // in an assert but not handle them.
711
712 for (const auto &Ctor : CA->operands()) {
714 continue;
715 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
716
717 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
718 "HLSL doesn't support setting priority for global ctors.");
719 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
720 "HLSL doesn't support COMDat for global ctors.");
721 Fns.push_back(cast<Function>(CS->getOperand(1)));
722 }
723}
724
726 llvm::Module &M = CGM.getModule();
729 gatherFunctions(CtorFns, M, true);
730 gatherFunctions(DtorFns, M, false);
731
732 // Insert a call to the global constructor at the beginning of the entry block
733 // to externally exported functions. This is a bit of a hack, but HLSL allows
734 // global constructors, but doesn't support driver initialization of globals.
735 for (auto &F : M.functions()) {
736 if (!F.hasFnAttribute("hlsl.shader"))
737 continue;
738 auto *Token = getConvergenceToken(F.getEntryBlock());
739 Instruction *IP = &*F.getEntryBlock().begin();
741 if (Token) {
742 llvm::Value *bundleArgs[] = {Token};
743 OB.emplace_back("convergencectrl", bundleArgs);
744 IP = Token->getNextNode();
745 }
746 IRBuilder<> B(IP);
747 for (auto *Fn : CtorFns) {
748 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
749 CI->setCallingConv(Fn->getCallingConv());
750 }
751
752 // Insert global dtors before the terminator of the last instruction
753 B.SetInsertPoint(F.back().getTerminator());
754 for (auto *Fn : DtorFns) {
755 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
756 CI->setCallingConv(Fn->getCallingConv());
757 }
758 }
759
760 // No need to keep global ctors/dtors for non-lib profile after call to
761 // ctors/dtors added for entry.
762 Triple T(M.getTargetTriple());
763 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
764 if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
765 GV->eraseFromParent();
766 if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
767 GV->eraseFromParent();
768 }
769}
770
771static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
772 Intrinsic::ID IntrID,
774
775 LLVMContext &Ctx = CGM.getLLVMContext();
776 llvm::Function *InitResFunc = llvm::Function::Create(
777 llvm::FunctionType::get(CGM.VoidTy, false),
778 llvm::GlobalValue::InternalLinkage,
779 ("_init_buffer_" + GV->getName()).str(), CGM.getModule());
780 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
781
782 llvm::BasicBlock *EntryBB =
783 llvm::BasicBlock::Create(Ctx, "entry", InitResFunc);
784 CGBuilderTy Builder(CGM, Ctx);
785 const DataLayout &DL = CGM.getModule().getDataLayout();
786 Builder.SetInsertPoint(EntryBB);
787
788 // Make sure the global variable is buffer resource handle
789 llvm::Type *HandleTy = GV->getValueType();
790 assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");
791
792 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
793 /*ReturnType=*/HandleTy, IntrID, Args, nullptr,
794 Twine(GV->getName()).concat("_h"));
795
796 llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
797 Builder.CreateAlignedStore(CreateHandle, HandleRef,
798 HandleRef->getPointerAlignment(DL));
799 Builder.CreateRetVoid();
800
801 CGM.AddCXXGlobalInit(InitResFunc);
802}
803
804void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
805 llvm::GlobalVariable *GV) {
806 ResourceBindingAttrs Binding(BufDecl);
807 assert(Binding.hasBinding() &&
808 "cbuffer/tbuffer should always have resource binding attribute");
809
810 auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
811 auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
812 auto *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
813 Value *Name = buildNameForResource(BufDecl->getName(), CGM);
814
815 // buffer with explicit binding
816 if (Binding.isExplicit()) {
817 llvm::Intrinsic::ID IntrinsicID =
818 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
819 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
820 SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
821 initializeBuffer(CGM, GV, IntrinsicID, Args);
822 } else {
823 // buffer with implicit binding
824 llvm::Intrinsic::ID IntrinsicID =
825 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
826 auto *OrderID =
827 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
828 SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
829 initializeBuffer(CGM, GV, IntrinsicID, Args);
830 }
831}
832
834 llvm::GlobalVariable *GV) {
835 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
836 addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
837}
838
839llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
840 if (!CGM.shouldEmitConvergenceTokens())
841 return nullptr;
842
843 auto E = BB.end();
844 for (auto I = BB.begin(); I != E; ++I) {
845 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
846 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
847 return II;
848 }
849 }
850 llvm_unreachable("Convergence token should have been emitted.");
851 return nullptr;
852}
853
854class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
855public:
859
861 // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
862 // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
863 // traversal, the temporary containing the copy out will not have
864 // been created yet.
865 return false;
866 }
867
869 // Traverse the source expression first.
870 if (E->getSourceExpr())
872
873 // Then add this OVE if we haven't seen it before.
874 if (Visited.insert(E).second)
875 OVEs.push_back(E);
876
877 return true;
878 }
879};
880
882 InitListExpr *E) {
883
884 typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
885 OpaqueValueVisitor Visitor;
886 Visitor.TraverseStmt(E);
887 for (auto *OVE : Visitor.OVEs) {
888 if (CGF.isOpaqueValueEmitted(OVE))
889 continue;
890 if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
891 LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
892 OpaqueValueMappingData::bind(CGF, OVE, LV);
893 } else {
894 RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
895 OpaqueValueMappingData::bind(CGF, OVE, RV);
896 }
897 }
898}
899
901 const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
902 assert((ArraySubsExpr->getType()->isHLSLResourceRecord() ||
903 ArraySubsExpr->getType()->isHLSLResourceRecordArray()) &&
904 "expected resource array subscript expression");
905
906 // Let clang codegen handle local resource array subscripts,
907 // or when the subscript references on opaque expression (as part of
908 // ArrayInitLoopExpr AST node).
909 const VarDecl *ArrayDecl =
910 dyn_cast_or_null<VarDecl>(getArrayDecl(ArraySubsExpr));
911 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage())
912 return std::nullopt;
913
914 // get the resource array type
915 ASTContext &AST = ArrayDecl->getASTContext();
916 const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
917 assert(ResArrayTy->isHLSLResourceRecordArray() &&
918 "expected array of resource classes");
919
920 // Iterate through all nested array subscript expressions to calculate
921 // the index in the flattened resource array (if this is a multi-
922 // dimensional array). The index is calculated as a sum of all indices
923 // multiplied by the total size of the array at that level.
924 Value *Index = nullptr;
925 const ArraySubscriptExpr *ASE = ArraySubsExpr;
926 while (ASE != nullptr) {
927 Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
928 if (const auto *ArrayTy =
929 dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
930 Value *Multiplier = llvm::ConstantInt::get(
931 CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy));
932 SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
933 }
934 Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
935 ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
936 }
937
938 // Find binding info for the resource array. For implicit binding
939 // an HLSLResourceBindingAttr should have been added by SemaHLSL.
940 ResourceBindingAttrs Binding(ArrayDecl);
941 assert((Binding.hasBinding()) &&
942 "resource array must have a binding attribute");
943
944 // Find the individual resource type.
945 QualType ResultTy = ArraySubsExpr->getType();
946 QualType ResourceTy =
947 ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy;
948
949 // Create a temporary variable for the result, which is either going
950 // to be a single resource instance or a local array of resources (we need to
951 // return an LValue).
952 RawAddress TmpVar = CGF.CreateMemTemp(ResultTy);
953 if (CGF.EmitLifetimeStart(TmpVar.getPointer()))
955 NormalEHLifetimeMarker, TmpVar);
956
961
962 // Calculate total array size (= range size).
963 llvm::Value *Range =
964 llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(AST, ResArrayTy));
965
966 // If the result of the subscript operation is a single resource, call the
967 // constructor.
968 if (ResultTy == ResourceTy) {
969 CallArgList Args;
970 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
971 CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
972 ArrayDecl->getName(), Binding, Args);
973
974 if (!CreateMethod)
975 // This can happen if someone creates an array of structs that looks like
976 // an HLSL resource record array but it does not have the required static
977 // create method. No binding will be generated for it.
978 return std::nullopt;
979
980 callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
981
982 } else {
983 // The result of the subscript operation is a local resource array which
984 // needs to be initialized.
985 const ConstantArrayType *ArrayTy =
987 std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
988 CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
989 ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)},
990 ArraySubsExpr->getExprLoc());
991 if (!EndIndex)
992 return std::nullopt;
993 }
994 return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
995}
Defines the clang::ASTContext interface.
static llvm::Value * createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, unsigned BuiltInID)
static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl, SmallVector< int32_t > &Layout)
static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, unsigned BuiltIn)
static void gatherFunctions(SmallVectorImpl< Function * > &Fns, llvm::Module &M, bool CtorOrDtor)
static Value * buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty)
static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV, Intrinsic::ID IntrID, ArrayRef< llvm::Value * > Args)
static const clang::HLSLAttributedResourceType * createBufferHandleType(const HLSLBufferDecl *BufDecl)
llvm::MachO::Record Record
Definition MachO.h:31
Defines the clang::TargetOptions class.
C Language Family Type Representation.
bool VisitHLSLOutArgExpr(HLSLOutArgExpr *)
llvm::SmallVector< OpaqueValueExpr *, 8 > OVEs
bool VisitOpaqueValueExpr(OpaqueValueExpr *E)
llvm::SmallPtrSet< OpaqueValueExpr *, 8 > Visited
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CanQualType CharTy
CanQualType IntTy
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedIntTy
QualType getHLSLAttributedResourceType(QualType Wrapped, QualType Contained, const HLSLAttributedResourceType::Attributes &Attrs)
uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const
Return number of constant array elements.
CanQualType getCanonicalTagType(const TagDecl *TD) const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition Expr.h:2721
SourceLocation getExprLoc() const LLVM_READONLY
Definition Expr.h:2776
QualType getElementType() const
Definition TypeBase.h:3734
Attr - This represents one attribute.
Definition Attr.h:44
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2129
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
QualType withConst() const
Retrieves a version of this type with const applied.
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
CharUnits alignmentOfArrayElement(CharUnits elementSize) const
Given that this is the alignment of the first element of an array, return the minimum alignment of an...
Definition CharUnits.h:214
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
Definition Address.h:128
CharUnits getAlignment() const
Definition Address.h:194
An aggregate value slot.
Definition CGValue.h:504
Address getAddress() const
Definition CGValue.h:644
static AggValueSlot forAddr(Address addr, Qualifiers quals, IsDestructed_t isDestructed, NeedsGCBarriers_t needsGC, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed, IsSanitizerChecked_t isChecked=IsNotSanitizerChecked)
forAddr - Make a slot for an aggregate value.
Definition CGValue.h:587
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Definition CGBuilder.h:296
Abstract information about a function or function prototype.
Definition CGCall.h:41
All available information about a concrete callee.
Definition CGCall.h:63
CGFunctionInfo - Class to encapsulate the information about a function definition.
llvm::Instruction * getConvergenceToken(llvm::BasicBlock &BB)
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
llvm::Value * handleScalarSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, SemanticInfo &ActiveSemantic)
llvm::Value * emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, SemanticInfo &ActiveSemantic)
void addHLSLBufferLayoutType(const RecordType *LayoutStructTy, llvm::TargetExtType *LayoutTy)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var)
llvm::TargetExtType * getHLSLBufferLayoutType(const RecordType *LayoutStructTy)
llvm::Type * convertHLSLSpecificType(const Type *T, SmallVector< int32_t > *Packoffsets=nullptr)
llvm::Value * handleSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, SemanticInfo &ActiveSemantic)
std::optional< LValue > emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF)
void addRootSignature(const HLSLRootSignatureDecl *D)
void addBuffer(const HLSLBufferDecl *D)
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E)
CallArgList - Type for representing both the value and type of arguments in a call.
Definition CGCall.h:274
void add(RValue rvalue, QualType type)
Definition CGCall.h:302
A non-RAII class containing all the information about a bound opaque value.
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
void pushFullExprCleanup(CleanupKind kind, As... A)
pushFullExprCleanup - Push a cleanup to be run at the end of the current full-expression.
bool EmitLifetimeStart(llvm::Value *Addr)
Emit a lifetime.begin marker if some criteria are satisfied.
Definition CGDecl.cpp:1356
RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, llvm::CallBase **CallOrInvoke, bool IsMustTail, SourceLocation Loc, bool IsVirtualFunctionPointerThunk=false)
EmitCall - Generate a call of the given function, expecting the given result type,...
Definition CGCall.cpp:5233
RValue EmitAnyExpr(const Expr *E, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
EmitAnyExpr - Emit code to compute the specified expression which can have any type.
Definition CGExpr.cpp:265
llvm::Type * ConvertTypeForMem(QualType T)
RawAddress CreateMemTemp(QualType T, const Twine &Name="tmp", RawAddress *Alloca=nullptr)
CreateMemTemp - Create a temporary memory object of the given type, with appropriate alignmen and cas...
Definition CGExpr.cpp:187
llvm::Value * EmitScalarExpr(const Expr *E, bool IgnoreResultAssign=false)
EmitScalarExpr - Emit the computation of the specified expression of LLVM scalar type,...
LValue MakeAddrLValue(Address Addr, QualType T, AlignmentSource Source=AlignmentSource::Type)
LValue EmitLValue(const Expr *E, KnownNonNull_t IsKnownNonNull=NotKnownNonNull)
EmitLValue - Emit code to compute a designator that specifies the location of the expression.
Definition CGExpr.cpp:1822
bool isOpaqueValueEmitted(const OpaqueValueExpr *E)
isOpaqueValueEmitted - Return true if the opaque value expression has already been emitted.
Definition CGExpr.cpp:6091
This class organizes the cross-function state that is used while generating LLVM code.
llvm::Module & getModule() const
llvm::Constant * GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty=nullptr, bool ForVTable=false, bool DontDefer=false, ForDefinition_t IsForDefinition=NotForDefinition)
Return the address of the given function.
void AddCXXGlobalInit(llvm::Function *F)
const TargetInfo & getTarget() const
void EmitGlobal(GlobalDecl D)
Emit code for a single global function or var decl.
ASTContext & getContext() const
llvm::LLVMContext & getLLVMContext()
void EmitTopLevelDecl(Decl *D)
Emit code for a single top level declaration.
ConstantAddress GetAddrOfConstantCString(const std::string &Str, StringRef GlobalName=".str")
Returns a pointer to a character array containing the literal and a terminating '\0' character.
const CGFunctionInfo & arrangeFreeFunctionCall(const CallArgList &Args, const FunctionType *Ty, bool ChainCall)
Figure out the rules for calling a function with the given formal type using the given arguments.
Definition CGCall.cpp:699
llvm::Constant * getPointer() const
Definition Address.h:308
LValue - This represents an lvalue references.
Definition CGValue.h:182
RValue - This trivial value class is used to represent the result of an expression that is evaluated.
Definition CGValue.h:42
static RValue get(llvm::Value *V)
Definition CGValue.h:98
An abstract representation of an aligned address.
Definition Address.h:42
llvm::Value * getPointer() const
Definition Address.h:66
ReturnValueSlot - Contains the address where the return value of a function can be stored,...
Definition CGCall.h:379
Represents the canonical version of C arrays with a specified constant size.
Definition TypeBase.h:3760
int64_t getSExtSize() const
Return the size sign-extended as a uint64_t.
Definition TypeBase.h:3842
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1270
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:573
bool hasAttrs() const
Definition DeclBase.h:518
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:524
AttrVec & getAttrs()
Definition DeclBase.h:524
Represents a ValueDecl that came out of a declarator.
Definition Decl.h:780
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3085
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3065
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2000
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2797
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5266
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5176
bool isCBuffer() const
Definition Decl.h:5220
const CXXRecordDecl * getLayoutStruct() const
Definition Decl.h:5223
bool hasValidPackoffset() const
Definition Decl.h:5222
buffer_decl_range buffer_decls() const
Definition Decl.h:5251
This class represents temporary values used to represent inout and out arguments in HLSL.
Definition Expr.h:7283
ArrayRef< llvm::hlsl::rootsig::RootElement > getRootElements() const
Definition Decl.h:5293
llvm::dxbc::RootSignatureVersion getVersion() const
Definition Decl.h:5291
unsigned getSemanticIndex() const
Definition Attr.h:260
Describes an C or C++ initializer list.
Definition Expr.h:5233
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition Expr.h:1178
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Definition Expr.h:1228
Represents a parameter to a function.
Definition Decl.h:1790
A (possibly-)qualified type.
Definition TypeBase.h:937
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8290
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8416
The collection of all-type qualifiers we support.
Definition TypeBase.h:331
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Encodes a location in the source.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Token - This structure provides full information about a lexed token.
Definition Token.h:36
The base class of the type hierarchy.
Definition TypeBase.h:1833
bool isIncompleteArrayType() const
Definition TypeBase.h:8634
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isArrayType() const
Definition TypeBase.h:8626
bool isHLSLResourceRecord() const
Definition Type.cpp:5364
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9103
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:653
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5368
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1226
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:1168
@ Type
The l-value was considered opaque, so the alignment was determined from a type.
Definition CGValue.h:154
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Definition CGValue.h:145
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
StorageClass
Storage classes.
Definition Specifiers.h:248
@ SC_Static
Definition Specifiers.h:252
@ SC_None
Definition Specifiers.h:250
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
unsigned getCounterImplicitOrderID() const