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, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
1439 HLSLAppliedSemanticAttr *Semantic,
1440 llvm::dxbc::PSV::SemanticKind SemanticKind,
1441 llvm::Triple::EnvironmentType Stage, std::optional<unsigned> Index,
1442 SemanticSignatures &Signature) {
1443 switch (SemanticKind) {
1444 case llvm::dxbc::PSV::SemanticKind::GroupIndex: {
1445 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1446 llvm::Triple::Amplification},
1447 Stage) &&
1448 "SV_GroupIndex is in an unavailable stage and should have been "
1449 "diagnosed by Sema");
1450 assert(Stage != llvm::Triple::Mesh &&
1451 Stage != llvm::Triple::Amplification &&
1452 "FIXME: SV_GroupIndex is not yet implemented for this shader "
1453 "stage");
1454 llvm::Function *GroupIndex =
1455 CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
1456 return B.CreateCall(FunctionCallee(GroupIndex));
1457 }
1458 case llvm::dxbc::PSV::SemanticKind::DispatchThreadID: {
1459 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1460 llvm::Triple::Amplification},
1461 Stage) &&
1462 "SV_DispatchThreadID is in an unavailable stage and should have "
1463 "been diagnosed by Sema");
1464 assert(Stage != llvm::Triple::Mesh &&
1465 Stage != llvm::Triple::Amplification &&
1466 "FIXME: SV_DispatchThreadID is not yet implemented for this "
1467 "shader stage");
1468 llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
1469 llvm::Function *ThreadIDIntrinsic =
1470 llvm::Intrinsic::isOverloaded(IntrinID)
1471 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1472 : CGM.getIntrinsic(IntrinID);
1473 return buildVectorInput(B, ThreadIDIntrinsic, Type);
1474 }
1475 case llvm::dxbc::PSV::SemanticKind::GroupThreadID: {
1476 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1477 llvm::Triple::Amplification},
1478 Stage) &&
1479 "SV_GroupThreadID is in an unavailable stage and should have been "
1480 "diagnosed by Sema");
1481 assert(Stage != llvm::Triple::Mesh &&
1482 Stage != llvm::Triple::Amplification &&
1483 "FIXME: SV_GroupThreadID is not yet implemented for this shader "
1484 "stage");
1485 llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
1486 llvm::Function *GroupThreadIDIntrinsic =
1487 llvm::Intrinsic::isOverloaded(IntrinID)
1488 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1489 : CGM.getIntrinsic(IntrinID);
1490 return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
1491 }
1492 case llvm::dxbc::PSV::SemanticKind::GroupID: {
1493 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1494 llvm::Triple::Amplification},
1495 Stage) &&
1496 "SV_GroupID is in an unavailable stage and should have been "
1497 "diagnosed by Sema");
1498 assert(Stage != llvm::Triple::Mesh &&
1499 Stage != llvm::Triple::Amplification &&
1500 "FIXME: SV_GroupID is not yet implemented for this shader stage");
1501 llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
1502 llvm::Function *GroupIDIntrinsic =
1503 llvm::Intrinsic::isOverloaded(IntrinID)
1504 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1505 : CGM.getIntrinsic(IntrinID);
1506 return buildVectorInput(B, GroupIDIntrinsic, Type);
1507 }
1508 case llvm::dxbc::PSV::SemanticKind::Position:
1509 assert(llvm::is_contained({llvm::Triple::Hull, llvm::Triple::Domain,
1510 llvm::Triple::Geometry, llvm::Triple::Pixel},
1511 Stage) &&
1512 "SV_Position is in an unavailable stage and should have been "
1513 "diagnosed by Sema");
1514 assert(Stage != llvm::Triple::Hull && Stage != llvm::Triple::Domain &&
1515 Stage != llvm::Triple::Geometry &&
1516 "FIXME: loading SV_Position is not yet implemented for this "
1517 "shader stage");
1518 if (CGM.getTarget().getTriple().isSPIRV())
1519 return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
1520 Semantic->getAttrName()->getName(),
1521 /* BuiltIn::FragCoord */ 15);
1522 if (CGM.getTarget().getTriple().isDXIL())
1523 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1524 Signature);
1525 break;
1526 case llvm::dxbc::PSV::SemanticKind::VertexID:
1527 assert(Stage == llvm::Triple::Vertex &&
1528 "SV_VertexID is in an unavailable stage and should have been "
1529 "diagnosed by Sema");
1530 if (CGM.getTarget().getTriple().isSPIRV())
1531 return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
1532 Semantic->getAttrName()->getName(),
1533 /* BuiltIn::VertexIndex */ 42);
1534 if (CGM.getTarget().getTriple().isDXIL())
1535 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1536 Signature);
1537 break;
1538 default:
1539 break;
1540 }
1541
1542 llvm_unreachable(
1543 "Load hasn't been implemented yet for this system semantic. FIXME");
1544}
1545
1546static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M,
1547 llvm::Value *Source, const Twine &Name,
1548 unsigned BuiltInID) {
1549 auto *GV = new llvm::GlobalVariable(
1550 M, Source->getType(), /* isConstant= */ false,
1551 llvm::GlobalValue::ExternalLinkage,
1552 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
1553 llvm::GlobalVariable::GeneralDynamicTLSModel,
1554 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
1555 addSPIRVBuiltinDecoration(GV, BuiltInID);
1556 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1557 B.CreateStore(Source, GV);
1558}
1559
1561 IRBuilder<> &B, llvm::Value *Source, const clang::DeclaratorDecl *Decl,
1562 HLSLAppliedSemanticAttr *Semantic,
1563 llvm::dxbc::PSV::SemanticKind SemanticKind,
1564 llvm::Triple::EnvironmentType Stage, std::optional<unsigned> Index,
1565 SemanticSignatures &Signature) {
1566 switch (SemanticKind) {
1567 case llvm::dxbc::PSV::SemanticKind::Position:
1568 assert(llvm::is_contained({llvm::Triple::Vertex, llvm::Triple::Hull,
1569 llvm::Triple::Domain, llvm::Triple::Geometry,
1570 llvm::Triple::Mesh},
1571 Stage) &&
1572 "SV_Position is in an unavailable stage and should have been "
1573 "diagnosed by Sema");
1574 assert(Stage != llvm::Triple::Hull && Stage != llvm::Triple::Domain &&
1575 Stage != llvm::Triple::Geometry && Stage != llvm::Triple::Mesh &&
1576 "FIXME: storing SV_Position is not yet implemented for this "
1577 "shader stage");
1578 if (CGM.getTarget().getTriple().isDXIL()) {
1579 emitDXILUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
1580 return;
1581 }
1582 if (CGM.getTarget().getTriple().isSPIRV()) {
1583 createSPIRVBuiltinStore(B, CGM.getModule(), Source,
1584 Semantic->getAttrName()->getName(),
1585 /* BuiltIn::Position */ 0);
1586 return;
1587 }
1588 break;
1589 case llvm::dxbc::PSV::SemanticKind::Target:
1590 assert(Stage == llvm::Triple::Pixel &&
1591 "SV_Target is in an unavailable stage and should have been "
1592 "diagnosed by Sema");
1593 emitUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
1594 return;
1595 default:
1596 break;
1597 }
1598
1599 llvm_unreachable(
1600 "Store hasn't been implemented yet for this system semantic. FIXME");
1601}
1602
1604 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1605 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1606 SemanticSignatures &Signature) {
1607
1608 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1609 llvm::dxbc::PSV::SemanticKind SemanticKind =
1610 llvm::hlsl::getSemanticKind(Semantic->getAttrName()->getName());
1611 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1612 assert(ShaderAttr && "Entry point has no shader attribute");
1613 llvm::hlsl::SemanticInterpretation Interpretation =
1614 llvm::hlsl::getInterpretationKind(SemanticKind, ShaderAttr->getType(),
1615 llvm::hlsl::IOType::In);
1616 assert(Interpretation != llvm::hlsl::SemanticInterpretation::Invalid &&
1617 "invalid semantic should have been diagnosed by Sema");
1618 if (Interpretation == llvm::hlsl::SemanticInterpretation::Arbitrary)
1619 return emitUserSemanticLoad(B, FD, Type, Decl, Semantic, Index, Signature);
1620 return emitSystemSemanticLoad(B, Type, Decl, Semantic, SemanticKind,
1621 ShaderAttr->getType(), Index, Signature);
1622}
1623
1625 const FunctionDecl *FD,
1626 llvm::Value *Source,
1628 HLSLAppliedSemanticAttr *Semantic,
1629 SemanticSignatures &Signature) {
1630 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1631 llvm::dxbc::PSV::SemanticKind SemanticKind =
1632 llvm::hlsl::getSemanticKind(Semantic->getAttrName()->getName());
1633 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1634 assert(ShaderAttr && "Entry point has no shader attribute");
1635
1636 llvm::hlsl::SemanticInterpretation Interpretation =
1637 llvm::hlsl::getInterpretationKind(SemanticKind, ShaderAttr->getType(),
1638 llvm::hlsl::IOType::Out);
1639 assert(Interpretation != llvm::hlsl::SemanticInterpretation::Invalid &&
1640 "invalid semantic should have been diagnosed by Sema");
1641
1642 if (Interpretation == llvm::hlsl::SemanticInterpretation::Arbitrary)
1643 return emitUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
1644 emitSystemSemanticStore(B, Source, Decl, Semantic, SemanticKind,
1645 ShaderAttr->getType(), Index, Signature);
1646}
1647
1648std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1650 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1654 SemanticSignatures &Signature) {
1655 const llvm::StructType *ST = cast<StructType>(Type);
1656 const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();
1657
1658 assert(RD->getNumFields() == ST->getNumElements());
1659
1660 llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
1661 auto FieldDecl = RD->field_begin();
1662 for (unsigned I = 0; I < ST->getNumElements(); ++I) {
1663 auto [ChildValue, NextAttr] =
1664 handleSemanticLoad(B, FD, ST->getElementType(I), *FieldDecl, AttrBegin,
1665 AttrEnd, Signature);
1666 AttrBegin = NextAttr;
1667 assert(ChildValue);
1668 Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
1669 ++FieldDecl;
1670 }
1671
1672 return std::make_pair(Aggregate, AttrBegin);
1673}
1674
1677 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
1681 SemanticSignatures &Signature) {
1682
1683 const llvm::StructType *ST = cast<StructType>(Source->getType());
1684
1685 const clang::RecordDecl *RD = nullptr;
1686 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
1688 else
1689 RD = Decl->getType()->getAsRecordDecl();
1690 assert(RD);
1691
1692 assert(RD->getNumFields() == ST->getNumElements());
1693
1694 auto FieldDecl = RD->field_begin();
1695 for (unsigned I = 0; I < ST->getNumElements(); ++I, ++FieldDecl) {
1696 llvm::Value *Extract = B.CreateExtractValue(Source, I);
1697 AttrBegin = handleSemanticStore(B, FD, Extract, *FieldDecl, AttrBegin,
1698 AttrEnd, Signature);
1699 }
1700
1701 return AttrBegin;
1702}
1703
1704std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1706 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1710 SemanticSignatures &Signature) {
1711 assert(AttrBegin != AttrEnd);
1712 if (Type->isStructTy())
1713 return handleStructSemanticLoad(B, FD, Type, Decl, AttrBegin, AttrEnd,
1714 Signature);
1715
1716 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
1717 ++AttrBegin;
1718 return std::make_pair(
1719 handleScalarSemanticLoad(B, FD, Type, Decl, Attr, Signature), AttrBegin);
1720}
1721
1724 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
1728 SemanticSignatures &Signature) {
1729 assert(AttrBegin != AttrEnd);
1730 if (Source->getType()->isStructTy())
1731 return handleStructSemanticStore(B, FD, Source, Decl, AttrBegin, AttrEnd,
1732 Signature);
1733
1734 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
1735 ++AttrBegin;
1736 handleScalarSemanticStore(B, FD, Source, Decl, Attr, Signature);
1737 return AttrBegin;
1738}
1739
1741 llvm::Function *Fn) {
1744
1745 llvm::Module &M = CGM.getModule();
1746 llvm::LLVMContext &Ctx = M.getContext();
1747 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
1748 Function *EntryFn =
1749 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
1750
1751 // Copy function attributes over, we have no argument or return attributes
1752 // that can be valid on the real entry.
1753 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
1754 Fn->getAttributes().getFnAttrs());
1755 EntryFn->setAttributes(NewAttrs);
1756 setHLSLEntryAttributes(FD, EntryFn);
1757
1758 // Set the called function as internal linkage.
1759 Fn->setLinkage(GlobalValue::InternalLinkage);
1760
1761 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
1762 IRBuilder<> B(BB);
1764
1766 if (CGM.shouldEmitConvergenceTokens()) {
1767 assert(EntryFn->isConvergent());
1768 llvm::Value *I =
1769 B.CreateIntrinsic(llvm::Intrinsic::experimental_convergence_entry, {});
1770 llvm::Value *bundleArgs[] = {I};
1771 OB.emplace_back("convergencectrl", bundleArgs);
1772 }
1773
1775
1776 unsigned SRetOffset = 0;
1777 for (const auto &Param : Fn->args()) {
1778 if (Param.hasStructRetAttr()) {
1779 SRetOffset = 1;
1780 llvm::Type *VarType = Param.getParamStructRetType();
1781 llvm::Value *Var =
1782 CGM.getLangOpts().EmitLogicalPointer
1783 ? cast<Instruction>(B.CreateStructuredAlloca(VarType))
1784 : cast<Instruction>(B.CreateAlloca(VarType));
1785 OutputSemantic.push_back(std::make_pair(Var, VarType));
1786 Args.push_back(Var);
1787 continue;
1788 }
1789
1790 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
1791 llvm::Value *SemanticValue = nullptr;
1792 // FIXME: support inout/out parameters for semantics.
1793 if ([[maybe_unused]] HLSLParamModifierAttr *MA =
1794 PD->getAttr<HLSLParamModifierAttr>()) {
1795 llvm_unreachable("Not handled yet");
1796 } else {
1797 llvm::Type *ParamType = nullptr;
1798 if (Param.hasByValAttr())
1799 ParamType = Param.getParamByValType();
1800 else if (PD->getType()->isRecordType())
1801 ParamType = CGM.getTypes().ConvertType(PD->getType());
1802 else
1803 ParamType = Param.getType();
1804
1805 auto AttrBegin = PD->specific_attr_begin<HLSLAppliedSemanticAttr>();
1806 auto AttrEnd = PD->specific_attr_end<HLSLAppliedSemanticAttr>();
1807 auto Result = handleSemanticLoad(B, FD, ParamType, PD, AttrBegin, AttrEnd,
1808 InputSignature);
1809 SemanticValue = Result.first;
1810 if (!SemanticValue)
1811 return;
1812 if (Param.hasByValAttr() || PD->getType()->isRecordType()) {
1813 llvm::Value *Var =
1814 CGM.getLangOpts().EmitLogicalPointer
1815 ? cast<Instruction>(B.CreateStructuredAlloca(ParamType))
1816 : cast<Instruction>(B.CreateAlloca(ParamType));
1817 B.CreateStore(SemanticValue, Var);
1818 SemanticValue = Var;
1819 }
1820 }
1821
1822 assert(SemanticValue);
1823 Args.push_back(SemanticValue);
1824 }
1825
1826 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
1827 CI->setCallingConv(Fn->getCallingConv());
1828
1829 if (Fn->getReturnType() != CGM.VoidTy)
1830 // Element type is unused, so set to dummy value (NULL).
1831 OutputSemantic.push_back(std::make_pair(CI, nullptr));
1832
1833 for (auto &SourcePair : OutputSemantic) {
1834 llvm::Value *Source = SourcePair.first;
1835 llvm::Type *ElementType = SourcePair.second;
1836 AllocaInst *AI = dyn_cast<AllocaInst>(Source);
1837 llvm::Value *SourceValue = AI ? B.CreateLoad(ElementType, Source) : Source;
1838
1839 auto AttrBegin = FD->specific_attr_begin<HLSLAppliedSemanticAttr>();
1840 auto AttrEnd = FD->specific_attr_end<HLSLAppliedSemanticAttr>();
1841 handleSemanticStore(B, FD, SourceValue, FD, AttrBegin, AttrEnd,
1842 OutputSignature);
1843 }
1844
1845 B.CreateRetVoid();
1846
1847 // Add and identify root signature to function, if applicable
1848 for (const Attr *Attr : FD->getAttrs()) {
1849 if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) {
1850 auto *RSDecl = RSAttr->getSignatureDecl();
1851 addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
1852 EntryFn, M);
1853 }
1854 }
1855
1856 addSemanticSignatureMD(InputSignature, OutputSignature, EntryFn, M);
1857}
1858
1859static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
1860 bool CtorOrDtor) {
1861 const auto *GV =
1862 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
1863 if (!GV)
1864 return;
1865 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
1866 if (!CA)
1867 return;
1868 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
1869 // HLSL neither supports priorities or COMDat values, so we will check those
1870 // in an assert but not handle them.
1871
1872 for (const auto &Ctor : CA->operands()) {
1874 continue;
1875 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
1876
1877 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
1878 "HLSL doesn't support setting priority for global ctors.");
1879 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
1880 "HLSL doesn't support COMDat for global ctors.");
1881 Fns.push_back(cast<Function>(CS->getOperand(1)));
1882 }
1883}
1884
1886 llvm::Module &M = CGM.getModule();
1889 gatherFunctions(CtorFns, M, true);
1890 gatherFunctions(DtorFns, M, false);
1891
1892 // Insert a call to the global constructor at the beginning of the entry block
1893 // to externally exported functions. This is a bit of a hack, but HLSL allows
1894 // global constructors, but doesn't support driver initialization of globals.
1895 for (auto &F : M.functions()) {
1896 if (!F.hasFnAttribute("hlsl.shader"))
1897 continue;
1898 auto *Token = getConvergenceToken(F.getEntryBlock());
1899 Instruction *IP = &*F.getEntryBlock().begin();
1901 if (Token) {
1902 llvm::Value *bundleArgs[] = {Token};
1903 OB.emplace_back("convergencectrl", bundleArgs);
1904 IP = Token->getNextNode();
1905 }
1906 IRBuilder<> B(IP);
1907 for (auto *Fn : CtorFns) {
1908 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1909 CI->setCallingConv(Fn->getCallingConv());
1910 }
1911
1912 // Insert global dtors before the terminator of the last instruction
1913 B.SetInsertPoint(F.back().getTerminator());
1914 for (auto *Fn : DtorFns) {
1915 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1916 CI->setCallingConv(Fn->getCallingConv());
1917 }
1918 }
1919
1920 // No need to keep global ctors/dtors for non-lib profile after call to
1921 // ctors/dtors added for entry.
1922 Triple T(M.getTargetTriple());
1923 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
1924 if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
1925 GV->eraseFromParent();
1926 if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
1927 GV->eraseFromParent();
1928 }
1929}
1930
1931static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
1932 Intrinsic::ID IntrID,
1934
1935 LLVMContext &Ctx = CGM.getLLVMContext();
1936 llvm::Function *InitResFunc =
1937 llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, false),
1938 llvm::GlobalValue::InternalLinkage,
1939 "_init_buffer_" + GV->getName(), CGM.getModule());
1940 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1941
1942 llvm::BasicBlock *EntryBB =
1943 llvm::BasicBlock::Create(Ctx, "entry", InitResFunc);
1944 CGBuilderTy Builder(CGM, Ctx);
1945 const DataLayout &DL = CGM.getModule().getDataLayout();
1946 Builder.SetInsertPoint(EntryBB);
1947
1948 // Make sure the global variable is buffer resource handle
1949 llvm::Type *HandleTy = GV->getValueType();
1950 assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");
1951
1952 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
1953 /*ReturnType=*/HandleTy, IntrID, Args, nullptr,
1954 Twine(GV->getName()).concat("_h"));
1955
1956 Builder.CreateAlignedStore(CreateHandle, GV, GV->getPointerAlignment(DL));
1957 Builder.CreateRetVoid();
1958
1959 CGM.AddCXXGlobalInit(InitResFunc);
1960}
1961
1962void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
1963 llvm::GlobalVariable *GV) {
1964 ResourceBindingAttrs Binding(BufDecl);
1965 assert(Binding.hasBinding() &&
1966 "cbuffer/tbuffer should always have resource binding attribute");
1967
1968 auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
1969 auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
1970 auto *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
1971 Value *Name = buildNameForResource(BufDecl->getName(), CGM);
1972
1973 // buffer with explicit binding
1974 if (Binding.isExplicit()) {
1975 llvm::Intrinsic::ID IntrinsicID =
1976 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
1977 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
1978 SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
1979 initializeBuffer(CGM, GV, IntrinsicID, Args);
1980 } else {
1981 // buffer with implicit binding
1982 llvm::Intrinsic::ID IntrinsicID =
1983 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
1984 auto *OrderID =
1985 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
1986 SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
1987 initializeBuffer(CGM, GV, IntrinsicID, Args);
1988 }
1989}
1990
1992 llvm::GlobalVariable *GV) {
1993 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
1994 addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
1995 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinOutputAttr>())
1996 addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
1997}
1998
1999llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
2000 if (!CGM.shouldEmitConvergenceTokens())
2001 return nullptr;
2002
2003 auto E = BB.end();
2004 for (auto I = BB.begin(); I != E; ++I) {
2005 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
2006 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
2007 return II;
2008 }
2009 }
2010 llvm_unreachable("Convergence token should have been emitted.");
2011 return nullptr;
2012}
2013
2014class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
2015public:
2019
2021 // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
2022 // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
2023 // traversal, the temporary containing the copy out will not have
2024 // been created yet.
2025 return false;
2026 }
2027
2029 // Traverse the source expression first.
2030 if (E->getSourceExpr())
2032
2033 // Then add this OVE if we haven't seen it before.
2034 if (Visited.insert(E).second)
2035 OVEs.push_back(E);
2036
2037 return true;
2038 }
2039};
2040
2042 InitListExpr *E) {
2043
2044 typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
2045 OpaqueValueVisitor Visitor;
2046 Visitor.TraverseStmt(E);
2047 for (auto *OVE : Visitor.OVEs) {
2048 if (CGF.isOpaqueValueEmitted(OVE))
2049 continue;
2050 if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
2051 LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
2052 OpaqueValueMappingData::bind(CGF, OVE, LV);
2053 } else {
2054 RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
2055 OpaqueValueMappingData::bind(CGF, OVE, RV);
2056 }
2057 }
2058}
2059
2061 const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
2062 assert((ArraySubsExpr->getType()->isHLSLResourceRecord() ||
2063 ArraySubsExpr->getType()->isHLSLResourceRecordArray()) &&
2064 "expected resource array subscript expression");
2065
2066 // Let clang codegen handle local and static resource array subscripts,
2067 // or when the subscript references on opaque expression (as part of
2068 // ArrayInitLoopExpr AST node).
2069 const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(
2070 getArrayDecl(CGF.CGM.getContext(), ArraySubsExpr));
2071 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
2072 ArrayDecl->getStorageClass() == SC_Static)
2073 return std::nullopt;
2074
2075 // get the resource array type
2076 ASTContext &AST = ArrayDecl->getASTContext();
2077 const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
2078 assert(ResArrayTy->isHLSLResourceRecordArray() &&
2079 "expected array of resource classes");
2080
2081 // Iterate through all nested array subscript expressions to calculate
2082 // the index in the flattened resource array (if this is a multi-
2083 // dimensional array). The index is calculated as a sum of all indices
2084 // multiplied by the total size of the array at that level.
2085 Value *Index = nullptr;
2086 const ArraySubscriptExpr *ASE = ArraySubsExpr;
2087 while (ASE != nullptr) {
2088 Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
2089 if (const auto *ArrayTy =
2090 dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
2091 Value *Multiplier = llvm::ConstantInt::get(
2092 CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy));
2093 SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
2094 }
2095 Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
2096 ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
2097 }
2098
2099 // Find binding info for the resource array. For implicit binding
2100 // an HLSLResourceBindingAttr should have been added by SemaHLSL.
2101 ResourceBindingAttrs Binding(ArrayDecl);
2102 assert(Binding.hasBinding() &&
2103 "resource array must have a binding attribute");
2104
2105 // Find the individual resource type.
2106 QualType ResultTy = ArraySubsExpr->getType();
2107 QualType ResourceTy =
2108 ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy;
2109
2110 // Create a temporary variable for the result, which is either going
2111 // to be a single resource instance or a local array of resources (we need to
2112 // return an LValue).
2113 RawAddress TmpVar = CGF.CreateMemTempWithoutCast(ResultTy);
2114 if (CGF.EmitLifetimeStart(TmpVar.getPointer()))
2116 NormalEHLifetimeMarker, TmpVar);
2117
2122
2123 // Calculate total array size (= range size).
2124 llvm::Value *Range = llvm::ConstantInt::getSigned(
2125 CGM.IntTy, getTotalArraySize(AST, ResArrayTy));
2126
2127 // If the result of the subscript operation is a single resource, call the
2128 // constructor.
2129 if (ResultTy == ResourceTy) {
2130 CallArgList Args;
2131 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
2132 CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
2133 ArrayDecl->getName(), Binding, Args);
2134
2135 if (!CreateMethod) {
2136 // This can happen if someone creates an array of structs that looks like
2137 // an HLSL resource record array but it does not have the required static
2138 // create method. No binding will be generated for it.
2139 assert(!ResourceTy->getAsCXXRecordDecl()->isImplicit() &&
2140 "create method lookup should always succeed for built-in resource "
2141 "records");
2142 return std::nullopt;
2143 }
2144
2145 callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
2146
2147 } else {
2148 // The result of the subscript operation is a local resource array which
2149 // needs to be initialized.
2150 const ConstantArrayType *ArrayTy =
2152 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
2153 CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
2154 ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)});
2155 if (!EndIndex)
2156 return std::nullopt;
2157 }
2158 return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
2159}
2160
2161// Initialize all resources of a global resource array into provided slot.
2162bool CGHLSLRuntime::initializeGlobalResourceArray(CodeGenFunction &CGF,
2163 const VarDecl *ArrayDecl,
2164 AggValueSlot &DestSlot) {
2165 assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
2166 ArrayDecl->hasGlobalStorage() &&
2167 ArrayDecl->getStorageClass() != SC_Static &&
2168 "expected global non-static resource array");
2169
2170 // Find binding info for the resource array. For implicit binding
2171 // the HLSLResourceBindingAttr should have been added by SemaHLSL.
2172 ResourceBindingAttrs Binding(ArrayDecl);
2173 assert(Binding.hasBinding() &&
2174 "resource array must have a binding attribute");
2175
2176 // Find the individual resource type.
2177 ASTContext &AST = ArrayDecl->getASTContext();
2178 QualType ResTy = AST.getBaseElementType(ArrayDecl->getType());
2179 const auto *ResArrayTy =
2181
2182 // Create Value for index and total array size (= range size).
2183 int Size = getTotalArraySize(AST, ResArrayTy);
2184 llvm::Value *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
2185 llvm::Value *Range = llvm::ConstantInt::get(CGM.IntTy, Size);
2186
2187 // Initialize individual resources in the array into DestSlot.
2188 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
2189 CGF, ResTy->getAsCXXRecordDecl(), ResArrayTy, DestSlot, Range, Zero,
2190 ArrayDecl->getName(), Binding, {Zero});
2191 return EndIndex.has_value();
2192}
2193
2194// If the expression is a global resource array, initialize all of its resources
2195// into Dest. Returns false if no initialization has been performed and the
2196// array copy should be handled by the default codegen.
2198 AggValueSlot &DestSlot) {
2199 assert(E->getType()->isHLSLResourceRecordArray() &&
2200 "expected resource array");
2201
2202 // Find the array declaration for the expression. Fallback to the default
2203 // handling if it's not a global resource array.
2204 const VarDecl *ArrayDecl =
2205 dyn_cast_or_null<VarDecl>(getArrayDecl(CGF.CGM.getContext(), E));
2206 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
2207 ArrayDecl->getStorageClass() == SC_Static)
2208 return false;
2209
2210 return initializeGlobalResourceArray(CGF, ArrayDecl, DestSlot);
2211}
2212
2213// If the expression is a global resource array, create a temporary and
2214// initialize all of its resources, and return it as an LValue. Returns nullopt
2215// if no initialization has been performed and the handling should follow the
2216// default path.
2217std::optional<LValue>
2219 const VarDecl *ArrayDecl) {
2220 assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
2221 "expected resource array declaration");
2222
2223 if (!ArrayDecl->hasGlobalStorage() ||
2224 ArrayDecl->getStorageClass() == SC_Static)
2225 return std::nullopt;
2226
2227 AggValueSlot TmpArraySlot =
2228 CGF.CreateAggTemp(ArrayDecl->getType(), "tmpResArray");
2229 if (initializeGlobalResourceArray(CGF, ArrayDecl, TmpArraySlot))
2230 return CGF.MakeAddrLValue(TmpArraySlot.getAddress(), ArrayDecl->getType(),
2232 return std::nullopt;
2233}
2234
2236 CodeGenFunction &CGF) {
2237
2238 assert(LV.getType()->isConstantMatrixType() && "expected matrix type");
2240 "expected cbuffer matrix");
2241
2242 QualType MatQualTy = LV.getType();
2243 llvm::Type *LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(MatQualTy);
2244 Address SrcAddr = LV.getAddress();
2245
2246 if (LayoutTy == CGF.ConvertTypeForMem(MatQualTy))
2247 return SrcAddr;
2248
2249 RawAddress DestAlloca =
2250 CGF.CreateMemTempWithoutCast(MatQualTy, "matrix.buf.copy");
2251 HLSLBufferCopyEmitter(CGF, DestAlloca, SrcAddr).emitCopy(MatQualTy);
2252 return DestAlloca;
2253}
2254
2256 const ArraySubscriptExpr *E, CodeGenFunction &CGF,
2257 llvm::function_ref<llvm::Value *(bool Promote)> EmitIdxAfterBase) {
2258 // Find the element type to index by first padding the element type per HLSL
2259 // buffer rules, and then padding out to a 16-byte register boundary if
2260 // necessary.
2261 llvm::Type *LayoutTy =
2263 uint64_t LayoutSizeInBits =
2264 CGM.getDataLayout().getTypeSizeInBits(LayoutTy).getFixedValue();
2265 CharUnits ElementSize = CharUnits::fromQuantity(LayoutSizeInBits / 8);
2266 CharUnits RowAlignedSize = ElementSize.alignTo(CharUnits::fromQuantity(16));
2267 if (RowAlignedSize > ElementSize) {
2268 llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding(
2269 CGM, RowAlignedSize - ElementSize);
2270 assert(Padding && "No padding type for target?");
2271 LayoutTy = llvm::StructType::get(CGF.getLLVMContext(), {LayoutTy, Padding},
2272 /*isPacked=*/true);
2273 }
2274
2275 // If the layout type doesn't introduce any padding, we don't need to do
2276 // anything special.
2277 llvm::Type *OrigTy = CGF.CGM.getTypes().ConvertTypeForMem(E->getType());
2278 if (LayoutTy == OrigTy)
2279 return std::nullopt;
2280
2281 LValueBaseInfo EltBaseInfo;
2282 TBAAAccessInfo EltTBAAInfo;
2283
2284 // Index into the object as-if we have an array of the padded element type,
2285 // and then dereference the element itself to avoid reading padding that may
2286 // be past the end of the in-memory object.
2288 llvm::Value *Idx = EmitIdxAfterBase(/*Promote*/ true);
2289 Indices.push_back(Idx);
2290 Indices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
2291
2292 if (CGF.getLangOpts().EmitLogicalPointer) {
2293 // The fact that we emit an array-to-pointer decay might be an oversight,
2294 // but for now, we simply ignore it (see #179951).
2295 const CastExpr *CE = cast<CastExpr>(E->getBase());
2296 assert(CE->getCastKind() == CastKind::CK_ArrayToPointerDecay);
2297
2298 LValue LV = CGF.EmitLValue(CE->getSubExpr());
2299 Address Addr = LV.getAddress();
2300 LayoutTy = llvm::ArrayType::get(
2301 LayoutTy,
2302 cast<llvm::ArrayType>(Addr.getElementType())->getNumElements());
2303 auto *GEP = cast<StructuredGEPInst>(CGF.Builder.CreateStructuredGEP(
2304 LayoutTy, Addr.emitRawPointer(CGF), Indices, "cbufferidx"));
2305 Addr =
2306 Address(GEP, GEP->getResultElementType(), RowAlignedSize, KnownNonNull);
2307 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
2308 }
2309
2310 Address Addr =
2311 CGF.EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
2312 llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF),
2313 Indices, "cbufferidx");
2314 Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull);
2315 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
2316}
2317
2318std::optional<LValue>
2320 const MemberExpr *ME) {
2321 assert((ME->getType()->isHLSLResourceRecord() ||
2323 "expected resource member expression");
2324
2325 const VarDecl *ResourceVD =
2326 findAssociatedResourceDeclForStruct(CGF.CGM.getContext(), ME);
2327 if (!ResourceVD)
2328 return std::nullopt;
2329
2330 // Handle member of resource array type.
2331 if (ResourceVD->getType()->isHLSLResourceRecordArray())
2332 return emitGlobalResourceArrayAsLValue(CGF, ResourceVD);
2333
2334 GlobalVariable *ResGV =
2335 cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(ResourceVD));
2336 const DataLayout &DL = CGM.getDataLayout();
2337 llvm::Type *Ty = ResGV->getValueType();
2338 CharUnits Align = CharUnits::fromQuantity(DL.getABITypeAlign(Ty));
2339 Address Addr = Address(ResGV, Ty, Align);
2340 LValue LV = LValue::MakeAddr(Addr, ME->getType(), CGM.getContext(),
2342 CGM.getTBAAAccessInfo(ME->getType()));
2343 return LV;
2344}
2345
2347 const LValue &SrcLV,
2348 AggValueSlot &DestSlot) {
2350 "expected expression in HLSL constant address space");
2351 assert(!E->getType()->isHLSLResourceRecord() &&
2353 "direct accesses to resource types should be handled separately");
2354
2355 if (DestSlot.isIgnored())
2356 return false;
2357
2358 QualType Ty = E->getType();
2359 Address DstPtr = DestSlot.getAddress();
2360 Address SrcPtr = SrcLV.getAddress();
2361
2362 // If there are no intangible types, we don't need to lookup associated
2363 // resources.
2364 if (!Ty->isHLSLIntangibleType())
2365 return HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty);
2366
2367 // Handle structs with intangible types by setting the resource fields
2368 // of the destination struct with the resources associated with the global
2369 // struct.
2370 EmbeddedResourceNameBuilder NameBuilder;
2371 const VarDecl *VD = findStructResourceParentDeclAndBuildName(E, NameBuilder);
2372 AssociatedResourcesList AssociatedResources(VD, NameBuilder.getName());
2373
2374 // Callback to fill in the associated resource.
2375 auto EmitResFn = [&](AggValueSlot &ResSlot) {
2376 const VarDecl *ResDecl = AssociatedResources.getNextResource();
2377 assert(ResDecl && "associated resource declaration not found");
2378
2379 // Check that the resource type of dest and src matches.
2380 [[maybe_unused]] llvm::Type *DestType =
2381 ResSlot.getAddress().getElementType();
2382 [[maybe_unused]] llvm::Type *SrcConvertedType =
2383 CGM.getTypes().ConvertTypeForMem(ResDecl->getType());
2384 assert(DestType == SrcConvertedType && "resource slot type mismatch");
2385
2386 if (ResDecl->getType()->isHLSLResourceRecord())
2387 copyGlobalResource(CGF, ResDecl, ResSlot);
2388 else
2389 initializeGlobalResourceArray(CGF, ResDecl, ResSlot);
2390 };
2391
2392 auto Result =
2393 HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty, EmitResFn);
2394 assert(AssociatedResources.getNextResource() == nullptr &&
2395 "expected all associated resources to be processed");
2396 return Result;
2397}
2398
2400 const MemberExpr *E) {
2401 LValue Base =
2403 auto *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
2404 assert(Field && "Unexpected access into HLSL buffer");
2405
2406 const RecordDecl *Rec = Field->getParent();
2407
2408 // Work out the buffer layout type to index into.
2409 QualType RecType = CGM.getContext().getCanonicalTagType(Rec);
2410 assert(RecType->isStructureOrClassType() && "Invalid type in HLSL buffer");
2411 // Since this is a member of an object in the buffer and not the buffer's
2412 // struct/class itself, we shouldn't have any offsets on the members we need
2413 // to contend with.
2414 CGHLSLOffsetInfo EmptyOffsets;
2415 llvm::StructType *LayoutTy = HLSLBufferLayoutBuilder(CGM).layOutStruct(
2416 RecType->getAsCanonical<RecordType>(), EmptyOffsets);
2417
2418 // Get the field index for the layout struct, accounting for padding.
2419 unsigned FieldIdx =
2420 CGM.getTypes().getCGRecordLayout(Rec).getLLVMFieldNo(Field);
2421 assert(FieldIdx < LayoutTy->getNumElements() &&
2422 "Layout struct is smaller than member struct");
2423 unsigned Skipped = 0;
2424 for (unsigned I = 0; I <= FieldIdx;) {
2425 llvm::Type *ElementTy = LayoutTy->getElementType(I + Skipped);
2426 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(ElementTy))
2427 ++Skipped;
2428 else
2429 ++I;
2430 }
2431 FieldIdx += Skipped;
2432 assert(FieldIdx < LayoutTy->getNumElements() && "Access out of bounds");
2433
2434 // Now index into the struct, making sure that the type we return is the
2435 // buffer layout type rather than the original type in the AST.
2436 QualType FieldType = Field->getType();
2437 llvm::Type *FieldLLVMTy = CGM.getTypes().ConvertTypeForMem(FieldType);
2439 CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy));
2440
2441 Value *Ptr = CGF.getLangOpts().EmitLogicalPointer
2442 ? CGF.Builder.CreateStructuredGEP(
2443 LayoutTy, Base.getPointer(CGF),
2444 llvm::ConstantInt::get(CGM.IntTy, FieldIdx))
2445 : CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF),
2446 FieldIdx, Field->getName());
2447 Address Addr(Ptr, FieldLLVMTy, Align, KnownNonNull);
2448
2449 LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(),
2451 CGM.getTBAAAccessInfo(FieldType));
2452 LV.getQuals().addCVRQualifiers(Base.getVRQualifiers());
2453
2454 return LV;
2455}
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
llvm::dxbc::PSV::SemanticKind SemanticKind
Definition SemaHLSL.cpp:59
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:239
SourceManager & getSourceManager()
Definition ASTContext.h:907
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:3812
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)
llvm::Value * emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, llvm::dxbc::PSV::SemanticKind SemanticKind, llvm::Triple::EnvironmentType Stage, std::optional< unsigned > Index, SemanticSignatures &Signature)
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)
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, llvm::dxbc::PSV::SemanticKind SemanticKind, llvm::Triple::EnvironmentType Stage, 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:5668
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:233
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:282
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:1617
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK)
Same as EmitLValue but additionally we generate checking code to guard against undefined behavior.
Definition CGExpr.cpp:1698
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:1733
bool isOpaqueValueEmitted(const OpaqueValueExpr *E)
isOpaqueValueEmitted - Return true if the opaque value expression has already been emitted.
Definition CGExpr.cpp:6467
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:736
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:3838
int64_t getSExtSize() const
Return the size sign-extended as a uint64_t.
Definition TypeBase.h:3920
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4465
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:781
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:3295
StringRef getName() const
The name of this FileEntry.
Definition FileEntry.h:61
Represents a function declaration or definition.
Definition Decl.h:2059
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2928
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:2993
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5385
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5329
bool isCBuffer() const
Definition Decl.h:5373
const CXXRecordDecl * getLayoutStruct() const
Definition Decl.h:5376
bool hasValidPackoffset() const
Definition Decl.h:5375
buffer_decl_range buffer_decls() const
Definition Decl.h:5404
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:5446
llvm::dxbc::RootSignatureVersion getVersion() const
Definition Decl.h:5444
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:296
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:302
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:1820
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:8418
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8544
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:4460
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
Definition Decl.h:4676
field_iterator field_begin() const
Definition Decl.cpp:5342
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:8762
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:8754
bool isConstantMatrixType() const
Definition TypeBase.h:8822
bool isHLSLIntangibleType() const
Definition Type.cpp:5557
bool isHLSLResourceRecord() const
Definition Type.cpp:5544
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:9254
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:8782
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5548
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:713
QualType getType() const
Definition Decl.h:724
Represents a variable declaration or definition.
Definition Decl.h:933
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1248
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:1175
Represents a GCC generic vector type.
Definition TypeBase.h:4253
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:2229
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