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 if (CodeGenOpts.AllResourcesBound)
487 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error,
488 "dx.allresourcesbound", 1);
489 // NativeHalfType corresponds to the -fnative-half-type clang option which is
490 // aliased by clang-dxc's -enable-16bit-types option. This option is used to
491 // set the UseNativeLowPrecision DXIL module flag in the DirectX backend
492 if (LangOpts.NativeHalfType)
493 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.nativelowprec",
494 1);
495
497}
498
500 const FunctionDecl *FD, llvm::Function *Fn) {
501 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
502 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
503 const StringRef ShaderAttrKindStr = "hlsl.shader";
504 Fn->addFnAttr(ShaderAttrKindStr,
505 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
506 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
507 const StringRef NumThreadsKindStr = "hlsl.numthreads";
508 std::string NumThreadsStr =
509 formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
510 NumThreadsAttr->getZ());
511 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
512 }
513 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->getAttr<HLSLWaveSizeAttr>()) {
514 const StringRef WaveSizeKindStr = "hlsl.wavesize";
515 std::string WaveSizeStr =
516 formatv("{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
517 WaveSizeAttr->getPreferred());
518 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
519 }
520 // HLSL entry functions are materialized for module functions with
521 // HLSLShaderAttr attribute. SetLLVMFunctionAttributesForDefinition called
522 // later in the compiler-flow for such module functions is not aware of and
523 // hence not able to set attributes of the newly materialized entry functions.
524 // So, set attributes of entry function here, as appropriate.
525 if (CGM.getCodeGenOpts().OptimizationLevel == 0)
526 Fn->addFnAttr(llvm::Attribute::OptimizeNone);
527 Fn->addFnAttr(llvm::Attribute::NoInline);
528
529 if (CGM.getLangOpts().HLSLSpvEnableMaximalReconvergence) {
530 Fn->addFnAttr("enable-maximal-reconvergence", "true");
531 }
532}
533
534static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
535 if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
536 Value *Result = PoisonValue::get(Ty);
537 for (unsigned I = 0; I < VT->getNumElements(); ++I) {
538 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
539 Result = B.CreateInsertElement(Result, Elt, I);
540 }
541 return Result;
542 }
543 return B.CreateCall(F, {B.getInt32(0)});
544}
545
546static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV,
547 unsigned BuiltIn) {
548 LLVMContext &Ctx = GV->getContext();
549 IRBuilder<> B(GV->getContext());
550 MDNode *Operands = MDNode::get(
551 Ctx,
552 {ConstantAsMetadata::get(B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)),
553 ConstantAsMetadata::get(B.getInt32(BuiltIn))});
554 MDNode *Decoration = MDNode::get(Ctx, {Operands});
555 GV->addMetadata("spirv.Decorations", *Decoration);
556}
557
558static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) {
559 LLVMContext &Ctx = GV->getContext();
560 IRBuilder<> B(GV->getContext());
561 MDNode *Operands =
562 MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)),
563 ConstantAsMetadata::get(B.getInt32(Location))});
564 MDNode *Decoration = MDNode::get(Ctx, {Operands});
565 GV->addMetadata("spirv.Decorations", *Decoration);
566}
567
568static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
569 llvm::Type *Ty, const Twine &Name,
570 unsigned BuiltInID) {
571 auto *GV = new llvm::GlobalVariable(
572 M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
573 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
574 llvm::GlobalVariable::GeneralDynamicTLSModel,
575 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
576 addSPIRVBuiltinDecoration(GV, BuiltInID);
577 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
578 return B.CreateLoad(Ty, GV);
579}
580
581static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M,
582 llvm::Type *Ty, unsigned Location,
583 StringRef Name) {
584 auto *GV = new llvm::GlobalVariable(
585 M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
586 /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
587 llvm::GlobalVariable::GeneralDynamicTLSModel,
588 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
589 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
590 addLocationDecoration(GV, Location);
591 return B.CreateLoad(Ty, GV);
592}
593
594llvm::Value *CGHLSLRuntime::emitSPIRVUserSemanticLoad(
595 llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
596 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
597 Twine BaseName = Twine(Semantic->getAttrName()->getName());
598 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
599
600 unsigned Location = SPIRVLastAssignedInputSemanticLocation;
601 if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
602 Location = L->getLocation();
603
604 // DXC completely ignores the semantic/index pair. Location are assigned from
605 // the first semantic to the last.
606 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
607 unsigned ElementCount = AT ? AT->getNumElements() : 1;
608 SPIRVLastAssignedInputSemanticLocation += ElementCount;
609
610 return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location,
611 VariableName.str());
612}
613
614static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M,
615 llvm::Value *Source, unsigned Location,
616 StringRef Name) {
617 auto *GV = new llvm::GlobalVariable(
618 M, Source->getType(), /* isConstant= */ false,
619 llvm::GlobalValue::ExternalLinkage,
620 /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
621 llvm::GlobalVariable::GeneralDynamicTLSModel,
622 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
623 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
624 addLocationDecoration(GV, Location);
625 B.CreateStore(Source, GV);
626}
627
628void CGHLSLRuntime::emitSPIRVUserSemanticStore(
629 llvm::IRBuilder<> &B, llvm::Value *Source,
630 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
631 std::optional<unsigned> Index) {
632 Twine BaseName = Twine(Semantic->getAttrName()->getName());
633 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
634
635 unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
636 if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
637 Location = L->getLocation();
638
639 // DXC completely ignores the semantic/index pair. Location are assigned from
640 // the first semantic to the last.
641 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
642 unsigned ElementCount = AT ? AT->getNumElements() : 1;
643 SPIRVLastAssignedOutputSemanticLocation += ElementCount;
644 createSPIRVLocationStore(B, CGM.getModule(), Source, Location,
645 VariableName.str());
646}
647
648llvm::Value *
649CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
650 HLSLAppliedSemanticAttr *Semantic,
651 std::optional<unsigned> Index) {
652 Twine BaseName = Twine(Semantic->getAttrName()->getName());
653 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
654
655 // DXIL packing rules etc shall be handled here.
656 // FIXME: generate proper sigpoint, index, col, row values.
657 // FIXME: also DXIL loads vectors element by element.
658 SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
659 B.getInt8(0),
660 llvm::PoisonValue::get(B.getInt32Ty())};
661
662 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
663 llvm::Value *Value = B.CreateIntrinsic(/*ReturnType=*/Type, IntrinsicID, Args,
664 nullptr, VariableName);
665 return Value;
666}
667
668void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
669 llvm::Value *Source,
670 HLSLAppliedSemanticAttr *Semantic,
671 std::optional<unsigned> Index) {
672 // DXIL packing rules etc shall be handled here.
673 // FIXME: generate proper sigpoint, index, col, row values.
674 SmallVector<Value *> Args{B.getInt32(4),
675 B.getInt32(0),
676 B.getInt32(0),
677 B.getInt8(0),
678 llvm::PoisonValue::get(B.getInt32Ty()),
679 Source};
680
681 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
682 B.CreateIntrinsic(/*ReturnType=*/CGM.VoidTy, IntrinsicID, Args, nullptr);
683}
684
685llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
686 IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
687 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
688 if (CGM.getTarget().getTriple().isSPIRV())
689 return emitSPIRVUserSemanticLoad(B, Type, Decl, Semantic, Index);
690
691 if (CGM.getTarget().getTriple().isDXIL())
692 return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
693
694 llvm_unreachable("Unsupported target for user-semantic load.");
695}
696
697void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
698 const clang::DeclaratorDecl *Decl,
699 HLSLAppliedSemanticAttr *Semantic,
700 std::optional<unsigned> Index) {
701 if (CGM.getTarget().getTriple().isSPIRV())
702 return emitSPIRVUserSemanticStore(B, Source, Decl, Semantic, Index);
703
704 if (CGM.getTarget().getTriple().isDXIL())
705 return emitDXILUserSemanticStore(B, Source, Semantic, Index);
706
707 llvm_unreachable("Unsupported target for user-semantic load.");
708}
709
711 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
712 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
713 std::optional<unsigned> Index) {
714
715 std::string SemanticName = Semantic->getAttrName()->getName().upper();
716 if (SemanticName == "SV_GROUPINDEX") {
717 llvm::Function *GroupIndex =
718 CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
719 return B.CreateCall(FunctionCallee(GroupIndex));
720 }
721
722 if (SemanticName == "SV_DISPATCHTHREADID") {
723 llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
724 llvm::Function *ThreadIDIntrinsic =
725 llvm::Intrinsic::isOverloaded(IntrinID)
726 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
727 : CGM.getIntrinsic(IntrinID);
728 return buildVectorInput(B, ThreadIDIntrinsic, Type);
729 }
730
731 if (SemanticName == "SV_GROUPTHREADID") {
732 llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
733 llvm::Function *GroupThreadIDIntrinsic =
734 llvm::Intrinsic::isOverloaded(IntrinID)
735 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
736 : CGM.getIntrinsic(IntrinID);
737 return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
738 }
739
740 if (SemanticName == "SV_GROUPID") {
741 llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
742 llvm::Function *GroupIDIntrinsic =
743 llvm::Intrinsic::isOverloaded(IntrinID)
744 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
745 : CGM.getIntrinsic(IntrinID);
746 return buildVectorInput(B, GroupIDIntrinsic, Type);
747 }
748
749 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
750 assert(ShaderAttr && "Entry point has no shader attribute");
751 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
752
753 if (SemanticName == "SV_POSITION") {
754 if (ST == Triple::EnvironmentType::Pixel) {
755 if (CGM.getTarget().getTriple().isSPIRV())
756 return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
757 Semantic->getAttrName()->getName(),
758 /* BuiltIn::FragCoord */ 15);
759 if (CGM.getTarget().getTriple().isDXIL())
760 return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
761 }
762
763 if (ST == Triple::EnvironmentType::Vertex) {
764 return emitUserSemanticLoad(B, Type, Decl, Semantic, Index);
765 }
766 }
767
768 llvm_unreachable(
769 "Load hasn't been implemented yet for this system semantic. FIXME");
770}
771
772static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M,
773 llvm::Value *Source, const Twine &Name,
774 unsigned BuiltInID) {
775 auto *GV = new llvm::GlobalVariable(
776 M, Source->getType(), /* isConstant= */ false,
777 llvm::GlobalValue::ExternalLinkage,
778 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
779 llvm::GlobalVariable::GeneralDynamicTLSModel,
780 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
781 addSPIRVBuiltinDecoration(GV, BuiltInID);
782 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
783 B.CreateStore(Source, GV);
784}
785
786void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
788 HLSLAppliedSemanticAttr *Semantic,
789 std::optional<unsigned> Index) {
790
791 std::string SemanticName = Semantic->getAttrName()->getName().upper();
792 if (SemanticName == "SV_POSITION") {
793 if (CGM.getTarget().getTriple().isDXIL()) {
794 emitDXILUserSemanticStore(B, Source, Semantic, Index);
795 return;
796 }
797
798 if (CGM.getTarget().getTriple().isSPIRV()) {
799 createSPIRVBuiltinStore(B, CGM.getModule(), Source,
800 Semantic->getAttrName()->getName(),
801 /* BuiltIn::Position */ 0);
802 return;
803 }
804 }
805
806 if (SemanticName == "SV_TARGET") {
807 emitUserSemanticStore(B, Source, Decl, Semantic, Index);
808 return;
809 }
810
811 llvm_unreachable(
812 "Store hasn't been implemented yet for this system semantic. FIXME");
813}
814
816 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
817 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
818
819 std::optional<unsigned> Index = Semantic->getSemanticIndex();
820 if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
821 return emitSystemSemanticLoad(B, FD, Type, Decl, Semantic, Index);
822 return emitUserSemanticLoad(B, Type, Decl, Semantic, Index);
823}
824
826 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
827 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
828 std::optional<unsigned> Index = Semantic->getSemanticIndex();
829 if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
830 emitSystemSemanticStore(B, Source, Decl, Semantic, Index);
831 else
832 emitUserSemanticStore(B, Source, Decl, Semantic, Index);
833}
834
835std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
837 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
841 const llvm::StructType *ST = cast<StructType>(Type);
842 const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();
843
844 assert(RD->getNumFields() == ST->getNumElements());
845
846 llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
847 auto FieldDecl = RD->field_begin();
848 for (unsigned I = 0; I < ST->getNumElements(); ++I) {
849 auto [ChildValue, NextAttr] = handleSemanticLoad(
850 B, FD, ST->getElementType(I), *FieldDecl, AttrBegin, AttrEnd);
851 AttrBegin = NextAttr;
852 assert(ChildValue);
853 Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
854 ++FieldDecl;
855 }
856
857 return std::make_pair(Aggregate, AttrBegin);
858}
859
862 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
866
867 const llvm::StructType *ST = cast<StructType>(Source->getType());
868
869 const clang::RecordDecl *RD = nullptr;
870 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
872 else
873 RD = Decl->getType()->getAsRecordDecl();
874 assert(RD);
875
876 assert(RD->getNumFields() == ST->getNumElements());
877
878 auto FieldDecl = RD->field_begin();
879 for (unsigned I = 0; I < ST->getNumElements(); ++I) {
880 llvm::Value *Extract = B.CreateExtractValue(Source, I);
881 AttrBegin =
882 handleSemanticStore(B, FD, Extract, *FieldDecl, AttrBegin, AttrEnd);
883 }
884
885 return AttrBegin;
886}
887
888std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
890 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
894 assert(AttrBegin != AttrEnd);
895 if (Type->isStructTy())
896 return handleStructSemanticLoad(B, FD, Type, Decl, AttrBegin, AttrEnd);
897
898 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
899 ++AttrBegin;
900 return std::make_pair(handleScalarSemanticLoad(B, FD, Type, Decl, Attr),
901 AttrBegin);
902}
903
906 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
910 assert(AttrBegin != AttrEnd);
911 if (Source->getType()->isStructTy())
912 return handleStructSemanticStore(B, FD, Source, Decl, AttrBegin, AttrEnd);
913
914 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
915 ++AttrBegin;
916 handleScalarSemanticStore(B, FD, Source, Decl, Attr);
917 return AttrBegin;
918}
919
921 llvm::Function *Fn) {
922 llvm::Module &M = CGM.getModule();
923 llvm::LLVMContext &Ctx = M.getContext();
924 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
925 Function *EntryFn =
926 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
927
928 // Copy function attributes over, we have no argument or return attributes
929 // that can be valid on the real entry.
930 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
931 Fn->getAttributes().getFnAttrs());
932 EntryFn->setAttributes(NewAttrs);
933 setHLSLEntryAttributes(FD, EntryFn);
934
935 // Set the called function as internal linkage.
936 Fn->setLinkage(GlobalValue::InternalLinkage);
937
938 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
939 IRBuilder<> B(BB);
941
943 if (CGM.shouldEmitConvergenceTokens()) {
944 assert(EntryFn->isConvergent());
945 llvm::Value *I =
946 B.CreateIntrinsic(llvm::Intrinsic::experimental_convergence_entry, {});
947 llvm::Value *bundleArgs[] = {I};
948 OB.emplace_back("convergencectrl", bundleArgs);
949 }
950
951 llvm::DenseMap<const DeclaratorDecl *, llvm::Value *> OutputSemantic;
952
953 unsigned SRetOffset = 0;
954 for (const auto &Param : Fn->args()) {
955 if (Param.hasStructRetAttr()) {
956 SRetOffset = 1;
957 llvm::Type *VarType = Param.getParamStructRetType();
958 llvm::Value *Var = B.CreateAlloca(VarType);
959 OutputSemantic.try_emplace(FD, Var);
960 Args.push_back(Var);
961 continue;
962 }
963
964 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
965 llvm::Value *SemanticValue = nullptr;
966 // FIXME: support inout/out parameters for semantics.
967 if ([[maybe_unused]] HLSLParamModifierAttr *MA =
968 PD->getAttr<HLSLParamModifierAttr>()) {
969 llvm_unreachable("Not handled yet");
970 } else {
971 llvm::Type *ParamType =
972 Param.hasByValAttr() ? Param.getParamByValType() : Param.getType();
973 auto AttrBegin = PD->specific_attr_begin<HLSLAppliedSemanticAttr>();
974 auto AttrEnd = PD->specific_attr_end<HLSLAppliedSemanticAttr>();
975 auto Result =
976 handleSemanticLoad(B, FD, ParamType, PD, AttrBegin, AttrEnd);
977 SemanticValue = Result.first;
978 if (!SemanticValue)
979 return;
980 if (Param.hasByValAttr()) {
981 llvm::Value *Var = B.CreateAlloca(Param.getParamByValType());
982 B.CreateStore(SemanticValue, Var);
983 SemanticValue = Var;
984 }
985 }
986
987 assert(SemanticValue);
988 Args.push_back(SemanticValue);
989 }
990
991 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
992 CI->setCallingConv(Fn->getCallingConv());
993
994 if (Fn->getReturnType() != CGM.VoidTy)
995 OutputSemantic.try_emplace(FD, CI);
996
997 for (auto &[Decl, Source] : OutputSemantic) {
998 AllocaInst *AI = dyn_cast<AllocaInst>(Source);
999 llvm::Value *SourceValue =
1000 AI ? B.CreateLoad(AI->getAllocatedType(), Source) : Source;
1001
1002 auto AttrBegin = Decl->specific_attr_begin<HLSLAppliedSemanticAttr>();
1003 auto AttrEnd = Decl->specific_attr_end<HLSLAppliedSemanticAttr>();
1004 handleSemanticStore(B, FD, SourceValue, Decl, AttrBegin, AttrEnd);
1005 }
1006
1007 B.CreateRetVoid();
1008
1009 // Add and identify root signature to function, if applicable
1010 for (const Attr *Attr : FD->getAttrs()) {
1011 if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) {
1012 auto *RSDecl = RSAttr->getSignatureDecl();
1013 addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
1014 EntryFn, M);
1015 }
1016 }
1017}
1018
1019static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
1020 bool CtorOrDtor) {
1021 const auto *GV =
1022 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
1023 if (!GV)
1024 return;
1025 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
1026 if (!CA)
1027 return;
1028 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
1029 // HLSL neither supports priorities or COMDat values, so we will check those
1030 // in an assert but not handle them.
1031
1032 for (const auto &Ctor : CA->operands()) {
1034 continue;
1035 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
1036
1037 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
1038 "HLSL doesn't support setting priority for global ctors.");
1039 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
1040 "HLSL doesn't support COMDat for global ctors.");
1041 Fns.push_back(cast<Function>(CS->getOperand(1)));
1042 }
1043}
1044
1046 llvm::Module &M = CGM.getModule();
1049 gatherFunctions(CtorFns, M, true);
1050 gatherFunctions(DtorFns, M, false);
1051
1052 // Insert a call to the global constructor at the beginning of the entry block
1053 // to externally exported functions. This is a bit of a hack, but HLSL allows
1054 // global constructors, but doesn't support driver initialization of globals.
1055 for (auto &F : M.functions()) {
1056 if (!F.hasFnAttribute("hlsl.shader"))
1057 continue;
1058 auto *Token = getConvergenceToken(F.getEntryBlock());
1059 Instruction *IP = &*F.getEntryBlock().begin();
1061 if (Token) {
1062 llvm::Value *bundleArgs[] = {Token};
1063 OB.emplace_back("convergencectrl", bundleArgs);
1064 IP = Token->getNextNode();
1065 }
1066 IRBuilder<> B(IP);
1067 for (auto *Fn : CtorFns) {
1068 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1069 CI->setCallingConv(Fn->getCallingConv());
1070 }
1071
1072 // Insert global dtors before the terminator of the last instruction
1073 B.SetInsertPoint(F.back().getTerminator());
1074 for (auto *Fn : DtorFns) {
1075 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1076 CI->setCallingConv(Fn->getCallingConv());
1077 }
1078 }
1079
1080 // No need to keep global ctors/dtors for non-lib profile after call to
1081 // ctors/dtors added for entry.
1082 Triple T(M.getTargetTriple());
1083 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
1084 if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
1085 GV->eraseFromParent();
1086 if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
1087 GV->eraseFromParent();
1088 }
1089}
1090
1091static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
1092 Intrinsic::ID IntrID,
1094
1095 LLVMContext &Ctx = CGM.getLLVMContext();
1096 llvm::Function *InitResFunc = llvm::Function::Create(
1097 llvm::FunctionType::get(CGM.VoidTy, false),
1098 llvm::GlobalValue::InternalLinkage,
1099 ("_init_buffer_" + GV->getName()).str(), CGM.getModule());
1100 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1101
1102 llvm::BasicBlock *EntryBB =
1103 llvm::BasicBlock::Create(Ctx, "entry", InitResFunc);
1104 CGBuilderTy Builder(CGM, Ctx);
1105 const DataLayout &DL = CGM.getModule().getDataLayout();
1106 Builder.SetInsertPoint(EntryBB);
1107
1108 // Make sure the global variable is buffer resource handle
1109 llvm::Type *HandleTy = GV->getValueType();
1110 assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");
1111
1112 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
1113 /*ReturnType=*/HandleTy, IntrID, Args, nullptr,
1114 Twine(GV->getName()).concat("_h"));
1115
1116 llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
1117 Builder.CreateAlignedStore(CreateHandle, HandleRef,
1118 HandleRef->getPointerAlignment(DL));
1119 Builder.CreateRetVoid();
1120
1121 CGM.AddCXXGlobalInit(InitResFunc);
1122}
1123
1124void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
1125 llvm::GlobalVariable *GV) {
1126 ResourceBindingAttrs Binding(BufDecl);
1127 assert(Binding.hasBinding() &&
1128 "cbuffer/tbuffer should always have resource binding attribute");
1129
1130 auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
1131 auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
1132 auto *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
1133 Value *Name = buildNameForResource(BufDecl->getName(), CGM);
1134
1135 // buffer with explicit binding
1136 if (Binding.isExplicit()) {
1137 llvm::Intrinsic::ID IntrinsicID =
1138 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
1139 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
1140 SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
1141 initializeBuffer(CGM, GV, IntrinsicID, Args);
1142 } else {
1143 // buffer with implicit binding
1144 llvm::Intrinsic::ID IntrinsicID =
1145 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
1146 auto *OrderID =
1147 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
1148 SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
1149 initializeBuffer(CGM, GV, IntrinsicID, Args);
1150 }
1151}
1152
1154 llvm::GlobalVariable *GV) {
1155 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
1156 addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
1157}
1158
1159llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
1160 if (!CGM.shouldEmitConvergenceTokens())
1161 return nullptr;
1162
1163 auto E = BB.end();
1164 for (auto I = BB.begin(); I != E; ++I) {
1165 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
1166 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
1167 return II;
1168 }
1169 }
1170 llvm_unreachable("Convergence token should have been emitted.");
1171 return nullptr;
1172}
1173
1174class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
1175public:
1179
1181 // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
1182 // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
1183 // traversal, the temporary containing the copy out will not have
1184 // been created yet.
1185 return false;
1186 }
1187
1189 // Traverse the source expression first.
1190 if (E->getSourceExpr())
1192
1193 // Then add this OVE if we haven't seen it before.
1194 if (Visited.insert(E).second)
1195 OVEs.push_back(E);
1196
1197 return true;
1198 }
1199};
1200
1202 InitListExpr *E) {
1203
1204 typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
1205 OpaqueValueVisitor Visitor;
1206 Visitor.TraverseStmt(E);
1207 for (auto *OVE : Visitor.OVEs) {
1208 if (CGF.isOpaqueValueEmitted(OVE))
1209 continue;
1210 if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
1211 LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
1212 OpaqueValueMappingData::bind(CGF, OVE, LV);
1213 } else {
1214 RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
1215 OpaqueValueMappingData::bind(CGF, OVE, RV);
1216 }
1217 }
1218}
1219
1221 const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
1222 assert((ArraySubsExpr->getType()->isHLSLResourceRecord() ||
1223 ArraySubsExpr->getType()->isHLSLResourceRecordArray()) &&
1224 "expected resource array subscript expression");
1225
1226 // Let clang codegen handle local and static resource array subscripts,
1227 // or when the subscript references on opaque expression (as part of
1228 // ArrayInitLoopExpr AST node).
1229 const VarDecl *ArrayDecl =
1230 dyn_cast_or_null<VarDecl>(getArrayDecl(ArraySubsExpr));
1231 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
1232 ArrayDecl->getStorageClass() == SC_Static)
1233 return std::nullopt;
1234
1235 // get the resource array type
1236 ASTContext &AST = ArrayDecl->getASTContext();
1237 const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
1238 assert(ResArrayTy->isHLSLResourceRecordArray() &&
1239 "expected array of resource classes");
1240
1241 // Iterate through all nested array subscript expressions to calculate
1242 // the index in the flattened resource array (if this is a multi-
1243 // dimensional array). The index is calculated as a sum of all indices
1244 // multiplied by the total size of the array at that level.
1245 Value *Index = nullptr;
1246 const ArraySubscriptExpr *ASE = ArraySubsExpr;
1247 while (ASE != nullptr) {
1248 Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
1249 if (const auto *ArrayTy =
1250 dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
1251 Value *Multiplier = llvm::ConstantInt::get(
1252 CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy));
1253 SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
1254 }
1255 Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
1256 ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
1257 }
1258
1259 // Find binding info for the resource array. For implicit binding
1260 // an HLSLResourceBindingAttr should have been added by SemaHLSL.
1261 ResourceBindingAttrs Binding(ArrayDecl);
1262 assert(Binding.hasBinding() &&
1263 "resource array must have a binding attribute");
1264
1265 // Find the individual resource type.
1266 QualType ResultTy = ArraySubsExpr->getType();
1267 QualType ResourceTy =
1268 ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy;
1269
1270 // Create a temporary variable for the result, which is either going
1271 // to be a single resource instance or a local array of resources (we need to
1272 // return an LValue).
1273 RawAddress TmpVar = CGF.CreateMemTemp(ResultTy);
1274 if (CGF.EmitLifetimeStart(TmpVar.getPointer()))
1276 NormalEHLifetimeMarker, TmpVar);
1277
1282
1283 // Calculate total array size (= range size).
1284 llvm::Value *Range = llvm::ConstantInt::getSigned(
1285 CGM.IntTy, getTotalArraySize(AST, ResArrayTy));
1286
1287 // If the result of the subscript operation is a single resource, call the
1288 // constructor.
1289 if (ResultTy == ResourceTy) {
1290 CallArgList Args;
1291 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
1292 CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
1293 ArrayDecl->getName(), Binding, Args);
1294
1295 if (!CreateMethod)
1296 // This can happen if someone creates an array of structs that looks like
1297 // an HLSL resource record array but it does not have the required static
1298 // create method. No binding will be generated for it.
1299 return std::nullopt;
1300
1301 callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
1302
1303 } else {
1304 // The result of the subscript operation is a local resource array which
1305 // needs to be initialized.
1306 const ConstantArrayType *ArrayTy =
1308 std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
1309 CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
1310 ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)},
1311 ArraySubsExpr->getExprLoc());
1312 if (!EndIndex)
1313 return std::nullopt;
1314 }
1315 return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
1316}
1317
1318// If RHSExpr is a global resource array, initialize all of its resources and
1319// set them into LHS. Returns false if no copy has been performed and the
1320// array copy should be handled by Clang codegen.
1322 CodeGenFunction &CGF) {
1323 QualType ResultTy = RHSExpr->getType();
1324 assert(ResultTy->isHLSLResourceRecordArray() && "expected resource array");
1325
1326 // Let Clang codegen handle local and static resource array copies.
1327 const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(getArrayDecl(RHSExpr));
1328 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
1329 ArrayDecl->getStorageClass() == SC_Static)
1330 return false;
1331
1332 // Find binding info for the resource array. For implicit binding
1333 // the HLSLResourceBindingAttr should have been added by SemaHLSL.
1334 ResourceBindingAttrs Binding(ArrayDecl);
1335 assert(Binding.hasBinding() &&
1336 "resource array must have a binding attribute");
1337
1338 // Find the individual resource type.
1339 ASTContext &AST = ArrayDecl->getASTContext();
1340 QualType ResTy = AST.getBaseElementType(ResultTy);
1341 const auto *ResArrayTy = cast<ConstantArrayType>(ResultTy.getTypePtr());
1342
1343 // Use the provided LHS for the result.
1348
1349 // Create Value for index and total array size (= range size).
1350 int Size = getTotalArraySize(AST, ResArrayTy);
1351 llvm::Value *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
1352 llvm::Value *Range = llvm::ConstantInt::get(CGM.IntTy, Size);
1353
1354 // Initialize individual resources in the array into LHS.
1355 std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
1356 CGF, ResTy->getAsCXXRecordDecl(), ResArrayTy, ValueSlot, Range, Zero,
1357 ArrayDecl->getName(), Binding, {Zero}, RHSExpr->getExprLoc());
1358 return EndIndex.has_value();
1359}
1360
1362 const ArraySubscriptExpr *E, CodeGenFunction &CGF,
1363 llvm::function_ref<llvm::Value *(bool Promote)> EmitIdxAfterBase) {
1364 // Find the element type to index by first padding the element type per HLSL
1365 // buffer rules, and then padding out to a 16-byte register boundary if
1366 // necessary.
1367 llvm::Type *LayoutTy =
1369 uint64_t LayoutSizeInBits =
1370 CGM.getDataLayout().getTypeSizeInBits(LayoutTy).getFixedValue();
1371 CharUnits ElementSize = CharUnits::fromQuantity(LayoutSizeInBits / 8);
1372 CharUnits RowAlignedSize = ElementSize.alignTo(CharUnits::fromQuantity(16));
1373 if (RowAlignedSize > ElementSize) {
1374 llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding(
1375 CGM, RowAlignedSize - ElementSize);
1376 assert(Padding && "No padding type for target?");
1377 LayoutTy = llvm::StructType::get(CGF.getLLVMContext(), {LayoutTy, Padding},
1378 /*isPacked=*/true);
1379 }
1380
1381 // If the layout type doesn't introduce any padding, we don't need to do
1382 // anything special.
1383 llvm::Type *OrigTy = CGF.CGM.getTypes().ConvertTypeForMem(E->getType());
1384 if (LayoutTy == OrigTy)
1385 return std::nullopt;
1386
1387 LValueBaseInfo EltBaseInfo;
1388 TBAAAccessInfo EltTBAAInfo;
1389 Address Addr =
1390 CGF.EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
1391 llvm::Value *Idx = EmitIdxAfterBase(/*Promote*/ true);
1392
1393 // Index into the object as-if we have an array of the padded element type,
1394 // and then dereference the element itself to avoid reading padding that may
1395 // be past the end of the in-memory object.
1397 Indices.push_back(Idx);
1398 Indices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
1399
1400 llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF),
1401 Indices, "cbufferidx");
1402 Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull);
1403
1404 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
1405}
1406
1407namespace {
1408/// Utility for emitting copies following the HLSL buffer layout rules (ie,
1409/// copying out of a cbuffer).
1410class HLSLBufferCopyEmitter {
1411 CodeGenFunction &CGF;
1412 Address DestPtr;
1413 Address SrcPtr;
1414 llvm::Type *LayoutTy = nullptr;
1415
1416 SmallVector<llvm::Value *> CurStoreIndices;
1417 SmallVector<llvm::Value *> CurLoadIndices;
1418
1419 void emitCopyAtIndices(llvm::Type *FieldTy, llvm::ConstantInt *StoreIndex,
1420 llvm::ConstantInt *LoadIndex) {
1421 CurStoreIndices.push_back(StoreIndex);
1422 CurLoadIndices.push_back(LoadIndex);
1423 llvm::scope_exit RestoreIndices([&]() {
1424 CurStoreIndices.pop_back();
1425 CurLoadIndices.pop_back();
1426 });
1427
1428 // First, see if this is some kind of aggregate and recurse.
1429 if (processArray(FieldTy))
1430 return;
1431 if (processBufferLayoutArray(FieldTy))
1432 return;
1433 if (processStruct(FieldTy))
1434 return;
1435
1436 // When we have a scalar or vector element we can emit the copy.
1438 CGF.CGM.getDataLayout().getABITypeAlign(FieldTy));
1439 Address SrcGEP = RawAddress(
1440 CGF.Builder.CreateInBoundsGEP(LayoutTy, SrcPtr.getBasePointer(),
1441 CurLoadIndices, "cbuf.src"),
1442 FieldTy, Align, SrcPtr.isKnownNonNull());
1443 Address DestGEP = CGF.Builder.CreateInBoundsGEP(
1444 DestPtr, CurStoreIndices, FieldTy, Align, "cbuf.dest");
1445 llvm::Value *Load = CGF.Builder.CreateLoad(SrcGEP, "cbuf.load");
1446 CGF.Builder.CreateStore(Load, DestGEP);
1447 }
1448
1449 bool processArray(llvm::Type *FieldTy) {
1450 auto *AT = dyn_cast<llvm::ArrayType>(FieldTy);
1451 if (!AT)
1452 return false;
1453
1454 // If we have an llvm::ArrayType this is just a regular array with no top
1455 // level padding, so all we need to do is copy each member.
1456 for (unsigned I = 0, E = AT->getNumElements(); I < E; ++I)
1457 emitCopyAtIndices(AT->getElementType(),
1458 llvm::ConstantInt::get(CGF.SizeTy, I),
1459 llvm::ConstantInt::get(CGF.SizeTy, I));
1460 return true;
1461 }
1462
1463 bool processBufferLayoutArray(llvm::Type *FieldTy) {
1464 // A buffer layout array is a struct with two elements: the padded array,
1465 // and the last element. That is, is should look something like this:
1466 //
1467 // { [%n x { %type, %padding }], %type }
1468 //
1469 auto *ST = dyn_cast<llvm::StructType>(FieldTy);
1470 if (!ST || ST->getNumElements() != 2)
1471 return false;
1472
1473 auto *PaddedEltsTy = dyn_cast<llvm::ArrayType>(ST->getElementType(0));
1474 if (!PaddedEltsTy)
1475 return false;
1476
1477 auto *PaddedTy = dyn_cast<llvm::StructType>(PaddedEltsTy->getElementType());
1478 if (!PaddedTy || PaddedTy->getNumElements() != 2)
1479 return false;
1480
1482 PaddedTy->getElementType(1)))
1483 return false;
1484
1485 llvm::Type *ElementTy = ST->getElementType(1);
1486 if (PaddedTy->getElementType(0) != ElementTy)
1487 return false;
1488
1489 // All but the last of the logical array elements are in the padded array.
1490 unsigned NumElts = PaddedEltsTy->getNumElements() + 1;
1491
1492 // Add an extra indirection to the load for the struct and walk the
1493 // array prefix.
1494 CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
1495 for (unsigned I = 0; I < NumElts - 1; ++I) {
1496 // We need to copy the element itself, without the padding.
1497 CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.SizeTy, I));
1498 emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.SizeTy, I),
1499 llvm::ConstantInt::get(CGF.Int32Ty, 0));
1500 CurLoadIndices.pop_back();
1501 }
1502 CurLoadIndices.pop_back();
1503
1504 // Now copy the last element.
1505 emitCopyAtIndices(ElementTy,
1506 llvm::ConstantInt::get(CGF.SizeTy, NumElts - 1),
1507 llvm::ConstantInt::get(CGF.Int32Ty, 1));
1508
1509 return true;
1510 }
1511
1512 bool processStruct(llvm::Type *FieldTy) {
1513 auto *ST = dyn_cast<llvm::StructType>(FieldTy);
1514 if (!ST)
1515 return false;
1516
1517 // Copy the struct field by field, but skip any explicit padding.
1518 unsigned Skipped = 0;
1519 for (unsigned I = 0, E = ST->getNumElements(); I < E; ++I) {
1520 llvm::Type *ElementTy = ST->getElementType(I);
1521 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(ElementTy))
1522 ++Skipped;
1523 else
1524 emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.Int32Ty, I),
1525 llvm::ConstantInt::get(CGF.Int32Ty, I + Skipped));
1526 }
1527 return true;
1528 }
1529
1530public:
1531 HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr)
1532 : CGF(CGF), DestPtr(DestPtr), SrcPtr(SrcPtr) {}
1533
1534 bool emitCopy(QualType CType) {
1535 LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(CType);
1536
1537 // TODO: We should be able to fall back to a regular memcpy if the layout
1538 // type doesn't have any padding, but that runs into issues in the backend
1539 // currently.
1540 //
1541 // See https://github.com/llvm/wg-hlsl/issues/351
1542 emitCopyAtIndices(LayoutTy, llvm::ConstantInt::get(CGF.SizeTy, 0),
1543 llvm::ConstantInt::get(CGF.SizeTy, 0));
1544 return true;
1545 }
1546};
1547} // namespace
1548
1550 Address SrcPtr, QualType CType) {
1551 return HLSLBufferCopyEmitter(CGF, DestPtr, SrcPtr).emitCopy(CType);
1552}
1553
1555 const MemberExpr *E) {
1556 LValue Base =
1558 auto *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
1559 assert(Field && "Unexpected access into HLSL buffer");
1560
1561 // Get the field index for the struct.
1562 const RecordDecl *Rec = Field->getParent();
1563 unsigned FieldIdx =
1564 CGM.getTypes().getCGRecordLayout(Rec).getLLVMFieldNo(Field);
1565
1566 // Work out the buffer layout type to index into.
1567 QualType RecType = CGM.getContext().getCanonicalTagType(Rec);
1568 assert(RecType->isStructureOrClassType() && "Invalid type in HLSL buffer");
1569 // Since this is a member of an object in the buffer and not the buffer's
1570 // struct/class itself, we shouldn't have any offsets on the members we need
1571 // to contend with.
1572 CGHLSLOffsetInfo EmptyOffsets;
1573 llvm::StructType *LayoutTy = HLSLBufferLayoutBuilder(CGM).layOutStruct(
1574 RecType->getAsCanonical<RecordType>(), EmptyOffsets);
1575
1576 // Now index into the struct, making sure that the type we return is the
1577 // buffer layout type rather than the original type in the AST.
1578 QualType FieldType = Field->getType();
1579 llvm::Type *FieldLLVMTy = CGM.getTypes().ConvertTypeForMem(FieldType);
1581 CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy));
1582 Address Addr(CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF),
1583 FieldIdx, Field->getName()),
1584 FieldLLVMTy, Align, KnownNonNull);
1585
1586 LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(),
1588 CGM.getTBAAAccessInfo(FieldType));
1589 LV.getQuals().addCVRQualifiers(Base.getVRQualifiers());
1590
1591 return LV;
1592}
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:3735
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:551
Address getAddress() const
Definition CGValue.h:691
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:634
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:267
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:1575
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK)
Same as EmitLValue but additionally we generate checking code to guard against undefined behavior.
Definition CGExpr.cpp:1656
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:189
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:1691
bool isOpaqueValueEmitted(const OpaqueValueExpr *E)
isOpaqueValueEmitted - Return true if the opaque value expression has already been emitted.
Definition CGExpr.cpp:6164
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:454
const Qualifiers & getQuals() const
Definition CGValue.h:350
Address getAddress() const
Definition CGValue.h:373
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:3761
int64_t getSExtSize() const
Return the size sign-extended as a uint64_t.
Definition TypeBase.h:3843
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:5269
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5193
bool isCBuffer() const
Definition Decl.h:5237
const CXXRecordDecl * getLayoutStruct() const
Definition Decl.h:5240
bool hasValidPackoffset() const
Definition Decl.h:5239
buffer_decl_range buffer_decls() const
Definition Decl.h:5268
This class represents temporary values used to represent inout and out arguments in HLSL.
Definition Expr.h:7349
ArrayRef< llvm::hlsl::rootsig::RootElement > getRootElements() const
Definition Decl.h:5310
llvm::dxbc::RootSignatureVersion getVersion() const
Definition Decl.h:5308
Describes an C or C++ initializer list.
Definition Expr.h:5299
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3364
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3447
Expr * getBase() const
Definition Expr.h:3441
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:8292
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8418
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:4324
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
Definition Decl.h:4540
field_iterator field_begin() const
Definition Decl.cpp:5270
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:8636
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:8628
bool isHLSLResourceRecord() const
Definition Type.cpp:5363
bool isStructureOrClassType() const
Definition Type.cpp:707
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2922
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9111
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:654
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5367
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