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