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