clang 24.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/Attr.h"
24#include "clang/AST/Decl.h"
25#include "clang/AST/Expr.h"
28#include "clang/AST/Type.h"
33#include "llvm/ADT/DenseMap.h"
34#include "llvm/ADT/STLExtras.h"
35#include "llvm/ADT/ScopeExit.h"
36#include "llvm/ADT/SmallString.h"
37#include "llvm/ADT/SmallVector.h"
38#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
39#include "llvm/IR/Constants.h"
40#include "llvm/IR/DerivedTypes.h"
41#include "llvm/IR/GlobalVariable.h"
42#include "llvm/IR/IntrinsicInst.h"
43#include "llvm/IR/LLVMContext.h"
44#include "llvm/IR/Metadata.h"
45#include "llvm/IR/Module.h"
46#include "llvm/IR/Type.h"
47#include "llvm/IR/Value.h"
48#include "llvm/Support/Alignment.h"
49#include "llvm/Support/ErrorHandling.h"
50#include "llvm/Support/FormatVariadic.h"
51#include "llvm/Support/Path.h"
52#include "llvm/Transforms/Utils/ModuleUtils.h"
53#include <cstdint>
54#include <optional>
55
56using namespace clang;
57using namespace CodeGen;
58using namespace clang::hlsl;
59using namespace llvm;
60
61using llvm::hlsl::CBufferRowSizeInBytes;
62
63namespace {
64
65void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
66 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
67 // Assume ValVersionStr is legal here.
68 VersionTuple Version;
69 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
70 Version.getSubminor() || !Version.getMinor()) {
71 return;
72 }
73
74 uint64_t Major = Version.getMajor();
75 uint64_t Minor = *Version.getMinor();
76
77 auto &Ctx = M.getContext();
78 IRBuilder<> B(M.getContext());
79 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
80 ConstantAsMetadata::get(B.getInt32(Minor))});
81 StringRef DXILValKey = "dx.valver";
82 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
83 DXILValMD->addOperand(Val);
84}
85
86void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
88 llvm::Function *Fn, llvm::Module &M) {
89 auto &Ctx = M.getContext();
90
91 llvm::hlsl::rootsig::MetadataBuilder RSBuilder(Ctx, Elements);
92 MDNode *RootSignature = RSBuilder.BuildRootSignature();
93
94 ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get(
95 llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer)));
96 ValueAsMetadata *EntryFunc = Fn ? ValueAsMetadata::get(Fn) : nullptr;
97 MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version});
98
99 StringRef RootSignatureValKey = "dx.rootsignatures";
100 auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey);
101 RootSignatureValMD->addOperand(MDVals);
102}
103
104static void copyGlobalResource(CodeGenFunction &CGF, const VarDecl *ResourceVD,
105 AggValueSlot &DestSlot) {
106 GlobalVariable *ResGV =
108 assert(ResGV && "expected valid global variable");
109 CGF.Builder.CreateStore(ResGV, DestSlot.getAddress());
110}
111
112// Given a MemberExpr of a resource or resource array type, find the parent
113// VarDecl of the struct or class instance that contains this resource and
114// build the full resource name based on the member access path.
115//
116// For example, for a member access like "myStructArray[0].memberA",
117// this function will find the VarDecl of "myStructArray" and use the
118// EmbeddedResourceNameBuilder to build the resource name
119// "myStructArray.0.memberA".
120//
121// This also works for a record type expression that has some embedded
122// resources. It finds the parent VarDecl of that record and builds a partial
123// name which is the prefix of the resource globals associated with the
124// declaration.
125static const VarDecl *findStructResourceParentDeclAndBuildName(
126 const Expr *E, EmbeddedResourceNameBuilder &NameBuilder) {
127
129 const VarDecl *VD = nullptr;
130
131 for (;;) {
132 if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
133 assert(isa<VarDecl>(DRE->getDecl()) &&
134 "member expr base is not a var decl");
135 VD = cast<VarDecl>(DRE->getDecl());
136 NameBuilder.pushName(VD->getName());
137 break;
138 }
139
140 WorkList.push_back(E);
141 if (const auto *MExp = dyn_cast<MemberExpr>(E))
142 E = MExp->getBase();
143 else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
144 E = ICE->getSubExpr();
145 else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
146 E = ASE->getBase();
147 else if (isa<CXXThisExpr>(E))
148 // Resource member access on "this" pointer not yet implemented
149 // (llvm/llvm-project#190299)
150 return nullptr;
151 else
152 llvm_unreachable("unexpected expr type in resource member access");
153
154 assert(E && "expected valid expression");
155 }
156
157 while (!WorkList.empty()) {
158 E = WorkList.pop_back_val();
159 if (const auto *ME = dyn_cast<MemberExpr>(E)) {
160 NameBuilder.pushName(
161 ME->getMemberNameInfo().getName().getAsIdentifierInfo()->getName());
162 } else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
163 if (ICE->getCastKind() == CK_UncheckedDerivedToBase) {
164 CXXRecordDecl *DerivedRD =
165 ICE->getSubExpr()->getType()->getAsCXXRecordDecl();
166 CXXRecordDecl *BaseRD = ICE->getType()->getAsCXXRecordDecl();
167 NameBuilder.pushBaseNameHierarchy(DerivedRD, BaseRD);
168 }
169 } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
170 const Expr *IdxExpr = ASE->getIdx();
171 std::optional<llvm::APSInt> Value =
173 assert(Value &&
174 "expected constant index in struct with resource array access");
175 NameBuilder.pushArrayIndex(Value->getZExtValue());
176 } else {
177 llvm_unreachable("unexpected expr type in resource member access");
178 }
179 }
180 return VD;
181}
182
183// Given a MemberExpr of a resource or resource array type, find the
184// corresponding global resource declaration associated with the owning struct
185// or class instance via HLSLAssociatedResourceDeclAttr.
186static const VarDecl *
187findAssociatedResourceDeclForStruct(ASTContext &AST, const MemberExpr *ME) {
188
189 EmbeddedResourceNameBuilder NameBuilder;
190 const VarDecl *ParentVD =
191 findStructResourceParentDeclAndBuildName(ME, NameBuilder);
192 if (!ParentVD)
193 return nullptr;
194
195 if (!ParentVD->hasGlobalStorage())
196 return nullptr;
197
198 IdentifierInfo *II = NameBuilder.getNameAsIdentifier(AST);
199 for (const Attr *A : ParentVD->getAttrs()) {
200 if (const auto *ADA = dyn_cast<HLSLAssociatedResourceDeclAttr>(A)) {
201 VarDecl *AssocResVD = ADA->getResDecl();
202 if (AssocResVD->getIdentifier() == II)
203 return AssocResVD;
204 }
205 }
206 return nullptr;
207}
208
209void addSourceInfo(CodeGenModule &CGM, llvm::Module &M) {
210 auto &SM = CGM.getContext().getSourceManager();
211 auto &Macros = CGM.getPreprocessorOpts().Macros;
212 auto &CodeGenOpts = CGM.getCodeGenOpts();
213 auto &Ctx = M.getContext();
214
215 // Names and content of shader source code files.
216 llvm::NamedMDNode *DXContents =
217 M.getOrInsertNamedMetadata("dx.source.contents");
218 auto addFile = [&](const std::pair<StringRef, StringRef> &NameContent) {
219 llvm::MDTuple *FileInfo =
220 llvm::MDNode::get(Ctx, {llvm::MDString::get(Ctx, NameContent.first),
221 llvm::MDString::get(Ctx, NameContent.second)});
222 DXContents->addOperand(FileInfo);
223 };
224
225 bool Invalid = false;
226 const SrcMgr::SLocEntry *MainLocEntry =
227 &SM.getSLocEntry(SM.getMainFileID(), &Invalid);
228 assert(!Invalid && "Main file SLocEntry must not be invalid!");
229 const SrcMgr::ContentCache &MainCCEntry =
230 MainLocEntry->getFile().getContentCache();
231
233 std::optional<SmallString<256>> MainFileName;
234 Files.reserve(SM.local_sloc_entry_size());
235 for (unsigned I : llvm::seq(SM.local_sloc_entry_size())) {
236 const SrcMgr::SLocEntry &LocEntry = SM.getLocalSLocEntry(I);
237 if (!LocEntry.isFile())
238 continue;
239
240 const SrcMgr::FileInfo &FInfo = LocEntry.getFile();
241 if (isSystem(FInfo.getFileCharacteristic()))
242 continue;
243
244 const SrcMgr::ContentCache &CCEntry = FInfo.getContentCache();
245 OptionalFileEntryRef FEntry = CCEntry.OrigEntry;
246 if (!FEntry)
247 continue;
248
249 llvm::SmallString<256> Path = FEntry->getName();
250 llvm::sys::path::native(Path);
251 std::optional<llvm::MemoryBufferRef> Buffer = CCEntry.getBufferOrNone(
252 SM.getDiagnostics(), SM.getFileManager(), SourceLocation());
253 if (!Buffer) {
254 SM.getDiagnostics().Report(diag::warn_hlsl_failed_to_embed_source)
255 << Path;
256 continue;
257 }
258
259 if (&MainCCEntry != &CCEntry) {
260 Files.emplace_back(Path, Buffer->getBuffer());
261 } else {
262 // Main file should be at first position.
263 addFile(std::make_pair(Path, Buffer->getBuffer()));
264 MainFileName.emplace(Path);
265 }
266 }
267 assert(MainFileName && "Main file not found.");
268
269 // Files other that main one should be sorted by name.
270 llvm::sort(Files);
271#ifndef NDEBUG
272 for (unsigned I = 1; I < Files.size(); ++I)
273 assert((Files[I - 1].first != Files[I].first) &&
274 "duplicate files in dx.source.contents");
275#endif
276 llvm::for_each(Files, addFile);
277
279 Defines.reserve(Macros.size());
280 for (const auto &Macro : Macros) {
281 // Ignore undefs.
282 if (!Macro.second)
283 Defines.emplace_back(llvm::MDString::get(Ctx, Macro.first));
284 }
285 M.getOrInsertNamedMetadata("dx.source.defines")
286 ->addOperand(llvm::MDNode::get(Ctx, Defines));
287
288 if (!CodeGenOpts.MainFileName.empty())
289 llvm::sys::path::native(CodeGenOpts.MainFileName, *MainFileName);
290 M.getOrInsertNamedMetadata("dx.source.mainFileName")
291 ->addOperand(
292 llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, *MainFileName)));
293
295 Args.reserve(CodeGenOpts.HLSLParsedCommandLine.size());
296 if (!CodeGenOpts.HLSLParsedCommandLine.empty())
297 for (const auto &Arg : llvm::drop_begin(CodeGenOpts.HLSLParsedCommandLine))
298 Args.push_back(llvm::MDString::get(Ctx, Arg));
299 M.getOrInsertNamedMetadata("dx.source.args")
300 ->addOperand(llvm::MDNode::get(Ctx, Args));
301}
302
303// Find array variable declaration from DeclRef expression
304static const ValueDecl *getArrayDecl(ASTContext &AST, const Expr *E) {
305 E = E->IgnoreImpCasts();
306 if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(E))
307 return DRE->getDecl();
308 if (auto *OVE = dyn_cast<OpaqueValueExpr>(E))
309 E = OVE->getSourceExpr()->IgnoreImpCasts();
310 if (isa<MemberExpr>(E))
311 return findAssociatedResourceDeclForStruct(AST, cast<MemberExpr>(E));
312 return nullptr;
313}
314
315// Find array variable declaration from nested array subscript AST nodes
316static const ValueDecl *getArrayDecl(ASTContext &AST,
317 const ArraySubscriptExpr *ASE) {
318 const Expr *E = nullptr;
319 while (ASE != nullptr) {
320 E = ASE->getBase()->IgnoreImpCasts();
321 if (!E)
322 return nullptr;
323 ASE = dyn_cast<ArraySubscriptExpr>(E);
324 }
325 return getArrayDecl(AST, E);
326}
327
328// Get the total size of the array, or 0 if the array is unbounded.
329static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) {
331 assert(Ty->isArrayType() && "expected array type");
332 if (Ty->isIncompleteArrayType())
333 return 0;
335}
336
337static Value *buildNameForResource(llvm::StringRef BaseName,
338 CodeGenModule &CGM) {
339 llvm::SmallString<64> GlobalName = {BaseName, ".str"};
340 return CGM.GetAddrOfConstantCString(BaseName.str(), GlobalName.c_str())
341 .getPointer();
342}
343
344static CXXMethodDecl *lookupMethod(CXXRecordDecl *Record, StringRef Name,
345 StorageClass SC = SC_None) {
346 for (auto *Method : Record->methods()) {
347 if (Method->getStorageClass() == SC && Method->getName() == Name)
348 return Method;
349 }
350 return nullptr;
351}
352
353static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
354 CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range,
355 llvm::Value *Index, StringRef Name, ResourceBindingAttrs &Binding,
356 CallArgList &Args) {
357 assert(Binding.hasBinding() && "at least one binding attribute expected");
358
359 ASTContext &AST = CGM.getContext();
360 CXXMethodDecl *CreateMethod = nullptr;
361 Value *NameStr = buildNameForResource(Name, CGM);
362 Value *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
363
364 bool HasCounter = hasCounterHandle(ResourceDecl);
365 assert((!HasCounter || Binding.hasCounterImplicitOrderID()) &&
366 "resources with counter handle must have a binding with counter "
367 "implicit order ID");
368 if (Binding.isExplicit()) {
369 // explicit binding
370 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
371 Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
372 const char *Name = Binding.hasCounterImplicitOrderID()
373 ? "__createFromBindingWithImplicitCounter"
374 : "__createFromBinding";
375 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
376 } else {
377 // implicit binding
378 auto *OrderID =
379 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
380 Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
381 const char *Name = Binding.hasCounterImplicitOrderID()
382 ? "__createFromImplicitBindingWithImplicitCounter"
383 : "__createFromImplicitBinding";
384 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
385 }
386 Args.add(RValue::get(Space), AST.UnsignedIntTy);
387 Args.add(RValue::get(Range), AST.IntTy);
388 Args.add(RValue::get(Index), AST.UnsignedIntTy);
389 Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst()));
390 if (HasCounter) {
391 uint32_t CounterBinding = Binding.getCounterImplicitOrderID();
392 auto *CounterOrderID = llvm::ConstantInt::get(CGM.IntTy, CounterBinding);
393 Args.add(RValue::get(CounterOrderID), AST.UnsignedIntTy);
394 }
395
396 return CreateMethod;
397}
398
399static void callResourceInitMethod(CodeGenFunction &CGF,
400 CXXMethodDecl *CreateMethod,
401 CallArgList &Args, Address ReturnAddress) {
402 llvm::Constant *CalleeFn = CGF.CGM.GetAddrOfFunction(CreateMethod);
403 const FunctionProtoType *Proto =
404 CreateMethod->getType()->getAs<FunctionProtoType>();
405 // HLSL code generation is restricted to DXIL and SPIR-V targets, so no
406 // caller declaration is needed for x86 SysV ABI selection.
408 Args, Proto, false, /*ABIInfoFD=*/nullptr);
409 ReturnValueSlot ReturnValue(ReturnAddress, false);
410 CGCallee Callee(CGCalleeInfo(Proto), CalleeFn);
411 CGF.EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr);
412}
413
414// Initializes local resource array variable with global resource array
415// elements. For multi-dimensional arrays it calls itself recursively to
416// initialize its sub-arrays. The Index used in the resource constructor calls
417// will begin at StartIndex and will be incremented for each array element. The
418// last used resource Index is returned to the caller. If the function returns
419// std::nullopt, it indicates an error.
420static std::optional<llvm::Value *> initializeResourceArrayFromGlobal(
421 CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl,
422 const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot,
423 llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
424 ResourceBindingAttrs &Binding, ArrayRef<llvm::Value *> PrevGEPIndices) {
425
426 ASTContext &AST = CGF.getContext();
427 llvm::IntegerType *IntTy = CGF.CGM.IntTy;
428 llvm::Value *Index = StartIndex;
429 llvm::Value *One = llvm::ConstantInt::get(IntTy, 1);
430 const uint64_t ArraySize = ArrayTy->getSExtSize();
431 QualType ElemType = ArrayTy->getElementType();
432 Address TmpArrayAddr = ValueSlot.getAddress();
433
434 // Add additional index to the getelementptr call indices.
435 // This index will be updated for each array element in the loops below.
436 SmallVector<llvm::Value *> GEPIndices(PrevGEPIndices);
437 GEPIndices.push_back(llvm::ConstantInt::get(IntTy, 0));
438
439 // For array of arrays, recursively initialize the sub-arrays.
440 if (ElemType->isArrayType()) {
441 const ConstantArrayType *SubArrayTy = cast<ConstantArrayType>(ElemType);
442 for (uint64_t I = 0; I < ArraySize; I++) {
443 if (I > 0) {
444 Index = CGF.Builder.CreateAdd(Index, One);
445 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
446 }
447 std::optional<llvm::Value *> MaybeIndex =
448 initializeResourceArrayFromGlobal(CGF, ResourceDecl, SubArrayTy,
449 ValueSlot, Range, Index,
450 ResourceName, Binding, GEPIndices);
451 if (!MaybeIndex)
452 return std::nullopt;
453 Index = *MaybeIndex;
454 }
455 return Index;
456 }
457
458 // For array of resources, initialize each resource in the array.
459 llvm::Type *Ty = CGF.ConvertTypeForMem(ElemType);
460 CharUnits ElemSize = AST.getTypeSizeInChars(ElemType);
461 CharUnits Align =
462 TmpArrayAddr.getAlignment().alignmentOfArrayElement(ElemSize);
463
464 for (uint64_t I = 0; I < ArraySize; I++) {
465 if (I > 0) {
466 Index = CGF.Builder.CreateAdd(Index, One);
467 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
468 }
469 Address ReturnAddress =
470 CGF.Builder.CreateGEP(TmpArrayAddr, GEPIndices, Ty, Align);
471
472 CallArgList Args;
473 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
474 CGF.CGM, ResourceDecl, Range, Index, ResourceName, Binding, Args);
475
476 if (!CreateMethod)
477 // This can happen if someone creates an array of structs that looks like
478 // an HLSL resource record array but it does not have the required static
479 // create method. No binding will be generated for it.
480 return std::nullopt;
481
482 callResourceInitMethod(CGF, CreateMethod, Args, ReturnAddress);
483 }
484 return Index;
485}
486
487/// Utility for emitting copies following the HLSL buffer layout rules (ie,
488/// copying out of a cbuffer).
489class HLSLBufferCopyEmitter {
490 CodeGenFunction &CGF;
491 Address DstPtr;
492 Address SrcPtr;
493 llvm::Type *LayoutTy = nullptr;
494
495 SmallVector<llvm::Value *> CurStoreIndices;
496 SmallVector<llvm::Value *> CurLoadIndices;
497
498 using EmitResourceFnTy = llvm::function_ref<void(AggValueSlot &)>;
499
500 // Creates & returns either a structured.gep or a ptradd/gep depending on
501 // langopts.
502 llvm::Value *emitAccessChain(llvm::Type *BaseTy, llvm::Value *Base,
503 ArrayRef<llvm::Value *> Indices) {
504 bool EmitLogical = CGF.getLangOpts().EmitLogicalPointer;
505 if (EmitLogical)
506 return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, Indices);
507
508 llvm::SmallVector<llvm::Value *> GEPIndices;
509 GEPIndices.reserve(Indices.size() + 1);
510 GEPIndices.push_back(llvm::ConstantInt::get(CGF.IntTy, 0));
511 GEPIndices.append(Indices.begin(), Indices.end());
512 return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, GEPIndices);
513 }
514
515 bool isBufferLayoutArray(llvm::StructType *ST) {
516 // A buffer layout array is a struct with two elements: the padded array,
517 // and the last element. That is, is should look something like this:
518 //
519 // { [%n x { %type, %padding }], %type }
520 //
521 if (!ST || ST->getNumElements() != 2)
522 return false;
523
524 auto *PaddedEltsTy = dyn_cast<llvm::ArrayType>(ST->getElementType(0));
525 if (!PaddedEltsTy)
526 return false;
527
528 auto *PaddedTy = dyn_cast<llvm::StructType>(PaddedEltsTy->getElementType());
529 if (!PaddedTy || PaddedTy->getNumElements() != 2)
530 return false;
531
532 if (!CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(
533 PaddedTy->getElementType(1)))
534 return false;
535
536 llvm::Type *ElementTy = ST->getElementType(1);
537 if (PaddedTy->getElementType(0) != ElementTy)
538 return false;
539 return true;
540 }
541
542 // Returns true if the type is either a struct representing a resource record,
543 // or an array of structs that are resource records. This assumes a struct is
544 // a resource record if the first element is a target type (resource handle).
545 // This is the case for all target types used by HLSL except the padding type
546 // ("{dx|spirv.Padding"), but padding will never be the first element of a
547 // struct.
548 bool isResourceOrResourceArray(llvm::Type *Ty) {
549 while (auto *AT = dyn_cast<llvm::ArrayType>(Ty))
550 Ty = AT->getElementType();
551
552 auto *ST = dyn_cast<llvm::StructType>(Ty);
553 if (!ST || ST->getNumElements() < 1)
554 return false;
555
556 auto *TargetTy = dyn_cast<llvm::TargetExtType>(ST->getElementType(0));
557 return TargetTy != nullptr;
558 }
559
560 void emitResourceOrResourceArray(Value *Dst, llvm::Type *DstTy,
561 EmitResourceFnTy EmitResFn) {
562 CharUnits DstAlign =
563 CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(DstTy));
564 Address DstAddr(Dst, DstTy, DstAlign);
565 AggValueSlot Slot = AggValueSlot::forAddr(
566 DstAddr, Qualifiers(), AggValueSlot::IsDestructed_t(true),
569
570 EmitResFn(Slot);
571 }
572
573 void emitBufferLayoutCopy(Value *Src, llvm::StructType *SrcTy, Value *Dst,
574 llvm::ArrayType *DstTy,
575 EmitResourceFnTy EmitResFn) {
576 // Those assumptions are checked by isBufferLayoutArray.
577 auto *SrcPaddedArrayTy = cast<llvm::ArrayType>(SrcTy->getElementType(0));
578 assert(SrcPaddedArrayTy->getNumElements() + 1 == DstTy->getNumElements());
579 assert(cast<llvm::StructType>(SrcPaddedArrayTy->getElementType())
580 ->getElementType(0) == SrcTy->getElementType(1));
581
582 auto *SrcDataTy = SrcTy->getElementType(1);
583 auto Zero = llvm::ConstantInt::get(CGF.IntTy, 0);
584
585 for (unsigned I = 0; I < SrcPaddedArrayTy->getNumElements(); ++I) {
586 auto Index = llvm::ConstantInt::get(CGF.IntTy, I);
587 auto *SrcElt = emitAccessChain(SrcTy, Src, {Zero, Index, Zero});
588 auto *DstElt = emitAccessChain(DstTy, Dst, {Index});
589 emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType(),
590 EmitResFn);
591 }
592
593 auto *SrcElt =
594 emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, 1)});
595 auto *DstElt = emitAccessChain(
596 DstTy, Dst,
597 {llvm::ConstantInt::get(CGF.IntTy, DstTy->getNumElements() - 1)});
598 emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType(),
599 EmitResFn);
600 }
601
602 void emitCopy(Value *Src, llvm::StructType *SrcTy, Value *Dst,
603 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
604 assert(!isResourceOrResourceArray(DstTy) &&
605 "direct access to resources or resource arrays should be handled "
606 "separately");
607
608 if (isBufferLayoutArray(SrcTy))
609 return emitBufferLayoutCopy(Src, SrcTy, Dst, cast<llvm::ArrayType>(DstTy),
610 EmitResFn);
611
612 unsigned SrcIndex = 0;
613 unsigned DstIndex = 0;
614
615 // DstTy layout is in default address space and can include resource types.
616 // SrcTy is in cbuffer layout where resources are filtered out, so the
617 // number of elements in SrcTy can be less than the number of elements in
618 // DstTy.
619 auto *DstST = cast<llvm::StructType>(DstTy);
620 while (DstIndex < DstST->getNumElements()) {
621 llvm::Type *DstEltTy = DstST->getElementType(DstIndex);
622 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(DstEltTy)) {
623 DstIndex += 1;
624 continue;
625 }
626 if (isResourceOrResourceArray(DstEltTy)) {
627 auto *DstElt = emitAccessChain(
628 DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, DstIndex)});
629 emitResourceOrResourceArray(DstElt, DstEltTy, EmitResFn);
630 DstIndex += 1;
631 continue;
632 }
633
634 assert(SrcIndex < SrcTy->getNumElements());
635 llvm::Type *SrcEltTy = SrcTy->getElementType(SrcIndex);
636 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(SrcEltTy)) {
637 SrcIndex += 1;
638 continue;
639 }
640
641 auto *SrcElt = emitAccessChain(
642 SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, SrcIndex)});
643 auto *DstElt = emitAccessChain(
644 DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, DstIndex)});
645 emitElementCopy(SrcElt, SrcEltTy, DstElt, DstEltTy, EmitResFn);
646 DstIndex += 1;
647 SrcIndex += 1;
648 }
649 }
650
651 void emitCopy(Value *Src, llvm::ArrayType *SrcTy, Value *Dst,
652 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
653 for (unsigned I = 0, E = SrcTy->getNumElements(); I < E; ++I) {
654 auto *SrcElt =
655 emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, I)});
656 auto *DstElt =
657 emitAccessChain(DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, I)});
658 emitElementCopy(SrcElt, SrcTy->getElementType(), DstElt,
659 cast<llvm::ArrayType>(DstTy)->getElementType(),
660 EmitResFn);
661 }
662 }
663
664 void emitElementCopy(Value *Src, llvm::Type *SrcTy, Value *Dst,
665 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
666 if (auto *AT = dyn_cast<llvm::ArrayType>(SrcTy))
667 return emitCopy(Src, AT, Dst, DstTy, EmitResFn);
668 if (auto *ST = dyn_cast<llvm::StructType>(SrcTy))
669 return emitCopy(Src, ST, Dst, DstTy, EmitResFn);
670
671 // When we have a scalar or vector element we can emit the copy.
672 CharUnits SrcAlign =
673 CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(SrcTy));
674 CharUnits DstAlign =
675 CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(DstTy));
676 Address SrcAddr(Src, SrcTy, SrcAlign);
677 Address DstAddr(Dst, DstTy, DstAlign);
678 llvm::Value *Load = CGF.Builder.CreateLoad(SrcAddr, "cbuf.load");
679 CGF.Builder.CreateStore(Load, DstAddr);
680 }
681
682public:
683 HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DstPtr, Address SrcPtr)
684 : CGF(CGF), DstPtr(DstPtr), SrcPtr(SrcPtr) {}
685
686 bool emitCopy(QualType CType, EmitResourceFnTy EmitResFn = nullptr) {
687 LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(CType);
688
689 // TODO: We should be able to fall back to a regular memcpy if the layout
690 // type doesn't have any padding, but that runs into issues in the backend
691 // currently.
692 //
693 // See https://github.com/llvm/wg-hlsl/issues/351
694 emitElementCopy(SrcPtr.getBasePointer(), LayoutTy, DstPtr.getBasePointer(),
695 DstPtr.getElementType(), EmitResFn);
696 return true;
697 }
698};
699
700// Represents a list resources associated with a global struct whose name
701// starts with the specified prefix.
702// The order of HLSLAssociatedResourceDeclAttr attributes is identical to the
703// order of the depth-first traversal of the corresponding fields in the struct.
704// The resources are always returned in that order, which is the same order
705// we need when a struct is copied element-by-element.
706class AssociatedResourcesList {
707 // Iterator pointers for the associated resource attributes that match the
708 // prefix. Begin = begin of the range of attributes that match the prefix End
709 // = end of the range of attributes that match the prefix Next = the current
710 // attribute in the iteration to be returned by getNextResource
711 specific_attr_iterator<HLSLAssociatedResourceDeclAttr> Begin, End, Next;
712
713public:
714 AssociatedResourcesList(const VarDecl *StructVD,
715 StringRef ResourceNamePrefix) {
716 auto I = StructVD->specific_attr_begin<HLSLAssociatedResourceDeclAttr>();
717 auto E = StructVD->specific_attr_end<HLSLAssociatedResourceDeclAttr>();
718
719 // Skip over associated resources that don't match the prefix.
720 while (I != E &&
721 !I->getResDecl()->getName().starts_with(ResourceNamePrefix))
722 ++I;
723 assert(I != E && "expected associated resource not found");
724 Begin = End = I;
725
726 // Scan over associated resources that do match the prefix to find the end
727 // of the range.
728 while (I != E && ((HLSLAssociatedResourceDeclAttr *)*I)
729 ->getResDecl()
730 ->getName()
731 .starts_with(ResourceNamePrefix))
732 End = ++I;
733
734 Next = Begin;
735 }
736
737 const VarDecl *getNextResource() {
738 if (Next == End)
739 return nullptr;
740
741 const VarDecl *Res = Next->getResDecl();
742 ++Next;
743 return Res;
744 }
745};
746
747} // namespace
748
749llvm::Type *
751 const CGHLSLOffsetInfo &OffsetInfo) {
752 assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
753
754 // Check if the target has a specific translation for this type first.
755 if (llvm::Type *TargetTy =
756 CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, OffsetInfo))
757 return TargetTy;
758
759 llvm_unreachable("Generic handling of HLSL types is not supported.");
760}
761
762llvm::Triple::ArchType CGHLSLRuntime::getArch() {
763 return CGM.getTarget().getTriple().getArch();
764}
765
766// Emits constant global variables for buffer constants declarations
767// and creates metadata linking the constant globals with the buffer global.
768void CGHLSLRuntime::emitBufferGlobalsAndMetadata(
769 const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *BufGV,
770 const CGHLSLOffsetInfo &OffsetInfo) {
771 LLVMContext &Ctx = CGM.getLLVMContext();
772
773 // get the layout struct from constant buffer target type
774 llvm::Type *BufType = BufGV->getValueType();
775 llvm::StructType *LayoutStruct = cast<llvm::StructType>(
776 cast<llvm::TargetExtType>(BufType)->getTypeParameter(0));
777
779 size_t OffsetIdx = 0;
780 for (Decl *D : BufDecl->buffer_decls()) {
782 // Nothing to do for this declaration.
783 continue;
784 if (isa<FunctionDecl>(D)) {
785 // A function within an cbuffer is effectively a top-level function.
786 CGM.EmitTopLevelDecl(D);
787 continue;
788 }
789 VarDecl *VD = dyn_cast<VarDecl>(D);
790 if (!VD)
791 continue;
792
793 QualType VDTy = VD->getType();
795 if (VD->getStorageClass() == SC_Static ||
798 // Emit static and groupshared variables and resource classes inside
799 // cbuffer as regular globals
800 CGM.EmitGlobal(VD);
801 }
802 continue;
803 }
804
805 DeclsWithOffset.emplace_back(VD, OffsetInfo[OffsetIdx++]);
806 }
807
808 if (!OffsetInfo.empty())
809 llvm::stable_sort(DeclsWithOffset, [](const auto &LHS, const auto &RHS) {
810 return CGHLSLOffsetInfo::compareOffsets(LHS.second, RHS.second);
811 });
812
813 // Associate the buffer global variable with its constants
814 SmallVector<llvm::Metadata *> BufGlobals;
815 BufGlobals.reserve(DeclsWithOffset.size() + 1);
816 BufGlobals.push_back(ValueAsMetadata::get(BufGV));
817
818 auto ElemIt = LayoutStruct->element_begin();
819 for (auto &[VD, _] : DeclsWithOffset) {
820 if (CGM.getTargetCodeGenInfo().isHLSLPadding(*ElemIt))
821 ++ElemIt;
822
823 assert(ElemIt != LayoutStruct->element_end() &&
824 "number of elements in layout struct does not match");
825 llvm::Type *LayoutType = *ElemIt++;
826
827 GlobalVariable *ElemGV =
828 cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
829 BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
830 }
831 assert(ElemIt == LayoutStruct->element_end() &&
832 "number of elements in layout struct does not match");
833
834 // add buffer metadata to the module
835 CGM.getModule()
836 .getOrInsertNamedMetadata("hlsl.cbs")
837 ->addOperand(MDNode::get(Ctx, BufGlobals));
838}
839
840// Creates resource handle type for the HLSL buffer declaration
841static const clang::HLSLAttributedResourceType *
843 ASTContext &AST = BufDecl->getASTContext();
845 AST.HLSLResourceTy, AST.getCanonicalTagType(BufDecl->getLayoutStruct()),
846 HLSLAttributedResourceType::Attributes(ResourceClass::CBuffer));
848}
849
852
853 // If we don't have packoffset info, just return an empty result.
854 if (!BufDecl.hasValidPackoffset())
855 return Result;
856
857 for (Decl *D : BufDecl.buffer_decls()) {
859 continue;
860 }
861 VarDecl *VD = dyn_cast<VarDecl>(D);
862 if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
863 continue;
864
865 if (!VD->hasAttrs()) {
866 Result.Offsets.push_back(Unspecified);
867 continue;
868 }
869
870 uint32_t Offset = Unspecified;
871 for (auto *Attr : VD->getAttrs()) {
872 if (auto *POA = dyn_cast<HLSLPackOffsetAttr>(Attr)) {
873 Offset = POA->getOffsetInBytes();
874 break;
875 }
876 auto *RBA = dyn_cast<HLSLResourceBindingAttr>(Attr);
877 if (RBA &&
878 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
879 Offset = RBA->getSlotNumber() * CBufferRowSizeInBytes;
880 break;
881 }
882 }
883 Result.Offsets.push_back(Offset);
884 }
885 return Result;
886}
887
888// Codegen for HLSLBufferDecl
890
891 assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
892
893 // create resource handle type for the buffer
894 const clang::HLSLAttributedResourceType *ResHandleTy =
895 createBufferHandleType(BufDecl);
896
897 // empty constant buffer is ignored
898 if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
899 return;
900
901 // create global variable for the constant buffer
902 CGHLSLOffsetInfo OffsetInfo = CGHLSLOffsetInfo::fromDecl(*BufDecl);
903 llvm::Type *LayoutTy = convertHLSLSpecificType(ResHandleTy, OffsetInfo);
904 llvm::GlobalVariable *BufGV = new GlobalVariable(
905 LayoutTy, /*isConstant*/ false,
906 GlobalValue::LinkageTypes::InternalLinkage, PoisonValue::get(LayoutTy),
907 llvm::formatv("{0}{1}", BufDecl->getName(),
908 BufDecl->isCBuffer() ? ".cb" : ".tb"),
909 GlobalValue::NotThreadLocal);
910
911 llvm::Module &M = CGM.getModule();
912 M.insertGlobalVariable(BufGV);
913
914 // Add the global variable to the compiler used list so it does not
915 // get optimized away by GlobalOptPass before it reaches
916 // {DXIL|SPIRV}CBufferAccess pass.
917 llvm::appendToCompilerUsed(M, {BufGV});
918
919 // Add globals for constant buffer elements and create metadata nodes
920 emitBufferGlobalsAndMetadata(BufDecl, BufGV, OffsetInfo);
921
922 // Initialize cbuffer from binding (implicit or explicit)
923 initializeBufferFromBinding(BufDecl, BufGV);
924}
925
927 const HLSLRootSignatureDecl *SignatureDecl) {
928 llvm::Module &M = CGM.getModule();
929 Triple T(M.getTargetTriple());
930
931 // Generated later with the function decl if not targeting root signature
932 if (T.getEnvironment() != Triple::EnvironmentType::RootSignature)
933 return;
934
935 addRootSignatureMD(SignatureDecl->getVersion(),
936 SignatureDecl->getRootElements(), nullptr, M);
937}
938
939llvm::StructType *
940CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
941 const auto Entry = LayoutTypes.find(StructType);
942 if (Entry != LayoutTypes.end())
943 return Entry->getSecond();
944 return nullptr;
945}
946
947void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
948 llvm::StructType *LayoutTy) {
949 assert(getHLSLBufferLayoutType(StructType) == nullptr &&
950 "layout type for this struct already exist");
951 LayoutTypes[StructType] = LayoutTy;
952}
953
955 auto &TargetOpts = CGM.getTarget().getTargetOpts();
956 auto &CodeGenOpts = CGM.getCodeGenOpts();
957 auto &LangOpts = CGM.getLangOpts();
958 llvm::Module &M = CGM.getModule();
959 Triple T(M.getTargetTriple());
960 if (T.getArch() == Triple::ArchType::dxil)
961 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
962 if (!CodeGenOpts.DisableDXSourceMetadata &&
963 CodeGenOpts.getDebugInfo() >=
964 llvm::codegenoptions::DebugInfoKind::DebugInfoConstructor)
965 addSourceInfo(CGM, M);
966 if (CodeGenOpts.ResMayAlias)
967 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.resmayalias", 1);
968 if (CodeGenOpts.AllResourcesBound)
969 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error,
970 "dx.allresourcesbound", 1);
971 if (CodeGenOpts.OptimizationLevel == 0)
972 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override,
973 "dx.disable_optimizations", 1);
974
975 // NativeHalfType corresponds to the -fnative-half-type clang option which is
976 // aliased by clang-dxc's -enable-16bit-types option. This option is used to
977 // set the UseNativeLowPrecision DXIL module flag in the DirectX backend
978 if (LangOpts.NativeHalfType)
979 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.nativelowprec",
980 1);
981
982 if (LangOpts.HLSLSpvPreserveInterface && T.isSPIRV()) {
983 // Runs before optimization. Keeps Input/Output globals from GlobalDCE.
984 const ASTContext &Ctx = CGM.getContext();
985 unsigned InputAS = Ctx.getTargetAddressSpace(LangAS::hlsl_input);
986 unsigned OutputAS = Ctx.getTargetAddressSpace(LangAS::hlsl_output);
987 SmallVector<GlobalValue *, 8> InterfaceVars;
988 for (GlobalVariable &GV : M.globals()) {
989 unsigned AS = GV.getAddressSpace();
990 if (AS == InputAS || AS == OutputAS)
991 InterfaceVars.push_back(&GV);
992 }
993 if (!InterfaceVars.empty())
994 appendToCompilerUsed(M, InterfaceVars);
995 }
996
998}
999
1001 const FunctionDecl *FD, llvm::Function *Fn) {
1002 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1003 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
1004 const StringRef ShaderAttrKindStr = "hlsl.shader";
1005 Fn->addFnAttr(ShaderAttrKindStr,
1006 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
1007 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
1008 const StringRef NumThreadsKindStr = "hlsl.numthreads";
1009 std::string NumThreadsStr =
1010 formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
1011 NumThreadsAttr->getZ());
1012 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
1013 }
1014 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->getAttr<HLSLWaveSizeAttr>()) {
1015 const StringRef WaveSizeKindStr = "hlsl.wavesize";
1016 std::string WaveSizeStr =
1017 formatv("{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
1018 WaveSizeAttr->getPreferred());
1019 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
1020 }
1021 // HLSL entry functions are materialized for module functions with
1022 // HLSLShaderAttr attribute. SetLLVMFunctionAttributesForDefinition called
1023 // later in the compiler-flow for such module functions is not aware of and
1024 // hence not able to set attributes of the newly materialized entry functions.
1025 // So, set attributes of entry function here, as appropriate.
1026 Fn->addFnAttr(llvm::Attribute::NoInline);
1027
1028 if (CGM.getLangOpts().HLSLSpvEnableMaximalReconvergence) {
1029 Fn->addFnAttr("enable-maximal-reconvergence", "true");
1030 }
1031}
1032
1033static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
1034 if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
1035 Value *Result = PoisonValue::get(Ty);
1036 for (unsigned I = 0; I < VT->getNumElements(); ++I) {
1037 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
1038 Result = B.CreateInsertElement(Result, Elt, I);
1039 }
1040 return Result;
1041 }
1042 return B.CreateCall(F, {B.getInt32(0)});
1043}
1044
1045static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV,
1046 unsigned BuiltIn) {
1047 LLVMContext &Ctx = GV->getContext();
1048 IRBuilder<> B(GV->getContext());
1049 MDNode *Operands = MDNode::get(
1050 Ctx,
1051 {ConstantAsMetadata::get(B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)),
1052 ConstantAsMetadata::get(B.getInt32(BuiltIn))});
1053 MDNode *Decoration = MDNode::get(Ctx, {Operands});
1054 GV->addMetadata("spirv.Decorations", *Decoration);
1055}
1056
1057static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) {
1058 LLVMContext &Ctx = GV->getContext();
1059 IRBuilder<> B(GV->getContext());
1060 MDNode *Operands =
1061 MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)),
1062 ConstantAsMetadata::get(B.getInt32(Location))});
1063 MDNode *Decoration = MDNode::get(Ctx, {Operands});
1064 GV->addMetadata("spirv.Decorations", *Decoration);
1065}
1066
1067// A fragment shader input interface variable whose base type is an integer or
1068// a 64-bit float (double) cannot be interpolated by the rasterizer. The Vulkan
1069// specification requires these variables to be decorated with Flat (see
1070// VUID-StandaloneSpirv-Flat-04744). Arrays and vectors are unwrapped to inspect
1071// their base scalar type.
1072static bool inputRequiresFlatDecoration(llvm::Type *Ty) {
1073 while (true) {
1074 if (auto *AT = dyn_cast<llvm::ArrayType>(Ty)) {
1075 Ty = AT->getElementType();
1076 continue;
1077 }
1078 if (auto *VT = dyn_cast<llvm::FixedVectorType>(Ty)) {
1079 Ty = VT->getElementType();
1080 continue;
1081 }
1082 break;
1083 }
1084 return Ty->isIntegerTy() || Ty->isDoubleTy();
1085}
1086
1087static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
1088 llvm::Type *Ty, const Twine &Name,
1089 unsigned BuiltInID) {
1090 auto *GV = new llvm::GlobalVariable(
1091 M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
1092 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
1093 llvm::GlobalVariable::GeneralDynamicTLSModel,
1094 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
1095 addSPIRVBuiltinDecoration(GV, BuiltInID);
1096 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1097 return B.CreateLoad(Ty, GV);
1098}
1099
1100static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M,
1101 llvm::Type *Ty, unsigned Location,
1102 StringRef Name, bool NeedsFlat) {
1103 auto *GV = new llvm::GlobalVariable(
1104 M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
1105 /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
1106 llvm::GlobalVariable::GeneralDynamicTLSModel,
1107 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
1108 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1109
1110 // Emit all decorations as a single `spirv.Decorations` node. Attaching
1111 // multiple `spirv.Decorations` metadata nodes to the same global is not
1112 // supported by the SPIR-V backend and results in all but one being dropped.
1113 LLVMContext &Ctx = GV->getContext();
1114 SmallVector<Metadata *, 2> Decorations;
1115 Decorations.push_back(
1116 MDNode::get(Ctx, {ConstantAsMetadata::get(
1117 B.getInt32(/* SPIRV::Decoration::Location */ 30)),
1118 ConstantAsMetadata::get(B.getInt32(Location))}));
1119 if (NeedsFlat)
1120 Decorations.push_back(
1121 MDNode::get(Ctx, {ConstantAsMetadata::get(
1122 B.getInt32(/* SPIRV::Decoration::Flat */ 14))}));
1123 GV->addMetadata("spirv.Decorations", *MDNode::get(Ctx, Decorations));
1124
1125 return B.CreateLoad(Ty, GV);
1126}
1127
1128llvm::Value *CGHLSLRuntime::emitSPIRVUserSemanticLoad(
1129 llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1130 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1131 std::optional<unsigned> Index) {
1132 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1133 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1134
1135 unsigned Location = SPIRVLastAssignedInputSemanticLocation;
1136 if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
1137 Location = L->getLocation();
1138
1139 // DXC completely ignores the semantic/index pair. Location are assigned from
1140 // the first semantic to the last.
1141 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
1142 unsigned ElementCount = AT ? AT->getNumElements() : 1;
1143 SPIRVLastAssignedInputSemanticLocation += ElementCount;
1144
1145 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1146 bool NeedsFlat =
1147 ShaderAttr &&
1148 ShaderAttr->getType() == llvm::Triple::EnvironmentType::Pixel &&
1150
1151 return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location,
1152 VariableName.str(), NeedsFlat);
1153}
1154
1155static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M,
1156 llvm::Value *Source, unsigned Location,
1157 StringRef Name) {
1158 auto *GV = new llvm::GlobalVariable(
1159 M, Source->getType(), /* isConstant= */ false,
1160 llvm::GlobalValue::ExternalLinkage,
1161 /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
1162 llvm::GlobalVariable::GeneralDynamicTLSModel,
1163 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
1164 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1165 addLocationDecoration(GV, Location);
1166 B.CreateStore(Source, GV);
1167}
1168
1169void CGHLSLRuntime::emitSPIRVUserSemanticStore(
1170 llvm::IRBuilder<> &B, llvm::Value *Source,
1171 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1172 std::optional<unsigned> Index) {
1173 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1174 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1175
1176 unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
1177 if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
1178 Location = L->getLocation();
1179
1180 // DXC completely ignores the semantic/index pair. Location are assigned from
1181 // the first semantic to the last.
1182 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
1183 unsigned ElementCount = AT ? AT->getNumElements() : 1;
1184 SPIRVLastAssignedOutputSemanticLocation += ElementCount;
1185 createSPIRVLocationStore(B, CGM.getModule(), Source, Location,
1186 VariableName.str());
1187}
1188
1189llvm::Value *
1190CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
1191 HLSLAppliedSemanticAttr *Semantic,
1192 std::optional<unsigned> Index) {
1193 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1194 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1195
1196 // DXIL packing rules etc shall be handled here.
1197 // FIXME: generate proper sigpoint, index, col, row values.
1198 // FIXME: also DXIL loads vectors element by element.
1199 SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
1200 B.getInt8(0),
1201 llvm::PoisonValue::get(B.getInt32Ty())};
1202
1203 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
1204
1205 SmallVector<OperandBundleDef, 1> OB;
1206 if (auto *Token = getConvergenceToken(*B.GetInsertBlock())) {
1207 llvm::Value *bundleArgs[] = {Token};
1208 OB.emplace_back("convergencectrl", bundleArgs);
1209 }
1210
1211 llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
1212 B.GetInsertBlock()->getModule(), IntrinsicID, {Type});
1213 llvm::Value *Value = B.CreateCall(IntrFn, Args, OB, VariableName);
1214 return Value;
1215}
1216
1217void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
1218 llvm::Value *Source,
1219 HLSLAppliedSemanticAttr *Semantic,
1220 std::optional<unsigned> Index) {
1221 // DXIL packing rules etc shall be handled here.
1222 // FIXME: generate proper sigpoint, index, col, row values.
1223 SmallVector<Value *> Args{B.getInt32(4),
1224 B.getInt32(0),
1225 B.getInt32(0),
1226 B.getInt8(0),
1227 llvm::PoisonValue::get(B.getInt32Ty()),
1228 Source};
1229
1230 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
1231
1232 SmallVector<OperandBundleDef, 1> OB;
1233 if (auto *Token = getConvergenceToken(*B.GetInsertBlock())) {
1234 llvm::Value *bundleArgs[] = {Token};
1235 OB.emplace_back("convergencectrl", bundleArgs);
1236 }
1237
1238 llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
1239 B.GetInsertBlock()->getModule(), IntrinsicID, {Source->getType()});
1240 B.CreateCall(IntrFn, Args, OB);
1241}
1242
1243llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
1244 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1245 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1246 std::optional<unsigned> Index) {
1247 if (CGM.getTarget().getTriple().isSPIRV())
1248 return emitSPIRVUserSemanticLoad(B, FD, Type, Decl, Semantic, Index);
1249
1250 if (CGM.getTarget().getTriple().isDXIL())
1251 return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
1252
1253 llvm_unreachable("Unsupported target for user-semantic load.");
1254}
1255
1256void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
1257 const clang::DeclaratorDecl *Decl,
1258 HLSLAppliedSemanticAttr *Semantic,
1259 std::optional<unsigned> Index) {
1260 if (CGM.getTarget().getTriple().isSPIRV())
1261 return emitSPIRVUserSemanticStore(B, Source, Decl, Semantic, Index);
1262
1263 if (CGM.getTarget().getTriple().isDXIL())
1264 return emitDXILUserSemanticStore(B, Source, Semantic, Index);
1265
1266 llvm_unreachable("Unsupported target for user-semantic load.");
1267}
1268
1270 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1271 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1272 std::optional<unsigned> Index) {
1273
1274 std::string SemanticName = Semantic->getAttrName()->getName().upper();
1275 if (SemanticName == "SV_GROUPINDEX") {
1276 llvm::Function *GroupIndex =
1277 CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
1278 return B.CreateCall(FunctionCallee(GroupIndex));
1279 }
1280
1281 if (SemanticName == "SV_DISPATCHTHREADID") {
1282 llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
1283 llvm::Function *ThreadIDIntrinsic =
1284 llvm::Intrinsic::isOverloaded(IntrinID)
1285 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1286 : CGM.getIntrinsic(IntrinID);
1287 return buildVectorInput(B, ThreadIDIntrinsic, Type);
1288 }
1289
1290 if (SemanticName == "SV_GROUPTHREADID") {
1291 llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
1292 llvm::Function *GroupThreadIDIntrinsic =
1293 llvm::Intrinsic::isOverloaded(IntrinID)
1294 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1295 : CGM.getIntrinsic(IntrinID);
1296 return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
1297 }
1298
1299 if (SemanticName == "SV_GROUPID") {
1300 llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
1301 llvm::Function *GroupIDIntrinsic =
1302 llvm::Intrinsic::isOverloaded(IntrinID)
1303 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1304 : CGM.getIntrinsic(IntrinID);
1305 return buildVectorInput(B, GroupIDIntrinsic, Type);
1306 }
1307
1308 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1309 assert(ShaderAttr && "Entry point has no shader attribute");
1310 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
1311
1312 if (SemanticName == "SV_POSITION") {
1313 if (ST == Triple::EnvironmentType::Pixel) {
1314 if (CGM.getTarget().getTriple().isSPIRV())
1315 return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
1316 Semantic->getAttrName()->getName(),
1317 /* BuiltIn::FragCoord */ 15);
1318 if (CGM.getTarget().getTriple().isDXIL())
1319 return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
1320 }
1321
1322 if (ST == Triple::EnvironmentType::Vertex) {
1323 return emitUserSemanticLoad(B, FD, Type, Decl, Semantic, Index);
1324 }
1325 }
1326
1327 if (SemanticName == "SV_VERTEXID") {
1328 if (ST == Triple::EnvironmentType::Vertex) {
1329 if (CGM.getTarget().getTriple().isSPIRV())
1330 return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
1331 Semantic->getAttrName()->getName(),
1332 /* BuiltIn::VertexIndex */ 42);
1333 else
1334 return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
1335 }
1336 }
1337
1338 llvm_unreachable(
1339 "Load hasn't been implemented yet for this system semantic. FIXME");
1340}
1341
1342static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M,
1343 llvm::Value *Source, const Twine &Name,
1344 unsigned BuiltInID) {
1345 auto *GV = new llvm::GlobalVariable(
1346 M, Source->getType(), /* isConstant= */ false,
1347 llvm::GlobalValue::ExternalLinkage,
1348 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
1349 llvm::GlobalVariable::GeneralDynamicTLSModel,
1350 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
1351 addSPIRVBuiltinDecoration(GV, BuiltInID);
1352 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1353 B.CreateStore(Source, GV);
1354}
1355
1356void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
1358 HLSLAppliedSemanticAttr *Semantic,
1359 std::optional<unsigned> Index) {
1360
1361 std::string SemanticName = Semantic->getAttrName()->getName().upper();
1362 if (SemanticName == "SV_POSITION") {
1363 if (CGM.getTarget().getTriple().isDXIL()) {
1364 emitDXILUserSemanticStore(B, Source, Semantic, Index);
1365 return;
1366 }
1367
1368 if (CGM.getTarget().getTriple().isSPIRV()) {
1369 createSPIRVBuiltinStore(B, CGM.getModule(), Source,
1370 Semantic->getAttrName()->getName(),
1371 /* BuiltIn::Position */ 0);
1372 return;
1373 }
1374 }
1375
1376 if (SemanticName == "SV_TARGET") {
1377 emitUserSemanticStore(B, Source, Decl, Semantic, Index);
1378 return;
1379 }
1380
1381 llvm_unreachable(
1382 "Store hasn't been implemented yet for this system semantic. FIXME");
1383}
1384
1386 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1387 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
1388
1389 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1390 if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
1391 return emitSystemSemanticLoad(B, FD, Type, Decl, Semantic, Index);
1392 return emitUserSemanticLoad(B, FD, Type, Decl, Semantic, Index);
1393}
1394
1396 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
1397 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
1398 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1399 if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
1400 emitSystemSemanticStore(B, Source, Decl, Semantic, Index);
1401 else
1402 emitUserSemanticStore(B, Source, Decl, Semantic, Index);
1403}
1404
1405std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1407 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1411 const llvm::StructType *ST = cast<StructType>(Type);
1412 const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();
1413
1414 assert(RD->getNumFields() == ST->getNumElements());
1415
1416 llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
1417 auto FieldDecl = RD->field_begin();
1418 for (unsigned I = 0; I < ST->getNumElements(); ++I) {
1419 auto [ChildValue, NextAttr] = handleSemanticLoad(
1420 B, FD, ST->getElementType(I), *FieldDecl, AttrBegin, AttrEnd);
1421 AttrBegin = NextAttr;
1422 assert(ChildValue);
1423 Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
1424 ++FieldDecl;
1425 }
1426
1427 return std::make_pair(Aggregate, AttrBegin);
1428}
1429
1432 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
1436
1437 const llvm::StructType *ST = cast<StructType>(Source->getType());
1438
1439 const clang::RecordDecl *RD = nullptr;
1440 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
1442 else
1443 RD = Decl->getType()->getAsRecordDecl();
1444 assert(RD);
1445
1446 assert(RD->getNumFields() == ST->getNumElements());
1447
1448 auto FieldDecl = RD->field_begin();
1449 for (unsigned I = 0; I < ST->getNumElements(); ++I, ++FieldDecl) {
1450 llvm::Value *Extract = B.CreateExtractValue(Source, I);
1451 AttrBegin =
1452 handleSemanticStore(B, FD, Extract, *FieldDecl, AttrBegin, AttrEnd);
1453 }
1454
1455 return AttrBegin;
1456}
1457
1458std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1460 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1464 assert(AttrBegin != AttrEnd);
1465 if (Type->isStructTy())
1466 return handleStructSemanticLoad(B, FD, Type, Decl, AttrBegin, AttrEnd);
1467
1468 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
1469 ++AttrBegin;
1470 return std::make_pair(handleScalarSemanticLoad(B, FD, Type, Decl, Attr),
1471 AttrBegin);
1472}
1473
1476 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
1480 assert(AttrBegin != AttrEnd);
1481 if (Source->getType()->isStructTy())
1482 return handleStructSemanticStore(B, FD, Source, Decl, AttrBegin, AttrEnd);
1483
1484 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
1485 ++AttrBegin;
1486 handleScalarSemanticStore(B, FD, Source, Decl, Attr);
1487 return AttrBegin;
1488}
1489
1491 llvm::Function *Fn) {
1492 llvm::Module &M = CGM.getModule();
1493 llvm::LLVMContext &Ctx = M.getContext();
1494 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
1495 Function *EntryFn =
1496 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
1497
1498 // Copy function attributes over, we have no argument or return attributes
1499 // that can be valid on the real entry.
1500 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
1501 Fn->getAttributes().getFnAttrs());
1502 EntryFn->setAttributes(NewAttrs);
1503 setHLSLEntryAttributes(FD, EntryFn);
1504
1505 // Set the called function as internal linkage.
1506 Fn->setLinkage(GlobalValue::InternalLinkage);
1507
1508 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
1509 IRBuilder<> B(BB);
1511
1513 if (CGM.shouldEmitConvergenceTokens()) {
1514 assert(EntryFn->isConvergent());
1515 llvm::Value *I =
1516 B.CreateIntrinsic(llvm::Intrinsic::experimental_convergence_entry, {});
1517 llvm::Value *bundleArgs[] = {I};
1518 OB.emplace_back("convergencectrl", bundleArgs);
1519 }
1520
1522
1523 unsigned SRetOffset = 0;
1524 for (const auto &Param : Fn->args()) {
1525 if (Param.hasStructRetAttr()) {
1526 SRetOffset = 1;
1527 llvm::Type *VarType = Param.getParamStructRetType();
1528 llvm::Value *Var =
1529 CGM.getLangOpts().EmitLogicalPointer
1530 ? cast<Instruction>(B.CreateStructuredAlloca(VarType))
1531 : cast<Instruction>(B.CreateAlloca(VarType));
1532 OutputSemantic.push_back(std::make_pair(Var, VarType));
1533 Args.push_back(Var);
1534 continue;
1535 }
1536
1537 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
1538 llvm::Value *SemanticValue = nullptr;
1539 // FIXME: support inout/out parameters for semantics.
1540 if ([[maybe_unused]] HLSLParamModifierAttr *MA =
1541 PD->getAttr<HLSLParamModifierAttr>()) {
1542 llvm_unreachable("Not handled yet");
1543 } else {
1544 llvm::Type *ParamType = nullptr;
1545 if (Param.hasByValAttr())
1546 ParamType = Param.getParamByValType();
1547 else if (PD->getType()->isRecordType())
1548 ParamType = CGM.getTypes().ConvertType(PD->getType());
1549 else
1550 ParamType = Param.getType();
1551
1552 auto AttrBegin = PD->specific_attr_begin<HLSLAppliedSemanticAttr>();
1553 auto AttrEnd = PD->specific_attr_end<HLSLAppliedSemanticAttr>();
1554 auto Result =
1555 handleSemanticLoad(B, FD, ParamType, PD, AttrBegin, AttrEnd);
1556 SemanticValue = Result.first;
1557 if (!SemanticValue)
1558 return;
1559 if (Param.hasByValAttr() || PD->getType()->isRecordType()) {
1560 llvm::Value *Var =
1561 CGM.getLangOpts().EmitLogicalPointer
1562 ? cast<Instruction>(B.CreateStructuredAlloca(ParamType))
1563 : cast<Instruction>(B.CreateAlloca(ParamType));
1564 B.CreateStore(SemanticValue, Var);
1565 SemanticValue = Var;
1566 }
1567 }
1568
1569 assert(SemanticValue);
1570 Args.push_back(SemanticValue);
1571 }
1572
1573 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
1574 CI->setCallingConv(Fn->getCallingConv());
1575
1576 if (Fn->getReturnType() != CGM.VoidTy)
1577 // Element type is unused, so set to dummy value (NULL).
1578 OutputSemantic.push_back(std::make_pair(CI, nullptr));
1579
1580 for (auto &SourcePair : OutputSemantic) {
1581 llvm::Value *Source = SourcePair.first;
1582 llvm::Type *ElementType = SourcePair.second;
1583 AllocaInst *AI = dyn_cast<AllocaInst>(Source);
1584 llvm::Value *SourceValue = AI ? B.CreateLoad(ElementType, Source) : Source;
1585
1586 auto AttrBegin = FD->specific_attr_begin<HLSLAppliedSemanticAttr>();
1587 auto AttrEnd = FD->specific_attr_end<HLSLAppliedSemanticAttr>();
1588 handleSemanticStore(B, FD, SourceValue, FD, AttrBegin, AttrEnd);
1589 }
1590
1591 B.CreateRetVoid();
1592
1593 // Add and identify root signature to function, if applicable
1594 for (const Attr *Attr : FD->getAttrs()) {
1595 if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) {
1596 auto *RSDecl = RSAttr->getSignatureDecl();
1597 addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
1598 EntryFn, M);
1599 }
1600 }
1601}
1602
1603static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
1604 bool CtorOrDtor) {
1605 const auto *GV =
1606 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
1607 if (!GV)
1608 return;
1609 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
1610 if (!CA)
1611 return;
1612 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
1613 // HLSL neither supports priorities or COMDat values, so we will check those
1614 // in an assert but not handle them.
1615
1616 for (const auto &Ctor : CA->operands()) {
1618 continue;
1619 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
1620
1621 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
1622 "HLSL doesn't support setting priority for global ctors.");
1623 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
1624 "HLSL doesn't support COMDat for global ctors.");
1625 Fns.push_back(cast<Function>(CS->getOperand(1)));
1626 }
1627}
1628
1630 llvm::Module &M = CGM.getModule();
1633 gatherFunctions(CtorFns, M, true);
1634 gatherFunctions(DtorFns, M, false);
1635
1636 // Insert a call to the global constructor at the beginning of the entry block
1637 // to externally exported functions. This is a bit of a hack, but HLSL allows
1638 // global constructors, but doesn't support driver initialization of globals.
1639 for (auto &F : M.functions()) {
1640 if (!F.hasFnAttribute("hlsl.shader"))
1641 continue;
1642 auto *Token = getConvergenceToken(F.getEntryBlock());
1643 Instruction *IP = &*F.getEntryBlock().begin();
1645 if (Token) {
1646 llvm::Value *bundleArgs[] = {Token};
1647 OB.emplace_back("convergencectrl", bundleArgs);
1648 IP = Token->getNextNode();
1649 }
1650 IRBuilder<> B(IP);
1651 for (auto *Fn : CtorFns) {
1652 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1653 CI->setCallingConv(Fn->getCallingConv());
1654 }
1655
1656 // Insert global dtors before the terminator of the last instruction
1657 B.SetInsertPoint(F.back().getTerminator());
1658 for (auto *Fn : DtorFns) {
1659 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1660 CI->setCallingConv(Fn->getCallingConv());
1661 }
1662 }
1663
1664 // No need to keep global ctors/dtors for non-lib profile after call to
1665 // ctors/dtors added for entry.
1666 Triple T(M.getTargetTriple());
1667 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
1668 if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
1669 GV->eraseFromParent();
1670 if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
1671 GV->eraseFromParent();
1672 }
1673}
1674
1675static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
1676 Intrinsic::ID IntrID,
1678
1679 LLVMContext &Ctx = CGM.getLLVMContext();
1680 llvm::Function *InitResFunc =
1681 llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, false),
1682 llvm::GlobalValue::InternalLinkage,
1683 "_init_buffer_" + GV->getName(), CGM.getModule());
1684 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1685
1686 llvm::BasicBlock *EntryBB =
1687 llvm::BasicBlock::Create(Ctx, "entry", InitResFunc);
1688 CGBuilderTy Builder(CGM, Ctx);
1689 const DataLayout &DL = CGM.getModule().getDataLayout();
1690 Builder.SetInsertPoint(EntryBB);
1691
1692 // Make sure the global variable is buffer resource handle
1693 llvm::Type *HandleTy = GV->getValueType();
1694 assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");
1695
1696 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
1697 /*ReturnType=*/HandleTy, IntrID, Args, nullptr,
1698 Twine(GV->getName()).concat("_h"));
1699
1700 Builder.CreateAlignedStore(CreateHandle, GV, GV->getPointerAlignment(DL));
1701 Builder.CreateRetVoid();
1702
1703 CGM.AddCXXGlobalInit(InitResFunc);
1704}
1705
1706void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
1707 llvm::GlobalVariable *GV) {
1708 ResourceBindingAttrs Binding(BufDecl);
1709 assert(Binding.hasBinding() &&
1710 "cbuffer/tbuffer should always have resource binding attribute");
1711
1712 auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
1713 auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
1714 auto *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
1715 Value *Name = buildNameForResource(BufDecl->getName(), CGM);
1716
1717 // buffer with explicit binding
1718 if (Binding.isExplicit()) {
1719 llvm::Intrinsic::ID IntrinsicID =
1720 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
1721 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
1722 SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
1723 initializeBuffer(CGM, GV, IntrinsicID, Args);
1724 } else {
1725 // buffer with implicit binding
1726 llvm::Intrinsic::ID IntrinsicID =
1727 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
1728 auto *OrderID =
1729 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
1730 SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
1731 initializeBuffer(CGM, GV, IntrinsicID, Args);
1732 }
1733}
1734
1736 llvm::GlobalVariable *GV) {
1737 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
1738 addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
1739 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinOutputAttr>())
1740 addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
1741}
1742
1743llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
1744 if (!CGM.shouldEmitConvergenceTokens())
1745 return nullptr;
1746
1747 auto E = BB.end();
1748 for (auto I = BB.begin(); I != E; ++I) {
1749 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
1750 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
1751 return II;
1752 }
1753 }
1754 llvm_unreachable("Convergence token should have been emitted.");
1755 return nullptr;
1756}
1757
1758class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
1759public:
1763
1765 // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
1766 // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
1767 // traversal, the temporary containing the copy out will not have
1768 // been created yet.
1769 return false;
1770 }
1771
1773 // Traverse the source expression first.
1774 if (E->getSourceExpr())
1776
1777 // Then add this OVE if we haven't seen it before.
1778 if (Visited.insert(E).second)
1779 OVEs.push_back(E);
1780
1781 return true;
1782 }
1783};
1784
1786 InitListExpr *E) {
1787
1788 typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
1789 OpaqueValueVisitor Visitor;
1790 Visitor.TraverseStmt(E);
1791 for (auto *OVE : Visitor.OVEs) {
1792 if (CGF.isOpaqueValueEmitted(OVE))
1793 continue;
1794 if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
1795 LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
1796 OpaqueValueMappingData::bind(CGF, OVE, LV);
1797 } else {
1798 RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
1799 OpaqueValueMappingData::bind(CGF, OVE, RV);
1800 }
1801 }
1802}
1803
1805 const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
1806 assert((ArraySubsExpr->getType()->isHLSLResourceRecord() ||
1807 ArraySubsExpr->getType()->isHLSLResourceRecordArray()) &&
1808 "expected resource array subscript expression");
1809
1810 // Let clang codegen handle local and static resource array subscripts,
1811 // or when the subscript references on opaque expression (as part of
1812 // ArrayInitLoopExpr AST node).
1813 const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(
1814 getArrayDecl(CGF.CGM.getContext(), ArraySubsExpr));
1815 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
1816 ArrayDecl->getStorageClass() == SC_Static)
1817 return std::nullopt;
1818
1819 // get the resource array type
1820 ASTContext &AST = ArrayDecl->getASTContext();
1821 const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
1822 assert(ResArrayTy->isHLSLResourceRecordArray() &&
1823 "expected array of resource classes");
1824
1825 // Iterate through all nested array subscript expressions to calculate
1826 // the index in the flattened resource array (if this is a multi-
1827 // dimensional array). The index is calculated as a sum of all indices
1828 // multiplied by the total size of the array at that level.
1829 Value *Index = nullptr;
1830 const ArraySubscriptExpr *ASE = ArraySubsExpr;
1831 while (ASE != nullptr) {
1832 Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
1833 if (const auto *ArrayTy =
1834 dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
1835 Value *Multiplier = llvm::ConstantInt::get(
1836 CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy));
1837 SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
1838 }
1839 Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
1840 ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
1841 }
1842
1843 // Find binding info for the resource array. For implicit binding
1844 // an HLSLResourceBindingAttr should have been added by SemaHLSL.
1845 ResourceBindingAttrs Binding(ArrayDecl);
1846 assert(Binding.hasBinding() &&
1847 "resource array must have a binding attribute");
1848
1849 // Find the individual resource type.
1850 QualType ResultTy = ArraySubsExpr->getType();
1851 QualType ResourceTy =
1852 ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy;
1853
1854 // Create a temporary variable for the result, which is either going
1855 // to be a single resource instance or a local array of resources (we need to
1856 // return an LValue).
1857 RawAddress TmpVar = CGF.CreateMemTempWithoutCast(ResultTy);
1858 if (CGF.EmitLifetimeStart(TmpVar.getPointer()))
1860 NormalEHLifetimeMarker, TmpVar);
1861
1866
1867 // Calculate total array size (= range size).
1868 llvm::Value *Range = llvm::ConstantInt::getSigned(
1869 CGM.IntTy, getTotalArraySize(AST, ResArrayTy));
1870
1871 // If the result of the subscript operation is a single resource, call the
1872 // constructor.
1873 if (ResultTy == ResourceTy) {
1874 CallArgList Args;
1875 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
1876 CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
1877 ArrayDecl->getName(), Binding, Args);
1878
1879 if (!CreateMethod) {
1880 // This can happen if someone creates an array of structs that looks like
1881 // an HLSL resource record array but it does not have the required static
1882 // create method. No binding will be generated for it.
1883 assert(!ResourceTy->getAsCXXRecordDecl()->isImplicit() &&
1884 "create method lookup should always succeed for built-in resource "
1885 "records");
1886 return std::nullopt;
1887 }
1888
1889 callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
1890
1891 } else {
1892 // The result of the subscript operation is a local resource array which
1893 // needs to be initialized.
1894 const ConstantArrayType *ArrayTy =
1896 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
1897 CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
1898 ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)});
1899 if (!EndIndex)
1900 return std::nullopt;
1901 }
1902 return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
1903}
1904
1905// Initialize all resources of a global resource array into provided slot.
1906bool CGHLSLRuntime::initializeGlobalResourceArray(CodeGenFunction &CGF,
1907 const VarDecl *ArrayDecl,
1908 AggValueSlot &DestSlot) {
1909 assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
1910 ArrayDecl->hasGlobalStorage() &&
1911 ArrayDecl->getStorageClass() != SC_Static &&
1912 "expected global non-static resource array");
1913
1914 // Find binding info for the resource array. For implicit binding
1915 // the HLSLResourceBindingAttr should have been added by SemaHLSL.
1916 ResourceBindingAttrs Binding(ArrayDecl);
1917 assert(Binding.hasBinding() &&
1918 "resource array must have a binding attribute");
1919
1920 // Find the individual resource type.
1921 ASTContext &AST = ArrayDecl->getASTContext();
1922 QualType ResTy = AST.getBaseElementType(ArrayDecl->getType());
1923 const auto *ResArrayTy =
1925
1926 // Create Value for index and total array size (= range size).
1927 int Size = getTotalArraySize(AST, ResArrayTy);
1928 llvm::Value *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
1929 llvm::Value *Range = llvm::ConstantInt::get(CGM.IntTy, Size);
1930
1931 // Initialize individual resources in the array into DestSlot.
1932 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
1933 CGF, ResTy->getAsCXXRecordDecl(), ResArrayTy, DestSlot, Range, Zero,
1934 ArrayDecl->getName(), Binding, {Zero});
1935 return EndIndex.has_value();
1936}
1937
1938// If the expression is a global resource array, initialize all of its resources
1939// into Dest. Returns false if no initialization has been performed and the
1940// array copy should be handled by the default codegen.
1942 AggValueSlot &DestSlot) {
1943 assert(E->getType()->isHLSLResourceRecordArray() &&
1944 "expected resource array");
1945
1946 // Find the array declaration for the expression. Fallback to the default
1947 // handling if it's not a global resource array.
1948 const VarDecl *ArrayDecl =
1949 dyn_cast_or_null<VarDecl>(getArrayDecl(CGF.CGM.getContext(), E));
1950 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
1951 ArrayDecl->getStorageClass() == SC_Static)
1952 return false;
1953
1954 return initializeGlobalResourceArray(CGF, ArrayDecl, DestSlot);
1955}
1956
1957// If the expression is a global resource array, create a temporary and
1958// initialize all of its resources, and return it as an LValue. Returns nullopt
1959// if no initialization has been performed and the handling should follow the
1960// default path.
1961std::optional<LValue>
1963 const VarDecl *ArrayDecl) {
1964 assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
1965 "expected resource array declaration");
1966
1967 if (!ArrayDecl->hasGlobalStorage() ||
1968 ArrayDecl->getStorageClass() == SC_Static)
1969 return std::nullopt;
1970
1971 AggValueSlot TmpArraySlot =
1972 CGF.CreateAggTemp(ArrayDecl->getType(), "tmpResArray");
1973 if (initializeGlobalResourceArray(CGF, ArrayDecl, TmpArraySlot))
1974 return CGF.MakeAddrLValue(TmpArraySlot.getAddress(), ArrayDecl->getType(),
1976 return std::nullopt;
1977}
1978
1980 CodeGenFunction &CGF) {
1981
1982 assert(LV.getType()->isConstantMatrixType() && "expected matrix type");
1984 "expected cbuffer matrix");
1985
1986 QualType MatQualTy = LV.getType();
1987 llvm::Type *LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(MatQualTy);
1988 Address SrcAddr = LV.getAddress();
1989
1990 if (LayoutTy == CGF.ConvertTypeForMem(MatQualTy))
1991 return SrcAddr;
1992
1993 RawAddress DestAlloca =
1994 CGF.CreateMemTempWithoutCast(MatQualTy, "matrix.buf.copy");
1995 HLSLBufferCopyEmitter(CGF, DestAlloca, SrcAddr).emitCopy(MatQualTy);
1996 return DestAlloca;
1997}
1998
2000 const ArraySubscriptExpr *E, CodeGenFunction &CGF,
2001 llvm::function_ref<llvm::Value *(bool Promote)> EmitIdxAfterBase) {
2002 // Find the element type to index by first padding the element type per HLSL
2003 // buffer rules, and then padding out to a 16-byte register boundary if
2004 // necessary.
2005 llvm::Type *LayoutTy =
2007 uint64_t LayoutSizeInBits =
2008 CGM.getDataLayout().getTypeSizeInBits(LayoutTy).getFixedValue();
2009 CharUnits ElementSize = CharUnits::fromQuantity(LayoutSizeInBits / 8);
2010 CharUnits RowAlignedSize = ElementSize.alignTo(CharUnits::fromQuantity(16));
2011 if (RowAlignedSize > ElementSize) {
2012 llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding(
2013 CGM, RowAlignedSize - ElementSize);
2014 assert(Padding && "No padding type for target?");
2015 LayoutTy = llvm::StructType::get(CGF.getLLVMContext(), {LayoutTy, Padding},
2016 /*isPacked=*/true);
2017 }
2018
2019 // If the layout type doesn't introduce any padding, we don't need to do
2020 // anything special.
2021 llvm::Type *OrigTy = CGF.CGM.getTypes().ConvertTypeForMem(E->getType());
2022 if (LayoutTy == OrigTy)
2023 return std::nullopt;
2024
2025 LValueBaseInfo EltBaseInfo;
2026 TBAAAccessInfo EltTBAAInfo;
2027
2028 // Index into the object as-if we have an array of the padded element type,
2029 // and then dereference the element itself to avoid reading padding that may
2030 // be past the end of the in-memory object.
2032 llvm::Value *Idx = EmitIdxAfterBase(/*Promote*/ true);
2033 Indices.push_back(Idx);
2034 Indices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
2035
2036 if (CGF.getLangOpts().EmitLogicalPointer) {
2037 // The fact that we emit an array-to-pointer decay might be an oversight,
2038 // but for now, we simply ignore it (see #179951).
2039 const CastExpr *CE = cast<CastExpr>(E->getBase());
2040 assert(CE->getCastKind() == CastKind::CK_ArrayToPointerDecay);
2041
2042 LValue LV = CGF.EmitLValue(CE->getSubExpr());
2043 Address Addr = LV.getAddress();
2044 LayoutTy = llvm::ArrayType::get(
2045 LayoutTy,
2046 cast<llvm::ArrayType>(Addr.getElementType())->getNumElements());
2047 auto *GEP = cast<StructuredGEPInst>(CGF.Builder.CreateStructuredGEP(
2048 LayoutTy, Addr.emitRawPointer(CGF), Indices, "cbufferidx"));
2049 Addr =
2050 Address(GEP, GEP->getResultElementType(), RowAlignedSize, KnownNonNull);
2051 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
2052 }
2053
2054 Address Addr =
2055 CGF.EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
2056 llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF),
2057 Indices, "cbufferidx");
2058 Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull);
2059 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
2060}
2061
2062std::optional<LValue>
2064 const MemberExpr *ME) {
2065 assert((ME->getType()->isHLSLResourceRecord() ||
2067 "expected resource member expression");
2068
2069 const VarDecl *ResourceVD =
2070 findAssociatedResourceDeclForStruct(CGF.CGM.getContext(), ME);
2071 if (!ResourceVD)
2072 return std::nullopt;
2073
2074 // Handle member of resource array type.
2075 if (ResourceVD->getType()->isHLSLResourceRecordArray())
2076 return emitGlobalResourceArrayAsLValue(CGF, ResourceVD);
2077
2078 GlobalVariable *ResGV =
2080 const DataLayout &DL = CGM.getDataLayout();
2081 llvm::Type *Ty = ResGV->getValueType();
2082 CharUnits Align = CharUnits::fromQuantity(DL.getABITypeAlign(Ty));
2083 Address Addr = Address(ResGV, Ty, Align);
2084 LValue LV = LValue::MakeAddr(Addr, ME->getType(), CGM.getContext(),
2086 CGM.getTBAAAccessInfo(ME->getType()));
2087 return LV;
2088}
2089
2091 const LValue &SrcLV,
2092 AggValueSlot &DestSlot) {
2094 "expected expression in HLSL constant address space");
2095 assert(!E->getType()->isHLSLResourceRecord() &&
2097 "direct accesses to resource types should be handled separately");
2098
2099 if (DestSlot.isIgnored())
2100 return false;
2101
2102 QualType Ty = E->getType();
2103 Address DstPtr = DestSlot.getAddress();
2104 Address SrcPtr = SrcLV.getAddress();
2105
2106 // If there are no intangible types, we don't need to lookup associated
2107 // resources.
2108 if (!Ty->isHLSLIntangibleType())
2109 return HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty);
2110
2111 // Handle structs with intangible types by setting the resource fields
2112 // of the destination struct with the resources associated with the global
2113 // struct.
2114 EmbeddedResourceNameBuilder NameBuilder;
2115 const VarDecl *VD = findStructResourceParentDeclAndBuildName(E, NameBuilder);
2116 AssociatedResourcesList AssociatedResources(VD, NameBuilder.getName());
2117
2118 // Callback to fill in the associated resource.
2119 auto EmitResFn = [&](AggValueSlot &ResSlot) {
2120 const VarDecl *ResDecl = AssociatedResources.getNextResource();
2121 assert(ResDecl && "associated resource declaration not found");
2122
2123 // Check that the resource type of dest and src matches.
2124 [[maybe_unused]] llvm::Type *DestType =
2125 ResSlot.getAddress().getElementType();
2126 [[maybe_unused]] llvm::Type *SrcConvertedType =
2127 CGM.getTypes().ConvertTypeForMem(ResDecl->getType());
2128 assert(DestType == SrcConvertedType && "resource slot type mismatch");
2129
2130 if (ResDecl->getType()->isHLSLResourceRecord())
2131 copyGlobalResource(CGF, ResDecl, ResSlot);
2132 else
2133 initializeGlobalResourceArray(CGF, ResDecl, ResSlot);
2134 };
2135
2136 auto Result =
2137 HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty, EmitResFn);
2138 assert(AssociatedResources.getNextResource() == nullptr &&
2139 "expected all associated resources to be processed");
2140 return Result;
2141}
2142
2144 const MemberExpr *E) {
2145 LValue Base =
2147 auto *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
2148 assert(Field && "Unexpected access into HLSL buffer");
2149
2150 const RecordDecl *Rec = Field->getParent();
2151
2152 // Work out the buffer layout type to index into.
2153 QualType RecType = CGM.getContext().getCanonicalTagType(Rec);
2154 assert(RecType->isStructureOrClassType() && "Invalid type in HLSL buffer");
2155 // Since this is a member of an object in the buffer and not the buffer's
2156 // struct/class itself, we shouldn't have any offsets on the members we need
2157 // to contend with.
2158 CGHLSLOffsetInfo EmptyOffsets;
2159 llvm::StructType *LayoutTy = HLSLBufferLayoutBuilder(CGM).layOutStruct(
2160 RecType->getAsCanonical<RecordType>(), EmptyOffsets);
2161
2162 // Get the field index for the layout struct, accounting for padding.
2163 unsigned FieldIdx =
2164 CGM.getTypes().getCGRecordLayout(Rec).getLLVMFieldNo(Field);
2165 assert(FieldIdx < LayoutTy->getNumElements() &&
2166 "Layout struct is smaller than member struct");
2167 unsigned Skipped = 0;
2168 for (unsigned I = 0; I <= FieldIdx;) {
2169 llvm::Type *ElementTy = LayoutTy->getElementType(I + Skipped);
2170 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(ElementTy))
2171 ++Skipped;
2172 else
2173 ++I;
2174 }
2175 FieldIdx += Skipped;
2176 assert(FieldIdx < LayoutTy->getNumElements() && "Access out of bounds");
2177
2178 // Now index into the struct, making sure that the type we return is the
2179 // buffer layout type rather than the original type in the AST.
2180 QualType FieldType = Field->getType();
2181 llvm::Type *FieldLLVMTy = CGM.getTypes().ConvertTypeForMem(FieldType);
2183 CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy));
2184
2185 Value *Ptr = CGF.getLangOpts().EmitLogicalPointer
2186 ? CGF.Builder.CreateStructuredGEP(
2187 LayoutTy, Base.getPointer(CGF),
2188 llvm::ConstantInt::get(CGM.IntTy, FieldIdx))
2189 : CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF),
2190 FieldIdx, Field->getName());
2191 Address Addr(Ptr, FieldLLVMTy, Align, KnownNonNull);
2192
2193 LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(),
2195 CGM.getTBAAAccessInfo(FieldType));
2196 LV.getQuals().addCVRQualifiers(Base.getVRQualifiers());
2197
2198 return LV;
2199}
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, bool NeedsFlat)
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)
static bool inputRequiresFlatDecoration(llvm::Type *Ty)
Result
Implement __builtin_bit_cast and related operations.
llvm::MachO::Record Record
Definition MachO.h:31
#define SM(sm)
Defines the SourceManager interface.
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:223
SourceManager & getSourceManager()
Definition ASTContext.h:869
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
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
unsigned getTargetAddressSpace(LangAS AS) const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition Expr.h:2727
QualType getElementType() const
Definition TypeBase.h:3833
Attr - This represents one attribute.
Definition Attr.h:46
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2145
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
QualType withConst() const
Retrieves a version of this type with const applied.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3682
CastKind getCastKind() const
Definition Expr.h:3726
Expr * getSubExpr()
Definition Expr.h:3732
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
CharUnits getAlignment() const
Definition Address.h:194
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:146
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Definition CGBuilder.h:302
Address CreateStructGEP(Address Addr, unsigned Index, const llvm::Twine &Name="")
Definition CGBuilder.h:229
Abstract information about a function or function prototype.
Definition CGCall.h:43
All available information about a concrete callee.
Definition CGCall.h:65
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)
std::optional< LValue > emitResourceMemberExpr(CodeGenFunction &CGF, const MemberExpr *E)
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)
std::optional< LValue > emitGlobalResourceArrayAsLValue(CodeGenFunction &CGF, const VarDecl *ArrayDecl)
void handleScalarSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic)
bool emitBufferCopy(CodeGenFunction &CGF, const Expr *E, const LValue &SrcLV, AggValueSlot &DestSlot)
std::pair< llvm::Value *, specific_attr_iterator< HLSLAppliedSemanticAttr > > handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > begin, specific_attr_iterator< HLSLAppliedSemanticAttr > end)
std::optional< LValue > emitBufferArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF, llvm::function_ref< llvm::Value *(bool Promote)> EmitIdxAfterBase)
std::optional< LValue > emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF)
void addRootSignature(const HLSLRootSignatureDecl *D)
LValue emitBufferMemberExpr(CodeGenFunction &CGF, const MemberExpr *E)
llvm::Type * convertHLSLSpecificType(const Type *T, const CGHLSLOffsetInfo &OffsetInfo)
RawAddress createBufferMatrixTempAddress(const LValue &LV, CodeGenFunction &CGF)
quad_read_across_diagonal resource_getpointer resource_handlefrombinding resource_nonuniformindex device_memory_barrier_with_group_sync resource_getdimensions_levels_xy GENERATE_HLSL_INTRINSIC_FUNCTION(CalculateLodUnclamped, resource_calculate_lod_unclamped) protected 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)
bool emitGlobalResourceArray(CodeGenFunction &CGF, const Expr *E, AggValueSlot &DestSlot)
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E)
unsigned getLLVMFieldNo(const FieldDecl *FD) const
Return llvm::StructType element number that corresponds to the field FD.
CallArgList - Type for representing both the value and type of arguments in a call.
Definition CGCall.h:276
void add(RValue rvalue, QualType type)
Definition CGCall.h:304
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...
const LangOptions & getLangOpts() const
@ 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.
AggValueSlot CreateAggTemp(QualType T, const Twine &Name="tmp", RawAddress *Alloca=nullptr)
CreateAggTemp - Create a temporary memory object for the given aggregate type.
bool EmitLifetimeStart(llvm::Value *Addr)
Emit a lifetime.begin marker if some criteria are satisfied.
Definition CGDecl.cpp:1364
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:5624
RawAddress CreateMemTempWithoutCast(QualType T, const Twine &Name="tmp")
CreateMemTemp - Create a temporary memory object of the given type, with appropriate alignmen without...
Definition CGExpr.cpp:232
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:281
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:1621
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK)
Same as EmitLValue but additionally we generate checking code to guard against undefined behavior.
Definition CGExpr.cpp:1702
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:1737
bool isOpaqueValueEmitted(const OpaqueValueExpr *E)
isOpaqueValueEmitted - Return true if the opaque value expression has already been emitted.
Definition CGExpr.cpp:6448
llvm::LLVMContext & getLLVMContext()
This class organizes the cross-function state that is used while generating LLVM code.
const PreprocessorOptions & getPreprocessorOpts() const
CGHLSLRuntime & getHLSLRuntime()
Return a reference to the configured HLSL runtime.
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 LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
void EmitGlobal(GlobalDecl D)
Emit code for a single global function or var decl.
const llvm::DataLayout & getDataLayout() const
TBAAAccessInfo getTBAAAccessInfo(QualType AccessType)
getTBAAAccessInfo - Get TBAA information that describes an access to an object of the given type.
ASTContext & getContext() const
llvm::Constant * GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty=nullptr, ForDefinition_t IsForDefinition=NotForDefinition)
Return the llvm::Constant for the address of the given global variable.
const TargetCodeGenInfo & getTargetCodeGenInfo()
const CodeGenOptions & getCodeGenOpts() const
llvm::LLVMContext & getLLVMContext()
llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys={})
void EmitTopLevelDecl(Decl *D)
Emit code for a single top level declaration.
ConstantAddress GetAddrOfConstantCString(const std::string &Str, StringRef GlobalName=".str")
Returns a pointer to a character array containing the literal and a terminating '\0' character.
const CGFunctionInfo & arrangeFreeFunctionCall(const CallArgList &Args, const FunctionType *Ty, bool ChainCall, const FunctionDecl *ABIInfoFD)
Figure out the rules for calling a function with the given formal type using the given arguments.
Definition CGCall.cpp:731
llvm::Type * ConvertType(QualType T)
ConvertType - Convert type T into a llvm::Type.
const CGRecordLayout & getCGRecordLayout(const RecordDecl *)
getCGRecordLayout - Return record layout info for the given record decl.
llvm::Type * ConvertTypeForMem(QualType T)
ConvertTypeForMem - Convert type T into a llvm::Type.
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
QualType getType() const
Definition CGValue.h:303
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:383
virtual bool isHLSLPadding(llvm::Type *Ty) const
Return true if this is an HLSL padding type.
Definition TargetInfo.h:443
virtual llvm::Type * getHLSLPadding(CodeGenModule &CGM, CharUnits NumBytes) const
Return an LLVM type that corresponds to padding in HLSL types.
Definition TargetInfo.h:437
virtual llvm::Type * getHLSLType(CodeGenModule &CGM, const Type *T, const CGHLSLOffsetInfo &OffsetInfo) const
Return an LLVM type that corresponds to a HLSL type.
Definition TargetInfo.h:431
Represents the canonical version of C arrays with a specified constant size.
Definition TypeBase.h:3859
int64_t getSExtSize() const
Return the size sign-extended as a uint64_t.
Definition TypeBase.h:3941
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2126
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:581
bool hasAttrs() const
Definition DeclBase.h:526
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition DeclBase.h:601
specific_attr_iterator< T > specific_attr_end() const
Definition DeclBase.h:577
specific_attr_iterator< T > specific_attr_begin() const
Definition DeclBase.h:572
AttrVec & getAttrs()
Definition DeclBase.h:532
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:3101
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3081
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3204
StringRef getName() const
The name of this FileEntry.
Definition FileEntry.h:61
Represents a function declaration or definition.
Definition Decl.h:2029
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2837
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:2902
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5406
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5238
bool isCBuffer() const
Definition Decl.h:5282
const CXXRecordDecl * getLayoutStruct() const
Definition Decl.h:5285
bool hasValidPackoffset() const
Definition Decl.h:5284
buffer_decl_range buffer_decls() const
Definition Decl.h:5313
This class represents temporary values used to represent inout and out arguments in HLSL.
Definition Expr.h:7409
ArrayRef< llvm::hlsl::rootsig::RootElement > getRootElements() const
Definition Decl.h:5355
llvm::dxbc::RootSignatureVersion getVersion() const
Definition Decl.h:5353
One of these records is kept for each identifier that is lexed.
Describes an C or C++ initializer list.
Definition Expr.h:5314
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3370
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3453
Expr * getBase() const
Definition Expr.h:3447
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:295
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:1184
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Definition Expr.h:1234
Represents a parameter to a function.
Definition Decl.h:1819
std::vector< std::pair< std::string, bool > > Macros
A (possibly-)qualified type.
Definition TypeBase.h:938
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8489
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8615
The collection of all-type qualifiers we support.
Definition TypeBase.h:332
void addCVRQualifiers(unsigned mask)
Definition TypeBase.h:503
Represents a struct/union/class.
Definition Decl.h:4369
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
Definition Decl.h:4585
field_iterator field_begin() const
Definition Decl.cpp:5275
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.
One instance of this struct is kept for every file loaded or used.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM, SourceLocation Loc=SourceLocation()) const
Returns the memory buffer for the associated content.
OptionalFileEntryRef OrigEntry
Reference to the file entry representing this ContentCache.
Information about a FileID, basically just the logical file that it represents and include stack info...
const ContentCache & getContentCache() const
CharacteristicKind getFileCharacteristic() const
Return whether this is a system header or not.
This is a discriminated union of FileInfo and ExpansionInfo.
const FileInfo & getFile() const
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition TargetInfo.h:330
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:1876
bool isIncompleteArrayType() const
Definition TypeBase.h:8833
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:8825
bool isConstantMatrixType() const
Definition TypeBase.h:8893
bool isHLSLIntangibleType() const
Definition Type.cpp:5527
bool isHLSLResourceRecord() const
Definition Type.cpp:5514
bool isStructureOrClassType() const
Definition Type.cpp:743
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2986
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9319
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:690
bool isRecordType() const
Definition TypeBase.h:8853
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5518
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:932
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1247
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:1174
void pushBaseNameHierarchy(CXXRecordDecl *DerivedRD, CXXRecordDecl *BaseRD)
IdentifierInfo * getNameAsIdentifier(ASTContext &AST) const
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
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
bool hasCounterHandle(const CXXRecordDecl *RD)
StringRef getName(const HeaderType T)
Definition HeaderFile.h:38
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
bool Load(InterpState &S, CodePtr OpPC)
Definition Interp.h:2230
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:196
std::vector< std::string > Macros
A list of macros of the form <definition>=<expansion> .
Definition Format.h:3951
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
StorageClass
Storage classes.
Definition Specifiers.h:249
@ SC_Static
Definition Specifiers.h:253
@ SC_None
Definition Specifiers.h:251
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
unsigned getCounterImplicitOrderID() const