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