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 "CGDebugInfo.h"
17#include "CGRecordLayout.h"
18#include "CodeGenFunction.h"
19#include "CodeGenModule.h"
21#include "TargetInfo.h"
23#include "clang/AST/Attrs.inc"
24#include "clang/AST/Decl.h"
27#include "clang/AST/Type.h"
30#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/ScopeExit.h"
32#include "llvm/ADT/SmallString.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
35#include "llvm/IR/Constants.h"
36#include "llvm/IR/DerivedTypes.h"
37#include "llvm/IR/GlobalVariable.h"
38#include "llvm/IR/LLVMContext.h"
39#include "llvm/IR/Metadata.h"
40#include "llvm/IR/Module.h"
41#include "llvm/IR/Type.h"
42#include "llvm/IR/Value.h"
43#include "llvm/Support/Alignment.h"
44#include "llvm/Support/ErrorHandling.h"
45#include "llvm/Support/FormatVariadic.h"
46#include <cstdint>
47#include <optional>
48
49using namespace clang;
50using namespace CodeGen;
51using namespace clang::hlsl;
52using namespace llvm;
53
54using llvm::hlsl::CBufferRowSizeInBytes;
55
56namespace {
57
58void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
59 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
60 // Assume ValVersionStr is legal here.
61 VersionTuple Version;
62 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
63 Version.getSubminor() || !Version.getMinor()) {
64 return;
65 }
66
67 uint64_t Major = Version.getMajor();
68 uint64_t Minor = *Version.getMinor();
69
70 auto &Ctx = M.getContext();
71 IRBuilder<> B(M.getContext());
72 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
73 ConstantAsMetadata::get(B.getInt32(Minor))});
74 StringRef DXILValKey = "dx.valver";
75 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
76 DXILValMD->addOperand(Val);
77}
78
79void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
81 llvm::Function *Fn, llvm::Module &M) {
82 auto &Ctx = M.getContext();
83
84 llvm::hlsl::rootsig::MetadataBuilder RSBuilder(Ctx, Elements);
85 MDNode *RootSignature = RSBuilder.BuildRootSignature();
86
87 ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get(
88 llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer)));
89 ValueAsMetadata *EntryFunc = Fn ? ValueAsMetadata::get(Fn) : nullptr;
90 MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version});
91
92 StringRef RootSignatureValKey = "dx.rootsignatures";
93 auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey);
94 RootSignatureValMD->addOperand(MDVals);
95}
96
97// Find array variable declaration from nested array subscript AST nodes
98static const ValueDecl *getArrayDecl(const ArraySubscriptExpr *ASE) {
99 const Expr *E = nullptr;
100 while (ASE != nullptr) {
101 E = ASE->getBase()->IgnoreImpCasts();
102 if (!E)
103 return nullptr;
104 ASE = dyn_cast<ArraySubscriptExpr>(E);
105 }
106 if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
107 return DRE->getDecl();
108 return nullptr;
109}
110
111// Get the total size of the array, or -1 if the array is unbounded.
112static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) {
114 assert(Ty->isArrayType() && "expected array type");
115 if (Ty->isIncompleteArrayType())
116 return -1;
118}
119
120static Value *buildNameForResource(llvm::StringRef BaseName,
121 CodeGenModule &CGM) {
122 llvm::SmallString<64> GlobalName = {BaseName, ".str"};
123 return CGM.GetAddrOfConstantCString(BaseName.str(), GlobalName.c_str())
124 .getPointer();
125}
126
127static CXXMethodDecl *lookupMethod(CXXRecordDecl *Record, StringRef Name,
128 StorageClass SC = SC_None) {
129 for (auto *Method : Record->methods()) {
130 if (Method->getStorageClass() == SC && Method->getName() == Name)
131 return Method;
132 }
133 return nullptr;
134}
135
136static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
137 CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range,
138 llvm::Value *Index, StringRef Name, ResourceBindingAttrs &Binding,
139 CallArgList &Args) {
140 assert(Binding.hasBinding() && "at least one binding attribute expected");
141
142 ASTContext &AST = CGM.getContext();
143 CXXMethodDecl *CreateMethod = nullptr;
144 Value *NameStr = buildNameForResource(Name, CGM);
145 Value *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
146
147 if (Binding.isExplicit()) {
148 // explicit binding
149 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
150 Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
151 const char *Name = Binding.hasCounterImplicitOrderID()
152 ? "__createFromBindingWithImplicitCounter"
153 : "__createFromBinding";
154 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
155 } else {
156 // implicit binding
157 auto *OrderID =
158 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
159 Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
160 const char *Name = Binding.hasCounterImplicitOrderID()
161 ? "__createFromImplicitBindingWithImplicitCounter"
162 : "__createFromImplicitBinding";
163 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
164 }
165 Args.add(RValue::get(Space), AST.UnsignedIntTy);
166 Args.add(RValue::get(Range), AST.IntTy);
167 Args.add(RValue::get(Index), AST.UnsignedIntTy);
168 Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst()));
169 if (Binding.hasCounterImplicitOrderID()) {
170 uint32_t CounterBinding = Binding.getCounterImplicitOrderID();
171 auto *CounterOrderID = llvm::ConstantInt::get(CGM.IntTy, CounterBinding);
172 Args.add(RValue::get(CounterOrderID), AST.UnsignedIntTy);
173 }
174
175 return CreateMethod;
176}
177
178static void callResourceInitMethod(CodeGenFunction &CGF,
179 CXXMethodDecl *CreateMethod,
180 CallArgList &Args, Address ReturnAddress) {
181 llvm::Constant *CalleeFn = CGF.CGM.GetAddrOfFunction(CreateMethod);
182 const FunctionProtoType *Proto =
183 CreateMethod->getType()->getAs<FunctionProtoType>();
184 const CGFunctionInfo &FnInfo =
185 CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, Proto, false);
186 ReturnValueSlot ReturnValue(ReturnAddress, false);
187 CGCallee Callee(CGCalleeInfo(Proto), CalleeFn);
188 CGF.EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr);
189}
190
191// Initializes local resource array variable. For multi-dimensional arrays it
192// calls itself recursively to initialize its sub-arrays. The Index used in the
193// resource constructor calls will begin at StartIndex and will be incremented
194// for each array element. The last used resource Index is returned to the
195// caller. If the function returns std::nullopt, it indicates an error.
196static std::optional<llvm::Value *> initializeLocalResourceArray(
197 CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl,
198 const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot,
199 llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
200 ResourceBindingAttrs &Binding, ArrayRef<llvm::Value *> PrevGEPIndices,
201 SourceLocation ArraySubsExprLoc) {
202
203 ASTContext &AST = CGF.getContext();
204 llvm::IntegerType *IntTy = CGF.CGM.IntTy;
205 llvm::Value *Index = StartIndex;
206 llvm::Value *One = llvm::ConstantInt::get(IntTy, 1);
207 const uint64_t ArraySize = ArrayTy->getSExtSize();
208 QualType ElemType = ArrayTy->getElementType();
209 Address TmpArrayAddr = ValueSlot.getAddress();
210
211 // Add additional index to the getelementptr call indices.
212 // This index will be updated for each array element in the loops below.
213 SmallVector<llvm::Value *> GEPIndices(PrevGEPIndices);
214 GEPIndices.push_back(llvm::ConstantInt::get(IntTy, 0));
215
216 // For array of arrays, recursively initialize the sub-arrays.
217 if (ElemType->isArrayType()) {
218 const ConstantArrayType *SubArrayTy = cast<ConstantArrayType>(ElemType);
219 for (uint64_t I = 0; I < ArraySize; I++) {
220 if (I > 0) {
221 Index = CGF.Builder.CreateAdd(Index, One);
222 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
223 }
224 std::optional<llvm::Value *> MaybeIndex = initializeLocalResourceArray(
225 CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index, ResourceName,
226 Binding, GEPIndices, ArraySubsExprLoc);
227 if (!MaybeIndex)
228 return std::nullopt;
229 Index = *MaybeIndex;
230 }
231 return Index;
232 }
233
234 // For array of resources, initialize each resource in the array.
235 llvm::Type *Ty = CGF.ConvertTypeForMem(ElemType);
236 CharUnits ElemSize = AST.getTypeSizeInChars(ElemType);
237 CharUnits Align =
238 TmpArrayAddr.getAlignment().alignmentOfArrayElement(ElemSize);
239
240 for (uint64_t I = 0; I < ArraySize; I++) {
241 if (I > 0) {
242 Index = CGF.Builder.CreateAdd(Index, One);
243 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
244 }
245 Address ReturnAddress =
246 CGF.Builder.CreateGEP(TmpArrayAddr, GEPIndices, Ty, Align);
247
248 CallArgList Args;
249 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
250 CGF.CGM, ResourceDecl, Range, Index, ResourceName, Binding, Args);
251
252 if (!CreateMethod)
253 // This can happen if someone creates an array of structs that looks like
254 // an HLSL resource record array but it does not have the required static
255 // create method. No binding will be generated for it.
256 return std::nullopt;
257
258 callResourceInitMethod(CGF, CreateMethod, Args, ReturnAddress);
259 }
260 return Index;
261}
262
263} // namespace
264
265llvm::Type *
267 const CGHLSLOffsetInfo &OffsetInfo) {
268 assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
269
270 // Check if the target has a specific translation for this type first.
271 if (llvm::Type *TargetTy =
272 CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, OffsetInfo))
273 return TargetTy;
274
275 llvm_unreachable("Generic handling of HLSL types is not supported.");
276}
277
278llvm::Triple::ArchType CGHLSLRuntime::getArch() {
279 return CGM.getTarget().getTriple().getArch();
280}
281
282// Emits constant global variables for buffer constants declarations
283// and creates metadata linking the constant globals with the buffer global.
284void CGHLSLRuntime::emitBufferGlobalsAndMetadata(
285 const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *BufGV,
286 const CGHLSLOffsetInfo &OffsetInfo) {
287 LLVMContext &Ctx = CGM.getLLVMContext();
288
289 // get the layout struct from constant buffer target type
290 llvm::Type *BufType = BufGV->getValueType();
291 llvm::StructType *LayoutStruct = cast<llvm::StructType>(
292 cast<llvm::TargetExtType>(BufType)->getTypeParameter(0));
293
295 size_t OffsetIdx = 0;
296 for (Decl *D : BufDecl->buffer_decls()) {
298 // Nothing to do for this declaration.
299 continue;
300 if (isa<FunctionDecl>(D)) {
301 // A function within an cbuffer is effectively a top-level function.
303 continue;
304 }
305 VarDecl *VD = dyn_cast<VarDecl>(D);
306 if (!VD)
307 continue;
308
309 QualType VDTy = VD->getType();
311 if (VD->getStorageClass() == SC_Static ||
314 // Emit static and groupshared variables and resource classes inside
315 // cbuffer as regular globals
316 CGM.EmitGlobal(VD);
317 } else {
318 // Anything else that is not in the hlsl_constant address space must be
319 // an empty struct or a zero-sized array and can be ignored
320 assert(BufDecl->getASTContext().getTypeSize(VDTy) == 0 &&
321 "constant buffer decl with non-zero sized type outside of "
322 "hlsl_constant address space");
323 }
324 continue;
325 }
326
327 DeclsWithOffset.emplace_back(VD, OffsetInfo[OffsetIdx++]);
328 }
329
330 if (!OffsetInfo.empty())
331 llvm::stable_sort(DeclsWithOffset, [](const auto &LHS, const auto &RHS) {
332 return CGHLSLOffsetInfo::compareOffsets(LHS.second, RHS.second);
333 });
334
335 // Associate the buffer global variable with its constants
336 SmallVector<llvm::Metadata *> BufGlobals;
337 BufGlobals.reserve(DeclsWithOffset.size() + 1);
338 BufGlobals.push_back(ValueAsMetadata::get(BufGV));
339
340 auto ElemIt = LayoutStruct->element_begin();
341 for (auto &[VD, _] : DeclsWithOffset) {
342 if (CGM.getTargetCodeGenInfo().isHLSLPadding(*ElemIt))
343 ++ElemIt;
344
345 assert(ElemIt != LayoutStruct->element_end() &&
346 "number of elements in layout struct does not match");
347 llvm::Type *LayoutType = *ElemIt++;
348
349 GlobalVariable *ElemGV =
350 cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
351 BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
352 }
353 assert(ElemIt == LayoutStruct->element_end() &&
354 "number of elements in layout struct does not match");
355
356 // add buffer metadata to the module
357 CGM.getModule()
358 .getOrInsertNamedMetadata("hlsl.cbs")
359 ->addOperand(MDNode::get(Ctx, BufGlobals));
360}
361
362// Creates resource handle type for the HLSL buffer declaration
363static const clang::HLSLAttributedResourceType *
365 ASTContext &AST = BufDecl->getASTContext();
367 AST.HLSLResourceTy, AST.getCanonicalTagType(BufDecl->getLayoutStruct()),
368 HLSLAttributedResourceType::Attributes(ResourceClass::CBuffer));
370}
371
374
375 // If we don't have packoffset info, just return an empty result.
376 if (!BufDecl.hasValidPackoffset())
377 return Result;
378
379 for (Decl *D : BufDecl.buffer_decls()) {
381 continue;
382 }
383 VarDecl *VD = dyn_cast<VarDecl>(D);
384 if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
385 continue;
386
387 if (!VD->hasAttrs()) {
388 Result.Offsets.push_back(Unspecified);
389 continue;
390 }
391
392 uint32_t Offset = Unspecified;
393 for (auto *Attr : VD->getAttrs()) {
394 if (auto *POA = dyn_cast<HLSLPackOffsetAttr>(Attr)) {
395 Offset = POA->getOffsetInBytes();
396 break;
397 }
398 auto *RBA = dyn_cast<HLSLResourceBindingAttr>(Attr);
399 if (RBA &&
400 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
401 Offset = RBA->getSlotNumber() * CBufferRowSizeInBytes;
402 break;
403 }
404 }
405 Result.Offsets.push_back(Offset);
406 }
407 return Result;
408}
409
410// Codegen for HLSLBufferDecl
412
413 assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
414
415 // create resource handle type for the buffer
416 const clang::HLSLAttributedResourceType *ResHandleTy =
417 createBufferHandleType(BufDecl);
418
419 // empty constant buffer is ignored
420 if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
421 return;
422
423 // create global variable for the constant buffer
424 CGHLSLOffsetInfo OffsetInfo = CGHLSLOffsetInfo::fromDecl(*BufDecl);
425 llvm::Type *LayoutTy = convertHLSLSpecificType(ResHandleTy, OffsetInfo);
426 llvm::GlobalVariable *BufGV = new GlobalVariable(
427 LayoutTy, /*isConstant*/ false,
428 GlobalValue::LinkageTypes::ExternalLinkage, PoisonValue::get(LayoutTy),
429 llvm::formatv("{0}{1}", BufDecl->getName(),
430 BufDecl->isCBuffer() ? ".cb" : ".tb"),
431 GlobalValue::NotThreadLocal);
432 CGM.getModule().insertGlobalVariable(BufGV);
433
434 // Add globals for constant buffer elements and create metadata nodes
435 emitBufferGlobalsAndMetadata(BufDecl, BufGV, OffsetInfo);
436
437 // Initialize cbuffer from binding (implicit or explicit)
438 initializeBufferFromBinding(BufDecl, BufGV);
439}
440
442 const HLSLRootSignatureDecl *SignatureDecl) {
443 llvm::Module &M = CGM.getModule();
444 Triple T(M.getTargetTriple());
445
446 // Generated later with the function decl if not targeting root signature
447 if (T.getEnvironment() != Triple::EnvironmentType::RootSignature)
448 return;
449
450 addRootSignatureMD(SignatureDecl->getVersion(),
451 SignatureDecl->getRootElements(), nullptr, M);
452}
453
454llvm::StructType *
455CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
456 const auto Entry = LayoutTypes.find(StructType);
457 if (Entry != LayoutTypes.end())
458 return Entry->getSecond();
459 return nullptr;
460}
461
462void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
463 llvm::StructType *LayoutTy) {
464 assert(getHLSLBufferLayoutType(StructType) == nullptr &&
465 "layout type for this struct already exist");
466 LayoutTypes[StructType] = LayoutTy;
467}
468
470 auto &TargetOpts = CGM.getTarget().getTargetOpts();
471 auto &CodeGenOpts = CGM.getCodeGenOpts();
472 auto &LangOpts = CGM.getLangOpts();
473 llvm::Module &M = CGM.getModule();
474 Triple T(M.getTargetTriple());
475 if (T.getArch() == Triple::ArchType::dxil)
476 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
477 if (CodeGenOpts.ResMayAlias)
478 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.resmayalias", 1);
479
480 // NativeHalfType corresponds to the -fnative-half-type clang option which is
481 // aliased by clang-dxc's -enable-16bit-types option. This option is used to
482 // set the UseNativeLowPrecision DXIL module flag in the DirectX backend
483 if (LangOpts.NativeHalfType)
484 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.nativelowprec",
485 1);
486
488}
489
491 const FunctionDecl *FD, llvm::Function *Fn) {
492 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
493 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
494 const StringRef ShaderAttrKindStr = "hlsl.shader";
495 Fn->addFnAttr(ShaderAttrKindStr,
496 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
497 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
498 const StringRef NumThreadsKindStr = "hlsl.numthreads";
499 std::string NumThreadsStr =
500 formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
501 NumThreadsAttr->getZ());
502 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
503 }
504 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->getAttr<HLSLWaveSizeAttr>()) {
505 const StringRef WaveSizeKindStr = "hlsl.wavesize";
506 std::string WaveSizeStr =
507 formatv("{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
508 WaveSizeAttr->getPreferred());
509 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
510 }
511 // HLSL entry functions are materialized for module functions with
512 // HLSLShaderAttr attribute. SetLLVMFunctionAttributesForDefinition called
513 // later in the compiler-flow for such module functions is not aware of and
514 // hence not able to set attributes of the newly materialized entry functions.
515 // So, set attributes of entry function here, as appropriate.
516 if (CGM.getCodeGenOpts().OptimizationLevel == 0)
517 Fn->addFnAttr(llvm::Attribute::OptimizeNone);
518 Fn->addFnAttr(llvm::Attribute::NoInline);
519
520 if (CGM.getLangOpts().HLSLSpvEnableMaximalReconvergence) {
521 Fn->addFnAttr("enable-maximal-reconvergence", "true");
522 }
523}
524
525static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
526 if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
527 Value *Result = PoisonValue::get(Ty);
528 for (unsigned I = 0; I < VT->getNumElements(); ++I) {
529 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
530 Result = B.CreateInsertElement(Result, Elt, I);
531 }
532 return Result;
533 }
534 return B.CreateCall(F, {B.getInt32(0)});
535}
536
537static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV,
538 unsigned BuiltIn) {
539 LLVMContext &Ctx = GV->getContext();
540 IRBuilder<> B(GV->getContext());
541 MDNode *Operands = MDNode::get(
542 Ctx,
543 {ConstantAsMetadata::get(B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)),
544 ConstantAsMetadata::get(B.getInt32(BuiltIn))});
545 MDNode *Decoration = MDNode::get(Ctx, {Operands});
546 GV->addMetadata("spirv.Decorations", *Decoration);
547}
548
549static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) {
550 LLVMContext &Ctx = GV->getContext();
551 IRBuilder<> B(GV->getContext());
552 MDNode *Operands =
553 MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)),
554 ConstantAsMetadata::get(B.getInt32(Location))});
555 MDNode *Decoration = MDNode::get(Ctx, {Operands});
556 GV->addMetadata("spirv.Decorations", *Decoration);
557}
558
559static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
560 llvm::Type *Ty, const Twine &Name,
561 unsigned BuiltInID) {
562 auto *GV = new llvm::GlobalVariable(
563 M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
564 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
565 llvm::GlobalVariable::GeneralDynamicTLSModel,
566 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
567 addSPIRVBuiltinDecoration(GV, BuiltInID);
568 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
569 return B.CreateLoad(Ty, GV);
570}
571
572static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M,
573 llvm::Type *Ty, unsigned Location,
574 StringRef Name) {
575 auto *GV = new llvm::GlobalVariable(
576 M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
577 /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
578 llvm::GlobalVariable::GeneralDynamicTLSModel,
579 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
580 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
581 addLocationDecoration(GV, Location);
582 return B.CreateLoad(Ty, GV);
583}
584
585llvm::Value *
586CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
587 HLSLAppliedSemanticAttr *Semantic,
588 std::optional<unsigned> Index) {
589 Twine BaseName = Twine(Semantic->getAttrName()->getName());
590 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
591
592 unsigned Location = SPIRVLastAssignedInputSemanticLocation;
593
594 // DXC completely ignores the semantic/index pair. Location are assigned from
595 // the first semantic to the last.
596 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
597 unsigned ElementCount = AT ? AT->getNumElements() : 1;
598 SPIRVLastAssignedInputSemanticLocation += ElementCount;
599 return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location,
600 VariableName.str());
601}
602
603static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M,
604 llvm::Value *Source, unsigned Location,
605 StringRef Name) {
606 auto *GV = new llvm::GlobalVariable(
607 M, Source->getType(), /* isConstant= */ false,
608 llvm::GlobalValue::ExternalLinkage,
609 /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
610 llvm::GlobalVariable::GeneralDynamicTLSModel,
611 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
612 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
613 addLocationDecoration(GV, Location);
614 B.CreateStore(Source, GV);
615}
616
617void CGHLSLRuntime::emitSPIRVUserSemanticStore(
618 llvm::IRBuilder<> &B, llvm::Value *Source,
619 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
620 Twine BaseName = Twine(Semantic->getAttrName()->getName());
621 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
622 unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
623
624 // DXC completely ignores the semantic/index pair. Location are assigned from
625 // the first semantic to the last.
626 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
627 unsigned ElementCount = AT ? AT->getNumElements() : 1;
628 SPIRVLastAssignedOutputSemanticLocation += ElementCount;
629 createSPIRVLocationStore(B, CGM.getModule(), Source, Location,
630 VariableName.str());
631}
632
633llvm::Value *
634CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
635 HLSLAppliedSemanticAttr *Semantic,
636 std::optional<unsigned> Index) {
637 Twine BaseName = Twine(Semantic->getAttrName()->getName());
638 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
639
640 // DXIL packing rules etc shall be handled here.
641 // FIXME: generate proper sigpoint, index, col, row values.
642 // FIXME: also DXIL loads vectors element by element.
643 SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
644 B.getInt8(0),
645 llvm::PoisonValue::get(B.getInt32Ty())};
646
647 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
648 llvm::Value *Value = B.CreateIntrinsic(/*ReturnType=*/Type, IntrinsicID, Args,
649 nullptr, VariableName);
650 return Value;
651}
652
653void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
654 llvm::Value *Source,
655 HLSLAppliedSemanticAttr *Semantic,
656 std::optional<unsigned> Index) {
657 // DXIL packing rules etc shall be handled here.
658 // FIXME: generate proper sigpoint, index, col, row values.
659 SmallVector<Value *> Args{B.getInt32(4),
660 B.getInt32(0),
661 B.getInt32(0),
662 B.getInt8(0),
663 llvm::PoisonValue::get(B.getInt32Ty()),
664 Source};
665
666 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
667 B.CreateIntrinsic(/*ReturnType=*/CGM.VoidTy, IntrinsicID, Args, nullptr);
668}
669
670llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
671 IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
672 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
673 if (CGM.getTarget().getTriple().isSPIRV())
674 return emitSPIRVUserSemanticLoad(B, Type, Semantic, Index);
675
676 if (CGM.getTarget().getTriple().isDXIL())
677 return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
678
679 llvm_unreachable("Unsupported target for user-semantic load.");
680}
681
682void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
683 const clang::DeclaratorDecl *Decl,
684 HLSLAppliedSemanticAttr *Semantic,
685 std::optional<unsigned> Index) {
686 if (CGM.getTarget().getTriple().isSPIRV())
687 return emitSPIRVUserSemanticStore(B, Source, Semantic, Index);
688
689 if (CGM.getTarget().getTriple().isDXIL())
690 return emitDXILUserSemanticStore(B, Source, Semantic, Index);
691
692 llvm_unreachable("Unsupported target for user-semantic load.");
693}
694
696 IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
697 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
698
699 std::string SemanticName = Semantic->getAttrName()->getName().upper();
700 if (SemanticName == "SV_GROUPINDEX") {
701 llvm::Function *GroupIndex =
702 CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
703 return B.CreateCall(FunctionCallee(GroupIndex));
704 }
705
706 if (SemanticName == "SV_DISPATCHTHREADID") {
707 llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
708 llvm::Function *ThreadIDIntrinsic =
709 llvm::Intrinsic::isOverloaded(IntrinID)
710 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
711 : CGM.getIntrinsic(IntrinID);
712 return buildVectorInput(B, ThreadIDIntrinsic, Type);
713 }
714
715 if (SemanticName == "SV_GROUPTHREADID") {
716 llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
717 llvm::Function *GroupThreadIDIntrinsic =
718 llvm::Intrinsic::isOverloaded(IntrinID)
719 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
720 : CGM.getIntrinsic(IntrinID);
721 return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
722 }
723
724 if (SemanticName == "SV_GROUPID") {
725 llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
726 llvm::Function *GroupIDIntrinsic =
727 llvm::Intrinsic::isOverloaded(IntrinID)
728 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
729 : CGM.getIntrinsic(IntrinID);
730 return buildVectorInput(B, GroupIDIntrinsic, Type);
731 }
732
733 if (SemanticName == "SV_POSITION") {
734 if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
735 return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
736 Semantic->getAttrName()->getName(),
737 /* BuiltIn::FragCoord */ 15);
738 }
739
740 llvm_unreachable("non-handled system semantic. FIXME.");
741}
742
743static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M,
744 llvm::Value *Source, const Twine &Name,
745 unsigned BuiltInID) {
746 auto *GV = new llvm::GlobalVariable(
747 M, Source->getType(), /* isConstant= */ false,
748 llvm::GlobalValue::ExternalLinkage,
749 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
750 llvm::GlobalVariable::GeneralDynamicTLSModel,
751 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
752 addSPIRVBuiltinDecoration(GV, BuiltInID);
753 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
754 B.CreateStore(Source, GV);
755}
756
757void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
759 HLSLAppliedSemanticAttr *Semantic,
760 std::optional<unsigned> Index) {
761
762 std::string SemanticName = Semantic->getAttrName()->getName().upper();
763 if (SemanticName == "SV_POSITION")
764 createSPIRVBuiltinStore(B, CGM.getModule(), Source,
765 Semantic->getAttrName()->getName(),
766 /* BuiltIn::Position */ 0);
767 else
768 llvm_unreachable("non-handled system semantic. FIXME.");
769}
770
772 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
773 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
774
775 std::optional<unsigned> Index = Semantic->getSemanticIndex();
776 if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
777 return emitSystemSemanticLoad(B, Type, Decl, Semantic, Index);
778 return emitUserSemanticLoad(B, Type, Decl, Semantic, Index);
779}
780
782 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
783 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
784 std::optional<unsigned> Index = Semantic->getSemanticIndex();
785 if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
786 emitSystemSemanticStore(B, Source, Decl, Semantic, Index);
787 else
788 emitUserSemanticStore(B, Source, Decl, Semantic, Index);
789}
790
791std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
793 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
797 const llvm::StructType *ST = cast<StructType>(Type);
798 const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();
799
800 assert(std::distance(RD->field_begin(), RD->field_end()) ==
801 ST->getNumElements());
802
803 llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
804 auto FieldDecl = RD->field_begin();
805 for (unsigned I = 0; I < ST->getNumElements(); ++I) {
806 auto [ChildValue, NextAttr] = handleSemanticLoad(
807 B, FD, ST->getElementType(I), *FieldDecl, AttrBegin, AttrEnd);
808 AttrBegin = NextAttr;
809 assert(ChildValue);
810 Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
811 ++FieldDecl;
812 }
813
814 return std::make_pair(Aggregate, AttrBegin);
815}
816
819 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
823
824 const llvm::StructType *ST = cast<StructType>(Source->getType());
825
826 const clang::RecordDecl *RD = nullptr;
827 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
829 else
830 RD = Decl->getType()->getAsRecordDecl();
831 assert(RD);
832
833 assert(std::distance(RD->field_begin(), RD->field_end()) ==
834 ST->getNumElements());
835
836 auto FieldDecl = RD->field_begin();
837 for (unsigned I = 0; I < ST->getNumElements(); ++I) {
838 llvm::Value *Extract = B.CreateExtractValue(Source, I);
839 AttrBegin =
840 handleSemanticStore(B, FD, Extract, *FieldDecl, AttrBegin, AttrEnd);
841 }
842
843 return AttrBegin;
844}
845
846std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
848 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
852 assert(AttrBegin != AttrEnd);
853 if (Type->isStructTy())
854 return handleStructSemanticLoad(B, FD, Type, Decl, AttrBegin, AttrEnd);
855
856 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
857 ++AttrBegin;
858 return std::make_pair(handleScalarSemanticLoad(B, FD, Type, Decl, Attr),
859 AttrBegin);
860}
861
864 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
868 assert(AttrBegin != AttrEnd);
869 if (Source->getType()->isStructTy())
870 return handleStructSemanticStore(B, FD, Source, Decl, AttrBegin, AttrEnd);
871
872 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
873 ++AttrBegin;
874 handleScalarSemanticStore(B, FD, Source, Decl, Attr);
875 return AttrBegin;
876}
877
879 llvm::Function *Fn) {
880 llvm::Module &M = CGM.getModule();
881 llvm::LLVMContext &Ctx = M.getContext();
882 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
883 Function *EntryFn =
884 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
885
886 // Copy function attributes over, we have no argument or return attributes
887 // that can be valid on the real entry.
888 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
889 Fn->getAttributes().getFnAttrs());
890 EntryFn->setAttributes(NewAttrs);
891 setHLSLEntryAttributes(FD, EntryFn);
892
893 // Set the called function as internal linkage.
894 Fn->setLinkage(GlobalValue::InternalLinkage);
895
896 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
897 IRBuilder<> B(BB);
899
901 if (CGM.shouldEmitConvergenceTokens()) {
902 assert(EntryFn->isConvergent());
903 llvm::Value *I =
904 B.CreateIntrinsic(llvm::Intrinsic::experimental_convergence_entry, {});
905 llvm::Value *bundleArgs[] = {I};
906 OB.emplace_back("convergencectrl", bundleArgs);
907 }
908
909 llvm::DenseMap<const DeclaratorDecl *, llvm::Value *> OutputSemantic;
910
911 unsigned SRetOffset = 0;
912 for (const auto &Param : Fn->args()) {
913 if (Param.hasStructRetAttr()) {
914 SRetOffset = 1;
915 llvm::Type *VarType = Param.getParamStructRetType();
916 llvm::Value *Var = B.CreateAlloca(VarType);
917 OutputSemantic.try_emplace(FD, Var);
918 Args.push_back(Var);
919 continue;
920 }
921
922 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
923 llvm::Value *SemanticValue = nullptr;
924 // FIXME: support inout/out parameters for semantics.
925 if ([[maybe_unused]] HLSLParamModifierAttr *MA =
926 PD->getAttr<HLSLParamModifierAttr>()) {
927 llvm_unreachable("Not handled yet");
928 } else {
929 llvm::Type *ParamType =
930 Param.hasByValAttr() ? Param.getParamByValType() : Param.getType();
931 auto AttrBegin = PD->specific_attr_begin<HLSLAppliedSemanticAttr>();
932 auto AttrEnd = PD->specific_attr_end<HLSLAppliedSemanticAttr>();
933 auto Result =
934 handleSemanticLoad(B, FD, ParamType, PD, AttrBegin, AttrEnd);
935 SemanticValue = Result.first;
936 if (!SemanticValue)
937 return;
938 if (Param.hasByValAttr()) {
939 llvm::Value *Var = B.CreateAlloca(Param.getParamByValType());
940 B.CreateStore(SemanticValue, Var);
941 SemanticValue = Var;
942 }
943 }
944
945 assert(SemanticValue);
946 Args.push_back(SemanticValue);
947 }
948
949 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
950 CI->setCallingConv(Fn->getCallingConv());
951
952 if (Fn->getReturnType() != CGM.VoidTy)
953 OutputSemantic.try_emplace(FD, CI);
954
955 for (auto &[Decl, Source] : OutputSemantic) {
956 AllocaInst *AI = dyn_cast<AllocaInst>(Source);
957 llvm::Value *SourceValue =
958 AI ? B.CreateLoad(AI->getAllocatedType(), Source) : Source;
959
960 auto AttrBegin = Decl->specific_attr_begin<HLSLAppliedSemanticAttr>();
961 auto AttrEnd = Decl->specific_attr_end<HLSLAppliedSemanticAttr>();
962 handleSemanticStore(B, FD, SourceValue, Decl, AttrBegin, AttrEnd);
963 }
964
965 B.CreateRetVoid();
966
967 // Add and identify root signature to function, if applicable
968 for (const Attr *Attr : FD->getAttrs()) {
969 if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) {
970 auto *RSDecl = RSAttr->getSignatureDecl();
971 addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
972 EntryFn, M);
973 }
974 }
975}
976
977static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
978 bool CtorOrDtor) {
979 const auto *GV =
980 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
981 if (!GV)
982 return;
983 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
984 if (!CA)
985 return;
986 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
987 // HLSL neither supports priorities or COMDat values, so we will check those
988 // in an assert but not handle them.
989
990 for (const auto &Ctor : CA->operands()) {
992 continue;
993 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
994
995 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
996 "HLSL doesn't support setting priority for global ctors.");
997 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
998 "HLSL doesn't support COMDat for global ctors.");
999 Fns.push_back(cast<Function>(CS->getOperand(1)));
1000 }
1001}
1002
1004 llvm::Module &M = CGM.getModule();
1007 gatherFunctions(CtorFns, M, true);
1008 gatherFunctions(DtorFns, M, false);
1009
1010 // Insert a call to the global constructor at the beginning of the entry block
1011 // to externally exported functions. This is a bit of a hack, but HLSL allows
1012 // global constructors, but doesn't support driver initialization of globals.
1013 for (auto &F : M.functions()) {
1014 if (!F.hasFnAttribute("hlsl.shader"))
1015 continue;
1016 auto *Token = getConvergenceToken(F.getEntryBlock());
1017 Instruction *IP = &*F.getEntryBlock().begin();
1019 if (Token) {
1020 llvm::Value *bundleArgs[] = {Token};
1021 OB.emplace_back("convergencectrl", bundleArgs);
1022 IP = Token->getNextNode();
1023 }
1024 IRBuilder<> B(IP);
1025 for (auto *Fn : CtorFns) {
1026 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1027 CI->setCallingConv(Fn->getCallingConv());
1028 }
1029
1030 // Insert global dtors before the terminator of the last instruction
1031 B.SetInsertPoint(F.back().getTerminator());
1032 for (auto *Fn : DtorFns) {
1033 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1034 CI->setCallingConv(Fn->getCallingConv());
1035 }
1036 }
1037
1038 // No need to keep global ctors/dtors for non-lib profile after call to
1039 // ctors/dtors added for entry.
1040 Triple T(M.getTargetTriple());
1041 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
1042 if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
1043 GV->eraseFromParent();
1044 if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
1045 GV->eraseFromParent();
1046 }
1047}
1048
1049static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
1050 Intrinsic::ID IntrID,
1052
1053 LLVMContext &Ctx = CGM.getLLVMContext();
1054 llvm::Function *InitResFunc = llvm::Function::Create(
1055 llvm::FunctionType::get(CGM.VoidTy, false),
1056 llvm::GlobalValue::InternalLinkage,
1057 ("_init_buffer_" + GV->getName()).str(), CGM.getModule());
1058 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1059
1060 llvm::BasicBlock *EntryBB =
1061 llvm::BasicBlock::Create(Ctx, "entry", InitResFunc);
1062 CGBuilderTy Builder(CGM, Ctx);
1063 const DataLayout &DL = CGM.getModule().getDataLayout();
1064 Builder.SetInsertPoint(EntryBB);
1065
1066 // Make sure the global variable is buffer resource handle
1067 llvm::Type *HandleTy = GV->getValueType();
1068 assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");
1069
1070 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
1071 /*ReturnType=*/HandleTy, IntrID, Args, nullptr,
1072 Twine(GV->getName()).concat("_h"));
1073
1074 llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
1075 Builder.CreateAlignedStore(CreateHandle, HandleRef,
1076 HandleRef->getPointerAlignment(DL));
1077 Builder.CreateRetVoid();
1078
1079 CGM.AddCXXGlobalInit(InitResFunc);
1080}
1081
1082void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
1083 llvm::GlobalVariable *GV) {
1084 ResourceBindingAttrs Binding(BufDecl);
1085 assert(Binding.hasBinding() &&
1086 "cbuffer/tbuffer should always have resource binding attribute");
1087
1088 auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
1089 auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
1090 auto *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
1091 Value *Name = buildNameForResource(BufDecl->getName(), CGM);
1092
1093 // buffer with explicit binding
1094 if (Binding.isExplicit()) {
1095 llvm::Intrinsic::ID IntrinsicID =
1096 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
1097 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
1098 SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
1099 initializeBuffer(CGM, GV, IntrinsicID, Args);
1100 } else {
1101 // buffer with implicit binding
1102 llvm::Intrinsic::ID IntrinsicID =
1103 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
1104 auto *OrderID =
1105 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
1106 SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
1107 initializeBuffer(CGM, GV, IntrinsicID, Args);
1108 }
1109}
1110
1112 llvm::GlobalVariable *GV) {
1113 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
1114 addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
1115}
1116
1117llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
1118 if (!CGM.shouldEmitConvergenceTokens())
1119 return nullptr;
1120
1121 auto E = BB.end();
1122 for (auto I = BB.begin(); I != E; ++I) {
1123 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
1124 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
1125 return II;
1126 }
1127 }
1128 llvm_unreachable("Convergence token should have been emitted.");
1129 return nullptr;
1130}
1131
1132class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
1133public:
1137
1139 // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
1140 // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
1141 // traversal, the temporary containing the copy out will not have
1142 // been created yet.
1143 return false;
1144 }
1145
1147 // Traverse the source expression first.
1148 if (E->getSourceExpr())
1150
1151 // Then add this OVE if we haven't seen it before.
1152 if (Visited.insert(E).second)
1153 OVEs.push_back(E);
1154
1155 return true;
1156 }
1157};
1158
1160 InitListExpr *E) {
1161
1162 typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
1163 OpaqueValueVisitor Visitor;
1164 Visitor.TraverseStmt(E);
1165 for (auto *OVE : Visitor.OVEs) {
1166 if (CGF.isOpaqueValueEmitted(OVE))
1167 continue;
1168 if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
1169 LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
1170 OpaqueValueMappingData::bind(CGF, OVE, LV);
1171 } else {
1172 RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
1173 OpaqueValueMappingData::bind(CGF, OVE, RV);
1174 }
1175 }
1176}
1177
1179 const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
1180 assert((ArraySubsExpr->getType()->isHLSLResourceRecord() ||
1181 ArraySubsExpr->getType()->isHLSLResourceRecordArray()) &&
1182 "expected resource array subscript expression");
1183
1184 // Let clang codegen handle local resource array subscripts,
1185 // or when the subscript references on opaque expression (as part of
1186 // ArrayInitLoopExpr AST node).
1187 const VarDecl *ArrayDecl =
1188 dyn_cast_or_null<VarDecl>(getArrayDecl(ArraySubsExpr));
1189 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage())
1190 return std::nullopt;
1191
1192 // get the resource array type
1193 ASTContext &AST = ArrayDecl->getASTContext();
1194 const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
1195 assert(ResArrayTy->isHLSLResourceRecordArray() &&
1196 "expected array of resource classes");
1197
1198 // Iterate through all nested array subscript expressions to calculate
1199 // the index in the flattened resource array (if this is a multi-
1200 // dimensional array). The index is calculated as a sum of all indices
1201 // multiplied by the total size of the array at that level.
1202 Value *Index = nullptr;
1203 const ArraySubscriptExpr *ASE = ArraySubsExpr;
1204 while (ASE != nullptr) {
1205 Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
1206 if (const auto *ArrayTy =
1207 dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
1208 Value *Multiplier = llvm::ConstantInt::get(
1209 CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy));
1210 SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
1211 }
1212 Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
1213 ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
1214 }
1215
1216 // Find binding info for the resource array. For implicit binding
1217 // an HLSLResourceBindingAttr should have been added by SemaHLSL.
1218 ResourceBindingAttrs Binding(ArrayDecl);
1219 assert((Binding.hasBinding()) &&
1220 "resource array must have a binding attribute");
1221
1222 // Find the individual resource type.
1223 QualType ResultTy = ArraySubsExpr->getType();
1224 QualType ResourceTy =
1225 ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy;
1226
1227 // Create a temporary variable for the result, which is either going
1228 // to be a single resource instance or a local array of resources (we need to
1229 // return an LValue).
1230 RawAddress TmpVar = CGF.CreateMemTemp(ResultTy);
1231 if (CGF.EmitLifetimeStart(TmpVar.getPointer()))
1233 NormalEHLifetimeMarker, TmpVar);
1234
1239
1240 // Calculate total array size (= range size).
1241 llvm::Value *Range =
1242 llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(AST, ResArrayTy));
1243
1244 // If the result of the subscript operation is a single resource, call the
1245 // constructor.
1246 if (ResultTy == ResourceTy) {
1247 CallArgList Args;
1248 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
1249 CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
1250 ArrayDecl->getName(), Binding, Args);
1251
1252 if (!CreateMethod)
1253 // This can happen if someone creates an array of structs that looks like
1254 // an HLSL resource record array but it does not have the required static
1255 // create method. No binding will be generated for it.
1256 return std::nullopt;
1257
1258 callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
1259
1260 } else {
1261 // The result of the subscript operation is a local resource array which
1262 // needs to be initialized.
1263 const ConstantArrayType *ArrayTy =
1265 std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
1266 CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
1267 ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)},
1268 ArraySubsExpr->getExprLoc());
1269 if (!EndIndex)
1270 return std::nullopt;
1271 }
1272 return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
1273}
1274
1276 const ArraySubscriptExpr *E, CodeGenFunction &CGF,
1277 llvm::function_ref<llvm::Value *(bool Promote)> EmitIdxAfterBase) {
1278 // Find the element type to index by first padding the element type per HLSL
1279 // buffer rules, and then padding out to a 16-byte register boundary if
1280 // necessary.
1281 llvm::Type *LayoutTy =
1283 uint64_t LayoutSizeInBits =
1284 CGM.getDataLayout().getTypeSizeInBits(LayoutTy).getFixedValue();
1285 CharUnits ElementSize = CharUnits::fromQuantity(LayoutSizeInBits / 8);
1286 CharUnits RowAlignedSize = ElementSize.alignTo(CharUnits::fromQuantity(16));
1287 if (RowAlignedSize > ElementSize) {
1288 llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding(
1289 CGM, RowAlignedSize - ElementSize);
1290 assert(Padding && "No padding type for target?");
1291 LayoutTy = llvm::StructType::get(CGF.getLLVMContext(), {LayoutTy, Padding},
1292 /*isPacked=*/true);
1293 }
1294
1295 // If the layout type doesn't introduce any padding, we don't need to do
1296 // anything special.
1297 llvm::Type *OrigTy = CGF.CGM.getTypes().ConvertTypeForMem(E->getType());
1298 if (LayoutTy == OrigTy)
1299 return std::nullopt;
1300
1301 LValueBaseInfo EltBaseInfo;
1302 TBAAAccessInfo EltTBAAInfo;
1303 Address Addr =
1304 CGF.EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
1305 llvm::Value *Idx = EmitIdxAfterBase(/*Promote*/ true);
1306
1307 // Index into the object as-if we have an array of the padded element type,
1308 // and then dereference the element itself to avoid reading padding that may
1309 // be past the end of the in-memory object.
1311 Indices.push_back(Idx);
1312 Indices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
1313
1314 llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF),
1315 Indices, "cbufferidx");
1316 Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull);
1317
1318 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
1319}
1320
1321namespace {
1322/// Utility for emitting copies following the HLSL buffer layout rules (ie,
1323/// copying out of a cbuffer).
1324class HLSLBufferCopyEmitter {
1325 CodeGenFunction &CGF;
1326 Address DestPtr;
1327 Address SrcPtr;
1328 llvm::Type *LayoutTy = nullptr;
1329
1330 SmallVector<llvm::Value *> CurStoreIndices;
1331 SmallVector<llvm::Value *> CurLoadIndices;
1332
1333 void emitCopyAtIndices(llvm::Type *FieldTy, llvm::ConstantInt *StoreIndex,
1334 llvm::ConstantInt *LoadIndex) {
1335 CurStoreIndices.push_back(StoreIndex);
1336 CurLoadIndices.push_back(LoadIndex);
1337 auto RestoreIndices = llvm::make_scope_exit([&]() {
1338 CurStoreIndices.pop_back();
1339 CurLoadIndices.pop_back();
1340 });
1341
1342 // First, see if this is some kind of aggregate and recurse.
1343 if (processArray(FieldTy))
1344 return;
1345 if (processBufferLayoutArray(FieldTy))
1346 return;
1347 if (processStruct(FieldTy))
1348 return;
1349
1350 // When we have a scalar or vector element we can emit the copy.
1352 CGF.CGM.getDataLayout().getABITypeAlign(FieldTy));
1353 Address SrcGEP = RawAddress(
1354 CGF.Builder.CreateInBoundsGEP(LayoutTy, SrcPtr.getBasePointer(),
1355 CurLoadIndices, "cbuf.src"),
1356 FieldTy, Align, SrcPtr.isKnownNonNull());
1357 Address DestGEP = CGF.Builder.CreateInBoundsGEP(
1358 DestPtr, CurStoreIndices, FieldTy, Align, "cbuf.dest");
1359 llvm::Value *Load = CGF.Builder.CreateLoad(SrcGEP, "cbuf.load");
1360 CGF.Builder.CreateStore(Load, DestGEP);
1361 }
1362
1363 bool processArray(llvm::Type *FieldTy) {
1364 auto *AT = dyn_cast<llvm::ArrayType>(FieldTy);
1365 if (!AT)
1366 return false;
1367
1368 // If we have an llvm::ArrayType this is just a regular array with no top
1369 // level padding, so all we need to do is copy each member.
1370 for (unsigned I = 0, E = AT->getNumElements(); I < E; ++I)
1371 emitCopyAtIndices(AT->getElementType(),
1372 llvm::ConstantInt::get(CGF.SizeTy, I),
1373 llvm::ConstantInt::get(CGF.SizeTy, I));
1374 return true;
1375 }
1376
1377 bool processBufferLayoutArray(llvm::Type *FieldTy) {
1378 // A buffer layout array is a struct with two elements: the padded array,
1379 // and the last element. That is, is should look something like this:
1380 //
1381 // { [%n x { %type, %padding }], %type }
1382 //
1383 auto *ST = dyn_cast<llvm::StructType>(FieldTy);
1384 if (!ST || ST->getNumElements() != 2)
1385 return false;
1386
1387 auto *PaddedEltsTy = dyn_cast<llvm::ArrayType>(ST->getElementType(0));
1388 if (!PaddedEltsTy)
1389 return false;
1390
1391 auto *PaddedTy = dyn_cast<llvm::StructType>(PaddedEltsTy->getElementType());
1392 if (!PaddedTy || PaddedTy->getNumElements() != 2)
1393 return false;
1394
1396 PaddedTy->getElementType(1)))
1397 return false;
1398
1399 llvm::Type *ElementTy = ST->getElementType(1);
1400 if (PaddedTy->getElementType(0) != ElementTy)
1401 return false;
1402
1403 // All but the last of the logical array elements are in the padded array.
1404 unsigned NumElts = PaddedEltsTy->getNumElements() + 1;
1405
1406 // Add an extra indirection to the load for the struct and walk the
1407 // array prefix.
1408 CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
1409 for (unsigned I = 0; I < NumElts - 1; ++I) {
1410 // We need to copy the element itself, without the padding.
1411 CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.SizeTy, I));
1412 emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.SizeTy, I),
1413 llvm::ConstantInt::get(CGF.Int32Ty, 0));
1414 CurLoadIndices.pop_back();
1415 }
1416 CurLoadIndices.pop_back();
1417
1418 // Now copy the last element.
1419 emitCopyAtIndices(ElementTy,
1420 llvm::ConstantInt::get(CGF.SizeTy, NumElts - 1),
1421 llvm::ConstantInt::get(CGF.Int32Ty, 1));
1422
1423 return true;
1424 }
1425
1426 bool processStruct(llvm::Type *FieldTy) {
1427 auto *ST = dyn_cast<llvm::StructType>(FieldTy);
1428 if (!ST)
1429 return false;
1430
1431 // Copy the struct field by field, but skip any explicit padding.
1432 unsigned Skipped = 0;
1433 for (unsigned I = 0, E = ST->getNumElements(); I < E; ++I) {
1434 llvm::Type *ElementTy = ST->getElementType(I);
1435 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(ElementTy))
1436 ++Skipped;
1437 else
1438 emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.Int32Ty, I),
1439 llvm::ConstantInt::get(CGF.Int32Ty, I + Skipped));
1440 }
1441 return true;
1442 }
1443
1444public:
1445 HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr)
1446 : CGF(CGF), DestPtr(DestPtr), SrcPtr(SrcPtr) {}
1447
1448 bool emitCopy(QualType CType) {
1449 LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(CType);
1450
1451 // TODO: We should be able to fall back to a regular memcpy if the layout
1452 // type doesn't have any padding, but that runs into issues in the backend
1453 // currently.
1454 //
1455 // See https://github.com/llvm/wg-hlsl/issues/351
1456 emitCopyAtIndices(LayoutTy, llvm::ConstantInt::get(CGF.SizeTy, 0),
1457 llvm::ConstantInt::get(CGF.SizeTy, 0));
1458 return true;
1459 }
1460};
1461} // namespace
1462
1464 Address SrcPtr, QualType CType) {
1465 return HLSLBufferCopyEmitter(CGF, DestPtr, SrcPtr).emitCopy(CType);
1466}
1467
1469 const MemberExpr *E) {
1470 LValue Base =
1472 auto *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
1473 assert(Field && "Unexpected access into HLSL buffer");
1474
1475 // Get the field index for the struct.
1476 const RecordDecl *Rec = Field->getParent();
1477 unsigned FieldIdx =
1478 CGM.getTypes().getCGRecordLayout(Rec).getLLVMFieldNo(Field);
1479
1480 // Work out the buffer layout type to index into.
1481 QualType RecType = CGM.getContext().getCanonicalTagType(Rec);
1482 assert(RecType->isStructureOrClassType() && "Invalid type in HLSL buffer");
1483 // Since this is a member of an object in the buffer and not the buffer's
1484 // struct/class itself, we shouldn't have any offsets on the members we need
1485 // to contend with.
1486 CGHLSLOffsetInfo EmptyOffsets;
1487 llvm::StructType *LayoutTy = HLSLBufferLayoutBuilder(CGM).layOutStruct(
1488 RecType->getAsCanonical<RecordType>(), EmptyOffsets);
1489
1490 // Now index into the struct, making sure that the type we return is the
1491 // buffer layout type rather than the original type in the AST.
1492 QualType FieldType = Field->getType();
1493 llvm::Type *FieldLLVMTy = CGM.getTypes().ConvertTypeForMem(FieldType);
1495 CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy));
1496 Address Addr(CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF),
1497 FieldIdx, Field->getName()),
1498 FieldLLVMTy, Align, KnownNonNull);
1499
1500 LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(),
1502 CGM.getTBAAAccessInfo(FieldType));
1503 LV.getQuals().addCVRQualifiers(Base.getVRQualifiers());
1504
1505 return LV;
1506}
Defines the clang::ASTContext interface.
static llvm::Value * createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, unsigned BuiltInID)
static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, unsigned BuiltIn)
static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M, llvm::Value *Source, unsigned Location, StringRef Name)
static void gatherFunctions(SmallVectorImpl< Function * > &Fns, llvm::Module &M, bool CtorOrDtor)
static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location)
static llvm::Value * createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, unsigned Location, StringRef Name)
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)
static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M, llvm::Value *Source, const Twine &Name, unsigned BuiltInID)
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:45
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
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
Definition CharUnits.h:201
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
Definition Address.h:128
llvm::Value * getBasePointer() const
Definition Address.h:198
CharUnits getAlignment() const
Definition Address.h:194
KnownNonNull_t isKnownNonNull() const
Whether the pointer is known not to be null.
Definition Address.h:233
An aggregate value slot.
Definition CGValue.h:505
Address getAddress() const
Definition CGValue.h:645
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:588
llvm::StoreInst * CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile=false)
Definition CGBuilder.h:140
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Definition CGBuilder.h:296
Address CreateStructGEP(Address Addr, unsigned Index, const llvm::Twine &Name="")
Definition CGBuilder.h:223
llvm::LoadInst * CreateLoad(Address Addr, const llvm::Twine &Name="")
Definition CGBuilder.h:112
Address CreateInBoundsGEP(Address Addr, ArrayRef< llvm::Value * > IdxList, llvm::Type *ElementType, CharUnits Align, const Twine &Name="")
Definition CGBuilder.h:350
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.
static const uint32_t Unspecified
static bool compareOffsets(uint32_t LHS, uint32_t RHS)
Comparison function for offsets received from operator[] suitable for use in a stable_sort.
static CGHLSLOffsetInfo fromDecl(const HLSLBufferDecl &BufDecl)
Iterates over all declarations in the HLSL buffer and based on the packoffset or register(c#) annotat...
llvm::Instruction * getConvergenceToken(llvm::BasicBlock &BB)
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
specific_attr_iterator< HLSLAppliedSemanticAttr > handleSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrBegin, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrEnd)
llvm::StructType * getHLSLBufferLayoutType(const RecordType *LayoutStructTy)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var)
void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, std::optional< unsigned > Index)
std::pair< llvm::Value *, specific_attr_iterator< HLSLAppliedSemanticAttr > > handleStructSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > begin, specific_attr_iterator< HLSLAppliedSemanticAttr > end)
specific_attr_iterator< HLSLAppliedSemanticAttr > handleStructSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrBegin, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrEnd)
llvm::Value * handleScalarSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic)
void addHLSLBufferLayoutType(const RecordType *LayoutStructTy, llvm::StructType *LayoutTy)
void handleScalarSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic)
std::pair< llvm::Value *, specific_attr_iterator< HLSLAppliedSemanticAttr > > handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > begin, specific_attr_iterator< HLSLAppliedSemanticAttr > end)
std::optional< LValue > emitBufferArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF, llvm::function_ref< llvm::Value *(bool Promote)> EmitIdxAfterBase)
std::optional< LValue > emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF)
void addRootSignature(const HLSLRootSignatureDecl *D)
LValue emitBufferMemberExpr(CodeGenFunction &CGF, const MemberExpr *E)
bool emitBufferCopy(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, QualType CType)
llvm::Type * convertHLSLSpecificType(const Type *T, const CGHLSLOffsetInfo &OffsetInfo)
void addBuffer(const HLSLBufferDecl *D)
llvm::Value * emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, std::optional< unsigned > Index)
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...
@ TCK_MemberAccess
Checking the object expression in a non-static data member access.
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:5235
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:266
llvm::Type * ConvertTypeForMem(QualType T)
Address EmitPointerWithAlignment(const Expr *Addr, LValueBaseInfo *BaseInfo=nullptr, TBAAAccessInfo *TBAAInfo=nullptr, KnownNonNull_t IsKnownNonNull=NotKnownNonNull)
EmitPointerWithAlignment - Given an expression with a pointer type, emit the value and compute our be...
Definition CGExpr.cpp:1552
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK)
Same as EmitLValue but additionally we generate checking code to guard against undefined behavior.
Definition CGExpr.cpp:1633
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:188
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:1668
bool isOpaqueValueEmitted(const OpaqueValueExpr *E)
isOpaqueValueEmitted - Return true if the opaque value expression has already been emitted.
Definition CGExpr.cpp:5942
llvm::LLVMContext & getLLVMContext()
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.
const llvm::DataLayout & getDataLayout() const
ASTContext & getContext() const
const TargetCodeGenInfo & getTargetCodeGenInfo()
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.
llvm::Type * ConvertTypeForMem(QualType T)
ConvertTypeForMem - Convert type T into a llvm::Type.
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:700
llvm::Constant * getPointer() const
Definition Address.h:308
llvm::StructType * layOutStruct(const RecordType *StructType, const CGHLSLOffsetInfo &OffsetInfo)
Lays out a struct type following HLSL buffer rules and considering any explicit offset information.
llvm::Type * layOutType(QualType Type)
Lays out a type following HLSL buffer rules.
LValue - This represents an lvalue references.
Definition CGValue.h:183
static LValue MakeAddr(Address Addr, QualType type, ASTContext &Context, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo)
Definition CGValue.h:433
const Qualifiers & getQuals() const
Definition CGValue.h:339
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:99
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
virtual bool isHLSLPadding(llvm::Type *Ty) const
Return true if this is an HLSL padding type.
Definition TargetInfo.h:459
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
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2109
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:546
specific_attr_iterator< T > specific_attr_end() const
Definition DeclBase.h:569
specific_attr_iterator< T > specific_attr_begin() const
Definition DeclBase.h:564
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 member of a struct/union/class.
Definition Decl.h:3160
Represents a function declaration or definition.
Definition Decl.h:2000
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2797
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
Definition Decl.h:2862
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5254
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
Describes an C or C++ initializer list.
Definition Expr.h:5233
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3298
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3381
Expr * getBase() const
Definition Expr.h:3375
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:8278
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8404
The collection of all-type qualifiers we support.
Definition TypeBase.h:331
void addCVRQualifiers(unsigned mask)
Definition TypeBase.h:502
Represents a struct/union/class.
Definition Decl.h:4312
field_iterator field_end() const
Definition Decl.h:4518
field_iterator field_begin() const
Definition Decl.cpp:5205
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:8622
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isArrayType() const
Definition TypeBase.h:8614
bool isHLSLResourceRecord() const
Definition Type.cpp:5362
bool isStructureOrClassType() const
Definition Type.cpp:706
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2921
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9091
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:5366
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
specific_attr_iterator - Iterates over a subrange of an AttrVec, only providing attributes that are o...
@ Type
The l-value was considered opaque, so the alignment was determined from a type.
Definition CGValue.h:155
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Definition CGValue.h:146
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
@ Result
The result type of a method or function.
Definition TypeBase.h:905
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