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