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"
29#include "clang/AST/Type.h"
34#include "llvm/ADT/DenseMap.h"
35#include "llvm/ADT/Enum.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/ScopeExit.h"
38#include "llvm/ADT/SmallString.h"
39#include "llvm/ADT/SmallVector.h"
40#include "llvm/Frontend/HLSL/HLSLResource.h"
41#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
42#include "llvm/Frontend/HLSL/SemanticSignaturePacking.h"
43#include "llvm/IR/Constants.h"
44#include "llvm/IR/DerivedTypes.h"
45#include "llvm/IR/GlobalVariable.h"
46#include "llvm/IR/IntrinsicInst.h"
47#include "llvm/IR/LLVMContext.h"
48#include "llvm/IR/Metadata.h"
49#include "llvm/IR/Module.h"
50#include "llvm/IR/Type.h"
51#include "llvm/IR/Value.h"
52#include "llvm/Support/Alignment.h"
53#include "llvm/Support/ErrorHandling.h"
54#include "llvm/Support/FormatVariadic.h"
55#include "llvm/Support/Path.h"
56#include "llvm/Transforms/Utils/ModuleUtils.h"
57#include <array>
58#include <cstdint>
59#include <optional>
60
61using namespace clang;
62using namespace CodeGen;
63using namespace clang::hlsl;
64using namespace llvm;
65
66using llvm::hlsl::CBufferRowSizeInBytes;
67
68namespace {
69
70void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
71 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
72 // Assume ValVersionStr is legal here.
73 VersionTuple Version;
74 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
75 Version.getSubminor() || !Version.getMinor()) {
76 return;
77 }
78
79 uint64_t Major = Version.getMajor();
80 uint64_t Minor = *Version.getMinor();
81
82 auto &Ctx = M.getContext();
83 IRBuilder<> B(M);
84 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
85 ConstantAsMetadata::get(B.getInt32(Minor))});
86 StringRef DXILValKey = "dx.valver";
87 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
88 DXILValMD->addOperand(Val);
89}
90
91void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
93 llvm::Function *Fn, llvm::Module &M) {
94 auto &Ctx = M.getContext();
95
96 llvm::hlsl::rootsig::MetadataBuilder RSBuilder(M, Elements);
97 MDNode *RootSignature = RSBuilder.BuildRootSignature();
98
99 ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get(
100 llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer)));
101 ValueAsMetadata *EntryFunc = Fn ? ValueAsMetadata::get(Fn) : nullptr;
102 MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version});
103
104 StringRef RootSignatureValKey = "dx.rootsignatures";
105 auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey);
106 RootSignatureValMD->addOperand(MDVals);
107}
108
109Expected<unsigned> packSemanticSignature(
111 llvm::Triple::EnvironmentType Stage, llvm::hlsl::IOType IOTy,
113 bool UseNative16BitTypes) {
114 using namespace llvm::hlsl;
115 // Vertex inputs and pixel outputs have fixed packing rules, independent of
116 // the packing mode used between programmable stages.
117 if (Stage == llvm::Triple::Vertex && IOTy == IOType::In)
118 return packSignatureStacked(Elements, Stage, IOTy);
119 if (Stage == llvm::Triple::Pixel && IOTy == IOType::Out)
120 return packSignatureIndexed(Elements, Stage, IOTy);
122 return packSignatureOptimized(Elements, Stage, IOTy, UseNative16BitTypes);
123 return packSignaturePrefixStable(Elements, Stage, IOTy, UseNative16BitTypes);
124}
125
126MDNode *buildSemanticSignatureMD(
127 ArrayRef<llvm::hlsl::SemanticSignatureElement> Elements, LLVMContext &Ctx) {
128 if (Elements.empty())
129 return nullptr;
130
131 SmallVector<Metadata *> ElementMD;
132 for (const llvm::hlsl::SemanticSignatureElement &Element : Elements)
133 ElementMD.push_back(Element.toMetadata(Ctx));
134 return MDNode::get(Ctx, ElementMD);
135}
136
137void addSemanticSignatureMD(
140 llvm::Function *Fn, llvm::Module &M) {
141 if (InputElements.empty() && OutputElements.empty())
142 return;
143
144 LLVMContext &Ctx = M.getContext();
145 MDNode *InputSignature = buildSemanticSignatureMD(InputElements, Ctx);
146 MDNode *OutputSignature = buildSemanticSignatureMD(OutputElements, Ctx);
147 MDNode *MDVals = MDNode::get(
148 Ctx, {ValueAsMetadata::get(Fn), InputSignature, OutputSignature});
149
150 M.getOrInsertNamedMetadata("dx.semantic.signatures")->addOperand(MDVals);
151}
152
153static void copyGlobalResource(CodeGenFunction &CGF, const VarDecl *ResourceVD,
154 AggValueSlot &DestSlot) {
155 GlobalVariable *ResGV =
157 assert(ResGV && "expected valid global variable");
158 CGF.Builder.CreateStore(ResGV, DestSlot.getAddress());
159}
160
161// Given a MemberExpr of a resource or resource array type, find the parent
162// VarDecl of the struct or class instance that contains this resource and
163// build the full resource name based on the member access path.
164//
165// For example, for a member access like "myStructArray[0].memberA",
166// this function will find the VarDecl of "myStructArray" and use the
167// EmbeddedResourceNameBuilder to build the resource name
168// "myStructArray.0.memberA".
169//
170// This also works for a record type expression that has some embedded
171// resources. It finds the parent VarDecl of that record and builds a partial
172// name which is the prefix of the resource globals associated with the
173// declaration.
174static const VarDecl *findStructResourceParentDeclAndBuildName(
175 const Expr *E, EmbeddedResourceNameBuilder &NameBuilder) {
176
178 const VarDecl *VD = nullptr;
179
180 for (;;) {
181 if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
182 assert(isa<VarDecl>(DRE->getDecl()) &&
183 "member expr base is not a var decl");
184 VD = cast<VarDecl>(DRE->getDecl());
185 NameBuilder.pushName(VD->getName());
186 break;
187 }
188
189 WorkList.push_back(E);
190 if (const auto *MExp = dyn_cast<MemberExpr>(E))
191 E = MExp->getBase();
192 else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
193 E = ICE->getSubExpr();
194 else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
195 E = ASE->getBase();
196 else if (isa<CXXThisExpr>(E))
197 // Resource member access on "this" pointer not yet implemented
198 // (llvm/llvm-project#190299)
199 return nullptr;
200 else
201 llvm_unreachable("unexpected expr type in resource member access");
202
203 assert(E && "expected valid expression");
204 }
205
206 while (!WorkList.empty()) {
207 E = WorkList.pop_back_val();
208 if (const auto *ME = dyn_cast<MemberExpr>(E)) {
209 NameBuilder.pushName(
210 ME->getMemberNameInfo().getName().getAsIdentifierInfo()->getName());
211 } else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
212 if (ICE->getCastKind() == CK_UncheckedDerivedToBase) {
213 CXXRecordDecl *DerivedRD =
214 ICE->getSubExpr()->getType()->getAsCXXRecordDecl();
215 CXXRecordDecl *BaseRD = ICE->getType()->getAsCXXRecordDecl();
216 NameBuilder.pushBaseNameHierarchy(DerivedRD, BaseRD);
217 }
218 } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
219 const Expr *IdxExpr = ASE->getIdx();
220 std::optional<llvm::APSInt> Value =
222 assert(Value &&
223 "expected constant index in struct with resource array access");
224 NameBuilder.pushArrayIndex(Value->getZExtValue());
225 } else {
226 llvm_unreachable("unexpected expr type in resource member access");
227 }
228 }
229 return VD;
230}
231
232// Given a MemberExpr of a resource or resource array type, find the
233// corresponding global resource declaration associated with the owning struct
234// or class instance via HLSLAssociatedResourceDeclAttr.
235static const VarDecl *
236findAssociatedResourceDeclForStruct(ASTContext &AST, const MemberExpr *ME) {
237
238 EmbeddedResourceNameBuilder NameBuilder;
239 const VarDecl *ParentVD =
240 findStructResourceParentDeclAndBuildName(ME, NameBuilder);
241 if (!ParentVD)
242 return nullptr;
243
244 if (!ParentVD->hasGlobalStorage())
245 return nullptr;
246
247 IdentifierInfo *II = NameBuilder.getNameAsIdentifier(AST);
248 for (const Attr *A : ParentVD->getAttrs()) {
249 if (const auto *ADA = dyn_cast<HLSLAssociatedResourceDeclAttr>(A)) {
250 VarDecl *AssocResVD = ADA->getResDecl();
251 if (AssocResVD->getIdentifier() == II)
252 return AssocResVD;
253 }
254 }
255 return nullptr;
256}
257
258void addSourceInfo(CodeGenModule &CGM, llvm::Module &M) {
259 auto &SM = CGM.getContext().getSourceManager();
260 auto &Macros = CGM.getPreprocessorOpts().Macros;
261 auto &CodeGenOpts = CGM.getCodeGenOpts();
262 auto &Ctx = M.getContext();
263
264 // Names and content of shader source code files.
265 llvm::NamedMDNode *DXContents =
266 M.getOrInsertNamedMetadata("dx.source.contents");
267 auto addFile = [&](const std::pair<StringRef, StringRef> &NameContent) {
268 llvm::MDTuple *FileInfo =
269 llvm::MDNode::get(Ctx, {llvm::MDString::get(Ctx, NameContent.first),
270 llvm::MDString::get(Ctx, NameContent.second)});
271 DXContents->addOperand(FileInfo);
272 };
273
274 bool Invalid = false;
275 const SrcMgr::SLocEntry *MainLocEntry =
276 &SM.getSLocEntry(SM.getMainFileID(), &Invalid);
277 assert(!Invalid && "Main file SLocEntry must not be invalid!");
278 const SrcMgr::ContentCache &MainCCEntry =
279 MainLocEntry->getFile().getContentCache();
280
282 std::optional<SmallString<256>> MainFileName;
283 Files.reserve(SM.local_sloc_entry_size());
284 for (unsigned I : llvm::seq(SM.local_sloc_entry_size())) {
285 const SrcMgr::SLocEntry &LocEntry = SM.getLocalSLocEntry(I);
286 if (!LocEntry.isFile())
287 continue;
288
289 const SrcMgr::FileInfo &FInfo = LocEntry.getFile();
290 if (isSystem(FInfo.getFileCharacteristic()))
291 continue;
292
293 const SrcMgr::ContentCache &CCEntry = FInfo.getContentCache();
294 OptionalFileEntryRef FEntry = CCEntry.OrigEntry;
295 if (!FEntry)
296 continue;
297
298 llvm::SmallString<256> Path = FEntry->getName();
299 llvm::sys::path::native(Path);
300 std::optional<llvm::MemoryBufferRef> Buffer = CCEntry.getBufferOrNone(
301 SM.getDiagnostics(), SM.getFileManager(), SourceLocation());
302 if (!Buffer) {
303 SM.getDiagnostics().Report(diag::warn_hlsl_failed_to_embed_source)
304 << Path;
305 continue;
306 }
307
308 if (&MainCCEntry != &CCEntry) {
309 Files.emplace_back(Path, Buffer->getBuffer());
310 } else {
311 // Main file should be at first position.
312 addFile(std::make_pair(Path, Buffer->getBuffer()));
313 MainFileName.emplace(Path);
314 }
315 }
316 assert(MainFileName && "Main file not found.");
317
318 // Files other that main one should be sorted by name.
319 llvm::sort(Files);
320#ifndef NDEBUG
321 for (unsigned I = 1; I < Files.size(); ++I)
322 assert((Files[I - 1].first != Files[I].first) &&
323 "duplicate files in dx.source.contents");
324#endif
325 llvm::for_each(Files, addFile);
326
328 Defines.reserve(Macros.size());
329 for (const auto &Macro : Macros) {
330 // Ignore undefs.
331 if (!Macro.second)
332 Defines.emplace_back(llvm::MDString::get(Ctx, Macro.first));
333 }
334 M.getOrInsertNamedMetadata("dx.source.defines")
335 ->addOperand(llvm::MDNode::get(Ctx, Defines));
336
337 if (!CodeGenOpts.MainFileName.empty())
338 llvm::sys::path::native(CodeGenOpts.MainFileName, *MainFileName);
339 M.getOrInsertNamedMetadata("dx.source.mainFileName")
340 ->addOperand(
341 llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, *MainFileName)));
342
344 Args.reserve(CodeGenOpts.HLSLParsedCommandLine.size());
345 if (!CodeGenOpts.HLSLParsedCommandLine.empty())
346 for (const auto &Arg : llvm::drop_begin(CodeGenOpts.HLSLParsedCommandLine))
347 Args.push_back(llvm::MDString::get(Ctx, Arg));
348 M.getOrInsertNamedMetadata("dx.source.args")
349 ->addOperand(llvm::MDNode::get(Ctx, Args));
350}
351
352// Find array variable declaration from DeclRef expression
353static const ValueDecl *getArrayDecl(ASTContext &AST, const Expr *E) {
354 E = E->IgnoreImpCasts();
355 if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(E))
356 return DRE->getDecl();
357 if (auto *OVE = dyn_cast<OpaqueValueExpr>(E))
358 E = OVE->getSourceExpr()->IgnoreImpCasts();
359 if (isa<MemberExpr>(E))
360 return findAssociatedResourceDeclForStruct(AST, cast<MemberExpr>(E));
361 return nullptr;
362}
363
364// Find array variable declaration from nested array subscript AST nodes
365static const ValueDecl *getArrayDecl(ASTContext &AST,
366 const ArraySubscriptExpr *ASE) {
367 const Expr *E = nullptr;
368 while (ASE != nullptr) {
369 E = ASE->getBase()->IgnoreImpCasts();
370 if (!E)
371 return nullptr;
372 ASE = dyn_cast<ArraySubscriptExpr>(E);
373 }
374 return getArrayDecl(AST, E);
375}
376
377// Get the total size of the array, or 0 if the array is unbounded.
378static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) {
380 assert(Ty->isArrayType() && "expected array type");
381 if (Ty->isIncompleteArrayType())
382 return 0;
384}
385
386static Value *buildNameForResource(llvm::StringRef BaseName,
387 CodeGenModule &CGM) {
388 llvm::SmallString<64> GlobalName = {BaseName, ".str"};
389 return CGM.GetAddrOfConstantCString(BaseName.str(), GlobalName.c_str())
390 .getPointer();
391}
392
393static CXXMethodDecl *lookupMethod(CXXRecordDecl *Record, StringRef Name,
394 StorageClass SC = SC_None) {
395 for (auto *Method : Record->methods()) {
396 if (Method->getStorageClass() == SC && Method->getName() == Name)
397 return Method;
398 }
399 return nullptr;
400}
401
402static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
403 CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range,
404 llvm::Value *Index, StringRef Name, ResourceBindingAttrs &Binding,
405 CallArgList &Args) {
406 assert(Binding.hasBinding() && "at least one binding attribute expected");
407
408 ASTContext &AST = CGM.getContext();
409 CXXMethodDecl *CreateMethod = nullptr;
410 Value *NameStr = buildNameForResource(Name, CGM);
411 Value *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
412
413 bool HasCounter = hasCounterHandle(ResourceDecl);
414 assert((!HasCounter || Binding.hasCounterImplicitOrderID()) &&
415 "resources with counter handle must have a binding with counter "
416 "implicit order ID");
417 if (Binding.isExplicit()) {
418 // explicit binding
419 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
420 Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
421 const char *Name = Binding.hasCounterImplicitOrderID()
422 ? "__createFromBindingWithImplicitCounter"
423 : "__createFromBinding";
424 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
425 } else {
426 // implicit binding
427 auto *OrderID =
428 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
429 Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
430 const char *Name = Binding.hasCounterImplicitOrderID()
431 ? "__createFromImplicitBindingWithImplicitCounter"
432 : "__createFromImplicitBinding";
433 CreateMethod = lookupMethod(ResourceDecl, Name, SC_Static);
434 }
435 Args.add(RValue::get(Space), AST.UnsignedIntTy);
436 Args.add(RValue::get(Range), AST.IntTy);
437 Args.add(RValue::get(Index), AST.UnsignedIntTy);
438 Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst()));
439 if (HasCounter) {
440 uint32_t CounterBinding = Binding.getCounterImplicitOrderID();
441 auto *CounterOrderID = llvm::ConstantInt::get(CGM.IntTy, CounterBinding);
442 Args.add(RValue::get(CounterOrderID), AST.UnsignedIntTy);
443 }
444
445 return CreateMethod;
446}
447
448static void callResourceInitMethod(CodeGenFunction &CGF,
449 CXXMethodDecl *CreateMethod,
450 CallArgList &Args, Address ReturnAddress) {
451 llvm::Constant *CalleeFn = CGF.CGM.GetAddrOfFunction(CreateMethod);
452 const FunctionProtoType *Proto =
453 CreateMethod->getType()->getAs<FunctionProtoType>();
454 // HLSL code generation is restricted to DXIL and SPIR-V targets, so no
455 // caller declaration is needed for x86 SysV ABI selection.
457 Args, Proto, false, /*ABIInfoFD=*/nullptr);
458 ReturnValueSlot ReturnValue(ReturnAddress, false);
459 CGCallee Callee(CGCalleeInfo(Proto), CalleeFn);
460 CGF.EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr);
461}
462
463// Initializes local resource array variable with global resource array
464// elements. For multi-dimensional arrays it calls itself recursively to
465// initialize its sub-arrays. The Index used in the resource constructor calls
466// will begin at StartIndex and will be incremented for each array element. The
467// last used resource Index is returned to the caller. If the function returns
468// std::nullopt, it indicates an error.
469static std::optional<llvm::Value *> initializeResourceArrayFromGlobal(
470 CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl,
471 const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot,
472 llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
473 ResourceBindingAttrs &Binding, ArrayRef<llvm::Value *> PrevGEPIndices) {
474
475 ASTContext &AST = CGF.getContext();
476 llvm::IntegerType *IntTy = CGF.CGM.IntTy;
477 llvm::Value *Index = StartIndex;
478 llvm::Value *One = llvm::ConstantInt::get(IntTy, 1);
479 const uint64_t ArraySize = ArrayTy->getSExtSize();
480 QualType ElemType = ArrayTy->getElementType();
481 Address TmpArrayAddr = ValueSlot.getAddress();
482
483 // Add additional index to the getelementptr call indices.
484 // This index will be updated for each array element in the loops below.
485 SmallVector<llvm::Value *> GEPIndices(PrevGEPIndices);
486 GEPIndices.push_back(llvm::ConstantInt::get(IntTy, 0));
487
488 // For array of arrays, recursively initialize the sub-arrays.
489 if (ElemType->isArrayType()) {
490 const ConstantArrayType *SubArrayTy = cast<ConstantArrayType>(ElemType);
491 for (uint64_t I = 0; I < ArraySize; I++) {
492 if (I > 0) {
493 Index = CGF.Builder.CreateAdd(Index, One);
494 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
495 }
496 std::optional<llvm::Value *> MaybeIndex =
497 initializeResourceArrayFromGlobal(CGF, ResourceDecl, SubArrayTy,
498 ValueSlot, Range, Index,
499 ResourceName, Binding, GEPIndices);
500 if (!MaybeIndex)
501 return std::nullopt;
502 Index = *MaybeIndex;
503 }
504 return Index;
505 }
506
507 // For array of resources, initialize each resource in the array.
508 llvm::Type *Ty = CGF.ConvertTypeForMem(ElemType);
509 CharUnits ElemSize = AST.getTypeSizeInChars(ElemType);
510 CharUnits Align =
511 TmpArrayAddr.getAlignment().alignmentOfArrayElement(ElemSize);
512
513 for (uint64_t I = 0; I < ArraySize; I++) {
514 if (I > 0) {
515 Index = CGF.Builder.CreateAdd(Index, One);
516 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
517 }
518 Address ReturnAddress =
519 CGF.Builder.CreateGEP(TmpArrayAddr, GEPIndices, Ty, Align);
520
521 CallArgList Args;
522 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
523 CGF.CGM, ResourceDecl, Range, Index, ResourceName, Binding, Args);
524
525 if (!CreateMethod)
526 // This can happen if someone creates an array of structs that looks like
527 // an HLSL resource record array but it does not have the required static
528 // create method. No binding will be generated for it.
529 return std::nullopt;
530
531 callResourceInitMethod(CGF, CreateMethod, Args, ReturnAddress);
532 }
533 return Index;
534}
535
536/// Utility for emitting copies following the HLSL buffer layout rules (ie,
537/// copying out of a cbuffer).
538class HLSLBufferCopyEmitter {
539 CodeGenFunction &CGF;
540 Address DstPtr;
541 Address SrcPtr;
542 llvm::Type *LayoutTy = nullptr;
543
544 SmallVector<llvm::Value *> CurStoreIndices;
545 SmallVector<llvm::Value *> CurLoadIndices;
546
547 using EmitResourceFnTy = llvm::function_ref<void(AggValueSlot &)>;
548
549 // Creates & returns either a structured.gep or a ptradd/gep depending on
550 // langopts.
551 llvm::Value *emitAccessChain(llvm::Type *BaseTy, llvm::Value *Base,
552 ArrayRef<llvm::Value *> Indices) {
553 bool EmitLogical = CGF.getLangOpts().EmitLogicalPointer;
554 if (EmitLogical)
555 return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, Indices);
556
557 llvm::SmallVector<llvm::Value *> GEPIndices;
558 GEPIndices.reserve(Indices.size() + 1);
559 GEPIndices.push_back(llvm::ConstantInt::get(CGF.IntTy, 0));
560 GEPIndices.append(Indices.begin(), Indices.end());
561 return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, GEPIndices);
562 }
563
564 bool isBufferLayoutArray(llvm::StructType *ST) {
565 // A buffer layout array is a struct with two elements: the padded array,
566 // and the last element. That is, is should look something like this:
567 //
568 // { [%n x { %type, %padding }], %type }
569 //
570 if (!ST || ST->getNumElements() != 2)
571 return false;
572
573 auto *PaddedEltsTy = dyn_cast<llvm::ArrayType>(ST->getElementType(0));
574 if (!PaddedEltsTy)
575 return false;
576
577 auto *PaddedTy = dyn_cast<llvm::StructType>(PaddedEltsTy->getElementType());
578 if (!PaddedTy || PaddedTy->getNumElements() != 2)
579 return false;
580
581 if (!CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(
582 PaddedTy->getElementType(1)))
583 return false;
584
585 llvm::Type *ElementTy = ST->getElementType(1);
586 if (PaddedTy->getElementType(0) != ElementTy)
587 return false;
588 return true;
589 }
590
591 // Returns true if the type is either a struct representing a resource record,
592 // or an array of structs that are resource records. This assumes a struct is
593 // a resource record if the first element is a target type (resource handle).
594 // This is the case for all target types used by HLSL except the padding type
595 // ("{dx|spirv.Padding"), but padding will never be the first element of a
596 // struct.
597 bool isResourceOrResourceArray(llvm::Type *Ty) {
598 while (auto *AT = dyn_cast<llvm::ArrayType>(Ty))
599 Ty = AT->getElementType();
600
601 auto *ST = dyn_cast<llvm::StructType>(Ty);
602 if (!ST || ST->getNumElements() < 1)
603 return false;
604
605 auto *TargetTy = dyn_cast<llvm::TargetExtType>(ST->getElementType(0));
606 return TargetTy != nullptr;
607 }
608
609 void emitResourceOrResourceArray(Value *Dst, llvm::Type *DstTy,
610 EmitResourceFnTy EmitResFn) {
611 CharUnits DstAlign =
612 CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(DstTy));
613 Address DstAddr(Dst, DstTy, DstAlign);
614 AggValueSlot Slot = AggValueSlot::forAddr(
615 DstAddr, Qualifiers(), AggValueSlot::IsDestructed_t(true),
618
619 EmitResFn(Slot);
620 }
621
622 void emitBufferLayoutCopy(Value *Src, llvm::StructType *SrcTy, Value *Dst,
623 llvm::ArrayType *DstTy,
624 EmitResourceFnTy EmitResFn) {
625 // Those assumptions are checked by isBufferLayoutArray.
626 auto *SrcPaddedArrayTy = cast<llvm::ArrayType>(SrcTy->getElementType(0));
627 assert(SrcPaddedArrayTy->getNumElements() + 1 == DstTy->getNumElements());
628 assert(cast<llvm::StructType>(SrcPaddedArrayTy->getElementType())
629 ->getElementType(0) == SrcTy->getElementType(1));
630
631 auto *SrcDataTy = SrcTy->getElementType(1);
632 auto Zero = llvm::ConstantInt::get(CGF.IntTy, 0);
633
634 for (unsigned I = 0; I < SrcPaddedArrayTy->getNumElements(); ++I) {
635 auto Index = llvm::ConstantInt::get(CGF.IntTy, I);
636 auto *SrcElt = emitAccessChain(SrcTy, Src, {Zero, Index, Zero});
637 auto *DstElt = emitAccessChain(DstTy, Dst, {Index});
638 emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType(),
639 EmitResFn);
640 }
641
642 auto *SrcElt =
643 emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, 1)});
644 auto *DstElt = emitAccessChain(
645 DstTy, Dst,
646 {llvm::ConstantInt::get(CGF.IntTy, DstTy->getNumElements() - 1)});
647 emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType(),
648 EmitResFn);
649 }
650
651 void emitCopy(Value *Src, llvm::StructType *SrcTy, Value *Dst,
652 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
653 assert(!isResourceOrResourceArray(DstTy) &&
654 "direct access to resources or resource arrays should be handled "
655 "separately");
656
657 if (isBufferLayoutArray(SrcTy))
658 return emitBufferLayoutCopy(Src, SrcTy, Dst, cast<llvm::ArrayType>(DstTy),
659 EmitResFn);
660
661 unsigned SrcIndex = 0;
662 unsigned DstIndex = 0;
663
664 // DstTy layout is in default address space and can include resource types.
665 // SrcTy is in cbuffer layout where resources are filtered out, so the
666 // number of elements in SrcTy can be less than the number of elements in
667 // DstTy.
668 auto *DstST = cast<llvm::StructType>(DstTy);
669 while (DstIndex < DstST->getNumElements()) {
670 llvm::Type *DstEltTy = DstST->getElementType(DstIndex);
671 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(DstEltTy)) {
672 DstIndex += 1;
673 continue;
674 }
675 if (isResourceOrResourceArray(DstEltTy)) {
676 auto *DstElt = emitAccessChain(
677 DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, DstIndex)});
678 emitResourceOrResourceArray(DstElt, DstEltTy, EmitResFn);
679 DstIndex += 1;
680 continue;
681 }
682
683 assert(SrcIndex < SrcTy->getNumElements());
684 llvm::Type *SrcEltTy = SrcTy->getElementType(SrcIndex);
685 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(SrcEltTy)) {
686 SrcIndex += 1;
687 continue;
688 }
689
690 auto *SrcElt = emitAccessChain(
691 SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, SrcIndex)});
692 auto *DstElt = emitAccessChain(
693 DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, DstIndex)});
694 emitElementCopy(SrcElt, SrcEltTy, DstElt, DstEltTy, EmitResFn);
695 DstIndex += 1;
696 SrcIndex += 1;
697 }
698 }
699
700 void emitCopy(Value *Src, llvm::ArrayType *SrcTy, Value *Dst,
701 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
702 for (unsigned I = 0, E = SrcTy->getNumElements(); I < E; ++I) {
703 auto *SrcElt =
704 emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, I)});
705 auto *DstElt =
706 emitAccessChain(DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, I)});
707 emitElementCopy(SrcElt, SrcTy->getElementType(), DstElt,
708 cast<llvm::ArrayType>(DstTy)->getElementType(),
709 EmitResFn);
710 }
711 }
712
713 void emitElementCopy(Value *Src, llvm::Type *SrcTy, Value *Dst,
714 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
715 if (auto *AT = dyn_cast<llvm::ArrayType>(SrcTy))
716 return emitCopy(Src, AT, Dst, DstTy, EmitResFn);
717 if (auto *ST = dyn_cast<llvm::StructType>(SrcTy))
718 return emitCopy(Src, ST, Dst, DstTy, EmitResFn);
719
720 // When we have a scalar or vector element we can emit the copy.
721 CharUnits SrcAlign =
722 CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(SrcTy));
723 CharUnits DstAlign =
724 CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(DstTy));
725 Address SrcAddr(Src, SrcTy, SrcAlign);
726 Address DstAddr(Dst, DstTy, DstAlign);
727 llvm::Value *Load = CGF.Builder.CreateLoad(SrcAddr, "cbuf.load");
728 CGF.Builder.CreateStore(Load, DstAddr);
729 }
730
731public:
732 HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DstPtr, Address SrcPtr)
733 : CGF(CGF), DstPtr(DstPtr), SrcPtr(SrcPtr) {}
734
735 bool emitCopy(QualType CType, EmitResourceFnTy EmitResFn = nullptr) {
736 LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(CType);
737
738 // TODO: We should be able to fall back to a regular memcpy if the layout
739 // type doesn't have any padding, but that runs into issues in the backend
740 // currently.
741 //
742 // See https://github.com/llvm/wg-hlsl/issues/351
743 emitElementCopy(SrcPtr.getBasePointer(), LayoutTy, DstPtr.getBasePointer(),
744 DstPtr.getElementType(), EmitResFn);
745 return true;
746 }
747};
748
749// Represents a list resources associated with a global struct whose name
750// starts with the specified prefix.
751// The order of HLSLAssociatedResourceDeclAttr attributes is identical to the
752// order of the depth-first traversal of the corresponding fields in the struct.
753// The resources are always returned in that order, which is the same order
754// we need when a struct is copied element-by-element.
755class AssociatedResourcesList {
756 // Iterator pointers for the associated resource attributes that match the
757 // prefix. Begin = begin of the range of attributes that match the prefix End
758 // = end of the range of attributes that match the prefix Next = the current
759 // attribute in the iteration to be returned by getNextResource
760 specific_attr_iterator<HLSLAssociatedResourceDeclAttr> Begin, End, Next;
761
762public:
763 AssociatedResourcesList(const VarDecl *StructVD,
764 StringRef ResourceNamePrefix) {
765 auto I = StructVD->specific_attr_begin<HLSLAssociatedResourceDeclAttr>();
766 auto E = StructVD->specific_attr_end<HLSLAssociatedResourceDeclAttr>();
767
768 // Skip over associated resources that don't match the prefix.
769 while (I != E &&
770 !I->getResDecl()->getName().starts_with(ResourceNamePrefix))
771 ++I;
772 assert(I != E && "expected associated resource not found");
773 Begin = End = I;
774
775 // Scan over associated resources that do match the prefix to find the end
776 // of the range.
777 while (I != E && ((HLSLAssociatedResourceDeclAttr *)*I)
778 ->getResDecl()
779 ->getName()
780 .starts_with(ResourceNamePrefix))
781 End = ++I;
782
783 Next = Begin;
784 }
785
786 const VarDecl *getNextResource() {
787 if (Next == End)
788 return nullptr;
789
790 const VarDecl *Res = Next->getResDecl();
791 ++Next;
792 return Res;
793 }
794};
795
796} // namespace
797
798llvm::Type *
800 const CGHLSLOffsetInfo &OffsetInfo) {
801 assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
802
803 // Check if the target has a specific translation for this type first.
804 if (llvm::Type *TargetTy =
805 CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, OffsetInfo))
806 return TargetTy;
807
808 llvm_unreachable("Generic handling of HLSL types is not supported.");
809}
810
811llvm::Triple::ArchType CGHLSLRuntime::getArch() {
812 return CGM.getTarget().getTriple().getArch();
813}
814
815// Emits constant global variables for buffer constants declarations
816// and creates metadata linking the constant globals with the buffer global.
817void CGHLSLRuntime::emitBufferGlobalsAndMetadata(
818 const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *BufGV,
819 const CGHLSLOffsetInfo &OffsetInfo) {
820 LLVMContext &Ctx = CGM.getLLVMContext();
821
822 // get the layout struct from constant buffer target type
823 llvm::Type *BufType = BufGV->getValueType();
824 llvm::StructType *LayoutStruct = cast<llvm::StructType>(
825 cast<llvm::TargetExtType>(BufType)->getTypeParameter(0));
826
828 size_t OffsetIdx = 0;
829 for (Decl *D : BufDecl->buffer_decls()) {
831 // Nothing to do for this declaration.
832 continue;
833 if (isa<FunctionDecl>(D)) {
834 // A function within an cbuffer is effectively a top-level function.
836 continue;
837 }
838 VarDecl *VD = dyn_cast<VarDecl>(D);
839 if (!VD)
840 continue;
841
842 QualType VDTy = VD->getType();
844 if (VD->getStorageClass() == SC_Static ||
847 // Emit static and groupshared variables and resource classes inside
848 // cbuffer as regular globals
849 CGM.EmitGlobal(VD);
850 }
851 continue;
852 }
853
854 DeclsWithOffset.emplace_back(VD, OffsetInfo[OffsetIdx++]);
855 }
856
857 if (!OffsetInfo.empty())
858 llvm::stable_sort(DeclsWithOffset, [](const auto &LHS, const auto &RHS) {
859 return CGHLSLOffsetInfo::compareOffsets(LHS.second, RHS.second);
860 });
861
862 // Associate the buffer global variable with its constants
863 SmallVector<llvm::Metadata *> BufGlobals;
864 BufGlobals.reserve(DeclsWithOffset.size() + 1);
865 BufGlobals.push_back(ValueAsMetadata::get(BufGV));
866
867 auto ElemIt = LayoutStruct->element_begin();
868 for (auto &[VD, _] : DeclsWithOffset) {
869 if (CGM.getTargetCodeGenInfo().isHLSLPadding(*ElemIt))
870 ++ElemIt;
871
872 assert(ElemIt != LayoutStruct->element_end() &&
873 "number of elements in layout struct does not match");
874 llvm::Type *LayoutType = *ElemIt++;
875
876 GlobalVariable *ElemGV =
877 cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
878 BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
879 }
880 assert(ElemIt == LayoutStruct->element_end() &&
881 "number of elements in layout struct does not match");
882
883 // add buffer metadata to the module
884 CGM.getModule()
885 .getOrInsertNamedMetadata("hlsl.cbs")
886 ->addOperand(MDNode::get(Ctx, BufGlobals));
887}
888
889// Creates resource handle type for the HLSL buffer declaration
890static const clang::HLSLAttributedResourceType *
892 ASTContext &AST = BufDecl->getASTContext();
894 AST.HLSLResourceTy, AST.getCanonicalTagType(BufDecl->getLayoutStruct()),
895 HLSLAttributedResourceType::Attributes(ResourceClass::CBuffer));
897}
898
901
902 // If we don't have packoffset info, just return an empty result.
903 if (!BufDecl.hasValidPackoffset())
904 return Result;
905
906 for (Decl *D : BufDecl.buffer_decls()) {
908 continue;
909 }
910 VarDecl *VD = dyn_cast<VarDecl>(D);
911 if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
912 continue;
913
914 if (!VD->hasAttrs()) {
915 Result.Offsets.push_back(Unspecified);
916 continue;
917 }
918
919 uint32_t Offset = Unspecified;
920 for (auto *Attr : VD->getAttrs()) {
921 if (auto *POA = dyn_cast<HLSLPackOffsetAttr>(Attr)) {
922 Offset = POA->getOffsetInBytes();
923 break;
924 }
925 auto *RBA = dyn_cast<HLSLResourceBindingAttr>(Attr);
926 if (RBA &&
927 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
928 Offset = RBA->getSlotNumber() * CBufferRowSizeInBytes;
929 break;
930 }
931 }
932 Result.Offsets.push_back(Offset);
933 }
934 return Result;
935}
936
937// Codegen for HLSLBufferDecl
939
940 assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
941
942 // create resource handle type for the buffer
943 const clang::HLSLAttributedResourceType *ResHandleTy =
944 createBufferHandleType(BufDecl);
945
946 // empty constant buffer is ignored
947 if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
948 return;
949
950 // create global variable for the constant buffer
951 CGHLSLOffsetInfo OffsetInfo = CGHLSLOffsetInfo::fromDecl(*BufDecl);
952 llvm::Type *LayoutTy = convertHLSLSpecificType(ResHandleTy, OffsetInfo);
953 llvm::GlobalVariable *BufGV = new GlobalVariable(
954 LayoutTy, /*isConstant*/ false,
955 GlobalValue::LinkageTypes::InternalLinkage, PoisonValue::get(LayoutTy),
956 llvm::formatv("{0}{1}", BufDecl->getName(),
957 BufDecl->isCBuffer() ? ".cb" : ".tb"),
958 GlobalValue::NotThreadLocal);
959
960 llvm::Module &M = CGM.getModule();
961 M.insertGlobalVariable(BufGV);
962
963 // Add the global variable to the compiler used list so it does not
964 // get optimized away by GlobalOptPass before it reaches
965 // {DXIL|SPIRV}CBufferAccess pass.
966 llvm::appendToCompilerUsed(M, {BufGV});
967
968 // Add globals for constant buffer elements and create metadata nodes
969 emitBufferGlobalsAndMetadata(BufDecl, BufGV, OffsetInfo);
970
971 // Initialize cbuffer from binding (implicit or explicit)
972 initializeBufferFromBinding(BufDecl, BufGV);
973}
974
976 const HLSLRootSignatureDecl *SignatureDecl) {
977 llvm::Module &M = CGM.getModule();
978 Triple T(M.getTargetTriple());
979
980 // Generated later with the function decl if not targeting root signature
981 if (T.getEnvironment() != Triple::EnvironmentType::RootSignature)
982 return;
983
984 addRootSignatureMD(SignatureDecl->getVersion(),
985 SignatureDecl->getRootElements(), nullptr, M);
986}
987
988llvm::StructType *
989CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
990 const auto Entry = LayoutTypes.find(StructType);
991 if (Entry != LayoutTypes.end())
992 return Entry->getSecond();
993 return nullptr;
994}
995
996void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
997 llvm::StructType *LayoutTy) {
998 assert(getHLSLBufferLayoutType(StructType) == nullptr &&
999 "layout type for this struct already exist");
1000 LayoutTypes[StructType] = LayoutTy;
1001}
1002
1004 auto &TargetOpts = CGM.getTarget().getTargetOpts();
1005 auto &CodeGenOpts = CGM.getCodeGenOpts();
1006 auto &LangOpts = CGM.getLangOpts();
1007 llvm::Module &M = CGM.getModule();
1008 Triple T(M.getTargetTriple());
1009 if (T.getArch() == Triple::ArchType::dxil)
1010 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
1011 if (!CodeGenOpts.DisableDXSourceMetadata &&
1012 CodeGenOpts.getDebugInfo() >=
1013 llvm::codegenoptions::DebugInfoKind::DebugInfoConstructor)
1014 addSourceInfo(CGM, M);
1015 if (CodeGenOpts.ResMayAlias)
1016 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.resmayalias", 1);
1017 if (CodeGenOpts.AllResourcesBound)
1018 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error,
1019 "dx.allresourcesbound", 1);
1020 if (CodeGenOpts.OptimizationLevel == 0)
1021 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override,
1022 "dx.disable_optimizations", 1);
1023
1024 // NativeHalfType corresponds to the -fnative-half-type clang option which is
1025 // aliased by clang-dxc's -enable-16bit-types option. This option is used to
1026 // set the UseNativeLowPrecision DXIL module flag in the DirectX backend
1027 if (LangOpts.NativeHalfType)
1028 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.nativelowprec",
1029 1);
1030
1031 if (LangOpts.HLSLSpvPreserveInterface && T.isSPIRV()) {
1032 // Runs before optimization. Keeps Input/Output globals from GlobalDCE.
1033 const ASTContext &Ctx = CGM.getContext();
1034 unsigned InputAS = Ctx.getTargetAddressSpace(LangAS::hlsl_input);
1035 unsigned OutputAS = Ctx.getTargetAddressSpace(LangAS::hlsl_output);
1036 SmallVector<GlobalValue *, 8> InterfaceVars;
1037 for (GlobalVariable &GV : M.globals()) {
1038 unsigned AS = GV.getAddressSpace();
1039 if (AS == InputAS || AS == OutputAS)
1040 InterfaceVars.push_back(&GV);
1041 }
1042 if (!InterfaceVars.empty())
1043 appendToCompilerUsed(M, InterfaceVars);
1044 }
1045
1047}
1048
1050 const FunctionDecl *FD, llvm::Function *Fn) {
1051 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1052 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
1053 const StringRef ShaderAttrKindStr = "hlsl.shader";
1054 Fn->addFnAttr(ShaderAttrKindStr,
1055 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
1056 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
1057 const StringRef NumThreadsKindStr = "hlsl.numthreads";
1058 std::string NumThreadsStr =
1059 formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
1060 NumThreadsAttr->getZ());
1061 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
1062 }
1063 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->getAttr<HLSLWaveSizeAttr>()) {
1064 const StringRef WaveSizeKindStr = "hlsl.wavesize";
1065 std::string WaveSizeStr =
1066 formatv("{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
1067 WaveSizeAttr->getPreferred());
1068 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
1069 }
1070 // HLSL entry functions are materialized for module functions with
1071 // HLSLShaderAttr attribute. SetLLVMFunctionAttributesForDefinition called
1072 // later in the compiler-flow for such module functions is not aware of and
1073 // hence not able to set attributes of the newly materialized entry functions.
1074 // So, set attributes of entry function here, as appropriate.
1075 Fn->addFnAttr(llvm::Attribute::NoInline);
1076
1077 if (CGM.getLangOpts().HLSLSpvEnableMaximalReconvergence) {
1078 Fn->addFnAttr("enable-maximal-reconvergence", "true");
1079 }
1080}
1081
1082static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
1083 // Compute ID intrinsics return i32 components, but the semantic may use
1084 // 16-bit integers. Narrow each component before assembling the input.
1085 if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
1086 Value *Result = PoisonValue::get(Ty);
1087 for (unsigned I = 0; I < VT->getNumElements(); ++I) {
1088 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
1089 Elt = B.CreateTrunc(Elt, VT->getElementType());
1090 Result = B.CreateInsertElement(Result, Elt, I);
1091 }
1092 return Result;
1093 }
1094 return B.CreateTrunc(B.CreateCall(F, {B.getInt32(0)}), Ty);
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 requiresFlatInterpolation(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::hlsl::InterpolationMode
1118getSPIRVInterpolationMode(llvm::hlsl::InterpolationMode InterpMode,
1119 llvm::Type *Ty, llvm::Triple::EnvironmentType Stage,
1120 llvm::hlsl::IOType IO) {
1121 using llvm::hlsl::InterpolationMode;
1122 if (!((Stage == llvm::Triple::Pixel && IO == llvm::hlsl::IOType::In) ||
1123 (Stage == llvm::Triple::Vertex && IO == llvm::hlsl::IOType::Out)))
1124 return InterpolationMode::Undefined;
1125 if (InterpMode == InterpolationMode::Undefined &&
1127 return InterpolationMode::Constant;
1128 return InterpMode;
1129}
1130
1131static void
1132addSPIRVInterfaceDecorations(llvm::GlobalVariable *GV,
1133 llvm::hlsl::SPIRVInterfaceDecoration Decoration,
1134 unsigned Operand,
1135 llvm::hlsl::InterpolationMode InterpMode =
1136 llvm::hlsl::InterpolationMode::Undefined) {
1137 using llvm::hlsl::InterpolationMode;
1138 using llvm::hlsl::SPIRVInterpolationMode;
1139
1140 LLVMContext &Ctx = GV->getContext();
1141 IRBuilder<> B(*GV->getParent());
1142 SmallVector<Metadata *, 3> Decorations;
1143 Decorations.push_back(MDNode::get(
1144 Ctx,
1145 {ConstantAsMetadata::get(B.getInt32(llvm::to_underlying(Decoration))),
1146 ConstantAsMetadata::get(B.getInt32(Operand))}));
1147 auto Add = [&](SPIRVInterpolationMode InterpolationDecoration) {
1148 Decorations.push_back(
1149 MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(
1150 llvm::to_underlying(InterpolationDecoration)))}));
1151 };
1152 switch (InterpMode) {
1153 case InterpolationMode::Undefined:
1154 case InterpolationMode::Linear:
1155 break;
1156 case InterpolationMode::Constant:
1157 Add(SPIRVInterpolationMode::Flat);
1158 break;
1159 case InterpolationMode::LinearNoperspective:
1160 Add(SPIRVInterpolationMode::NoPerspective);
1161 break;
1162 case InterpolationMode::LinearNoperspectiveCentroid:
1163 Add(SPIRVInterpolationMode::NoPerspective);
1164 [[fallthrough]];
1165 case InterpolationMode::LinearCentroid:
1166 Add(SPIRVInterpolationMode::Centroid);
1167 break;
1168 case InterpolationMode::LinearNoperspectiveSample:
1169 Add(SPIRVInterpolationMode::NoPerspective);
1170 [[fallthrough]];
1171 case InterpolationMode::LinearSample:
1172 Add(SPIRVInterpolationMode::Sample);
1173 break;
1174 default:
1175 llvm_unreachable("invalid interpolation mode");
1176 }
1177 // The backend consumes one decoration list per global, including both the
1178 // Location or BuiltIn and any interpolation decorations.
1179 GV->addMetadata("spirv.Decorations", *MDNode::get(Ctx, Decorations));
1180}
1181
1182static llvm::Value *createSPIRVInputLoad(
1183 IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name,
1184 llvm::hlsl::SPIRVInterfaceDecoration Decoration, unsigned Operand,
1185 llvm::hlsl::InterpolationMode InterpMode) {
1186 // SPIR-V integer built-ins are 32-bit, so a narrower integer declaration
1187 // loads the 32-bit built-in and truncates it. Other types are loaded as is.
1188 bool Truncate = Decoration == llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn &&
1189 Ty->isIntegerTy() && Ty->getIntegerBitWidth() < 32;
1190 llvm::Type *LoadTy = Truncate ? B.getInt32Ty() : Ty;
1191 auto *GV = new llvm::GlobalVariable(
1192 M, LoadTy, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
1193 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
1194 llvm::GlobalVariable::GeneralDynamicTLSModel,
1195 /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
1196 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1197 addSPIRVInterfaceDecorations(GV, Decoration, Operand, InterpMode);
1198 llvm::Value *Value = B.CreateLoad(LoadTy, GV);
1199 return Truncate ? B.CreateTrunc(Value, Ty) : Value;
1200}
1201
1202llvm::Value *CGHLSLRuntime::emitSPIRVUserSemanticLoad(
1203 llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
1204 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index,
1205 llvm::hlsl::InterpolationMode InterpMode) {
1206 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1207 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1208
1209 unsigned Location = SPIRVLastAssignedInputSemanticLocation;
1210 if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
1211 Location = L->getLocation();
1212
1213 // DXC completely ignores the semantic/index pair. Location are assigned from
1214 // the first semantic to the last.
1215 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
1216 unsigned ElementCount = AT ? AT->getNumElements() : 1;
1217 SPIRVLastAssignedInputSemanticLocation += ElementCount;
1218
1219 return createSPIRVInputLoad(B, CGM.getModule(), Type, VariableName.str(),
1220 llvm::hlsl::SPIRVInterfaceDecoration::Location,
1221 Location, InterpMode);
1222}
1223
1225 IRBuilder<> &B, llvm::Module &M, llvm::Value *Source, const Twine &Name,
1226 llvm::hlsl::SPIRVInterfaceDecoration Decoration, unsigned Operand,
1227 llvm::hlsl::InterpolationMode InterpMode) {
1228 auto *GV = new llvm::GlobalVariable(
1229 M, Source->getType(), /* isConstant= */ false,
1230 llvm::GlobalValue::ExternalLinkage,
1231 /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
1232 llvm::GlobalVariable::GeneralDynamicTLSModel,
1233 /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
1234 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1235 addSPIRVInterfaceDecorations(GV, Decoration, Operand, InterpMode);
1236 B.CreateStore(Source, GV);
1237}
1238
1239void CGHLSLRuntime::emitSPIRVUserSemanticStore(
1240 llvm::IRBuilder<> &B, llvm::Value *Source,
1241 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1242 std::optional<unsigned> Index, llvm::hlsl::InterpolationMode InterpMode) {
1243 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1244 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1245
1246 unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
1247 if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
1248 Location = L->getLocation();
1249
1250 // DXC completely ignores the semantic/index pair. Location are assigned from
1251 // the first semantic to the last.
1252 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
1253 unsigned ElementCount = AT ? AT->getNumElements() : 1;
1254 SPIRVLastAssignedOutputSemanticLocation += ElementCount;
1255 createSPIRVOutputStore(B, CGM.getModule(), Source, VariableName.str(),
1256 llvm::hlsl::SPIRVInterfaceDecoration::Location,
1257 Location, InterpMode);
1258}
1259
1260namespace {
1261// Describes how a semantic leaf lowers to signature rows
1262struct SemanticShape {
1263 // Array length followed by matrix major-axis length.
1264 SmallVector<unsigned> Dimensions;
1265 unsigned Cols;
1266 QualType RowType;
1267 bool IsMatrix = false;
1268 bool IsRowMajor = false;
1269
1270 // Direct matrix arguments/results use column-major flattened vectors even
1271 // when their signature (and aggregate memory representation) is row-major.
1272 unsigned getMatrixElementIndex(unsigned Row, unsigned Col) const {
1273 assert(IsMatrix);
1274 unsigned MatrixRow = Row % Dimensions.back();
1275 return IsRowMajor ? Col * Dimensions.back() + MatrixRow
1276 : MatrixRow * Cols + Col;
1277 }
1278
1279 unsigned getNumRows() const {
1280 unsigned Rows = 1;
1281 for (unsigned Dimension : Dimensions)
1282 Rows *= Dimension;
1283 return Rows;
1284 }
1285
1286 SmallVector<unsigned> getArrayIndicesForRow(unsigned Row) const {
1287 assert(Row < getNumRows() && "row exceeds semantic shape");
1288
1289 SmallVector<unsigned> Indices(Dimensions.size());
1290 for (auto [Index, Dimension] :
1291 llvm::zip_equal(llvm::reverse(Indices), llvm::reverse(Dimensions))) {
1292 Index = Row % Dimension;
1293 Row /= Dimension;
1294 }
1295 return Indices;
1296 }
1297};
1298} // namespace
1299
1300// Returns the QualType of a semantic leaf declarator. For a function the
1301// declared return type is used, otherwise the declared type.
1303 if (const auto *FD = dyn_cast<clang::FunctionDecl>(Decl))
1304 return FD->getDeclaredReturnType();
1305 return Decl->getType();
1306}
1307
1308// Collects array dimensions and, for a matrix leaf, its major-axis dimension.
1309// RowType is the scalar or vector transferred by each signature load/store.
1310static SemanticShape getSemanticShape(ASTContext &Ctx, QualType Ty) {
1311 SemanticShape Shape{{}, 1, Ty};
1312 while (const ConstantArrayType *CAT =
1313 Ctx.getAsConstantArrayType(Shape.RowType)) {
1314 Shape.Dimensions.push_back(CAT->getSize().getZExtValue());
1315 Shape.RowType = CAT->getElementType();
1316 }
1317
1318 if (const auto *VT = Shape.RowType->getAs<clang::VectorType>()) {
1319 Shape.Cols = VT->getNumElements();
1320 } else if (const auto *MT =
1321 Shape.RowType->getAs<clang::ConstantMatrixType>()) {
1322 Shape.IsMatrix = true;
1323 Shape.IsRowMajor = isMatrixRowMajor(Ctx.getLangOpts(), Shape.RowType);
1324 Shape.Dimensions.push_back(Shape.IsRowMajor ? MT->getNumRows()
1325 : MT->getNumColumns());
1326 Shape.Cols = Shape.IsRowMajor ? MT->getNumColumns() : MT->getNumRows();
1327 Shape.RowType = Ctx.getExtVectorType(MT->getElementType(), Shape.Cols);
1328 }
1329
1330 return Shape;
1331}
1332
1333static llvm::dxil::ElementType getSignatureComponentType(CodeGenModule &CGM,
1334 QualType Ty) {
1335 if (const auto *VT = Ty->getAs<clang::VectorType>())
1336 Ty = VT->getElementType();
1337
1338 llvm::Type *IRTy = CGM.getTypes().ConvertTypeForMem(Ty);
1339 bool IsSigned = Ty->isSignedIntegerOrEnumerationType();
1340 return llvm::hlsl::getDXILElementType(IRTy, IsSigned);
1341}
1342
1343static llvm::hlsl::SemanticSignatureElement createSemanticSignatureElement(
1344 CodeGenModule &CGM, uint32_t SigId, HLSLAppliedSemanticAttr *Semantic,
1345 std::optional<unsigned> Index, const SemanticShape &Shape) {
1346 StringRef Name = Semantic->getAttrName()->getName();
1347
1348 // One semantic index per row, starting from the declared index.
1349 SmallVector<uint32_t> SemanticIndices;
1350 uint32_t FirstSemanticIndex = Index.value_or(0);
1351 for (uint32_t I = 0, E = Shape.getNumRows(); I < E; ++I)
1352 SemanticIndices.push_back(FirstSemanticIndex + I);
1353
1354 llvm::dxbc::PSV::SemanticKind Kind = llvm::hlsl::getSemanticKind(Name);
1355 llvm::dxil::ElementType CompType =
1356 getSignatureComponentType(CGM, Shape.RowType);
1357 // SV_SampleIndex and SV_PrimitiveID may be declared as int or uint, as in
1358 // DXC. Both are indices generated by the system, so they are never negative
1359 // and a signed declaration reads the same value. DXIL signatures require an
1360 // unsigned component type.
1361 if (Kind == llvm::dxbc::PSV::SemanticKind::SampleIndex ||
1362 Kind == llvm::dxbc::PSV::SemanticKind::PrimitiveID) {
1363 if (CompType == llvm::dxil::ElementType::I16)
1364 CompType = llvm::dxil::ElementType::U16;
1365 else if (CompType == llvm::dxil::ElementType::I32)
1366 CompType = llvm::dxil::ElementType::U32;
1367 }
1368
1369 // The remaining members keep their default value and will be filled at a
1370 // later stage, either during packing or analysis of usage. Interpolation
1371 // is set by the load/store traversal after visiting each leaf.
1372 return llvm::hlsl::SemanticSignatureElement(SigId, Name, CompType, Kind,
1373 SemanticIndices,
1374 static_cast<uint8_t>(Shape.Cols));
1375}
1376
1377llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
1378 llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
1379 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index,
1380 SemanticSignatures &Signature) {
1381 StringRef Name = Semantic->getAttrName()->getName();
1382 SemanticShape Shape =
1384
1385 uint32_t SigId = Signature.size();
1386 Signature.push_back(
1387 createSemanticSignatureElement(CGM, SigId, Semantic, Index, Shape));
1388
1389 llvm::Type *RowTy = CGM.getTypes().ConvertTypeForMem(Shape.RowType);
1390
1391 llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
1392 B.getModule(), llvm::Intrinsic::dx_load_input, {RowTy});
1393
1394 SmallVector<OperandBundleDef, 1> OB;
1395 if (auto *Token = getConvergenceToken(*B.GetInsertBlock())) {
1396 llvm::Value *bundleArgs[] = {Token};
1397 OB.emplace_back("convergencectrl", bundleArgs);
1398 }
1399
1400 bool IsMatrixValue = Shape.IsMatrix && Type->isVectorTy();
1401 llvm::Type *LeafTy = Shape.IsMatrix && !IsMatrixValue
1402 ? RowTy
1403 : CGM.getTypes().ConvertType(Shape.RowType);
1404 llvm::Value *Result = llvm::PoisonValue::get(Type);
1405
1406 const unsigned NumRows = Shape.getNumRows();
1407
1408 for (unsigned Row = 0; Row < NumRows; ++Row) {
1409 std::array<Value *, 4> Args{
1410 /*SigElementId=*/B.getInt32(SigId),
1411 /*RowIndex=*/B.getInt32(Row),
1412 /*ColIndex=*/B.getInt8(0),
1413 /*GsVertexOrPrimIndex=*/llvm::PoisonValue::get(B.getInt32Ty())};
1414 llvm::Value *Value =
1415 B.CreateCall(IntrFn, Args, OB, Twine(Name).concat(Twine(Row)));
1416 // Booleans use their memory representation in DXIL signatures, but
1417 // function parameters use their value representation.
1418 if (Value->getType() != LeafTy) {
1419 assert(Shape.RowType->hasBooleanRepresentation() &&
1420 "unexpected semantic load type mismatch");
1421 Value = B.CreateICmpNE(
1422 Value, llvm::Constant::getNullValue(Value->getType()), "loadedv");
1423 }
1424
1425 if (IsMatrixValue) {
1426 for (unsigned Col = 0; Col < Shape.Cols; ++Col)
1427 Result =
1428 B.CreateInsertElement(Result, B.CreateExtractElement(Value, Col),
1429 Shape.getMatrixElementIndex(Row, Col));
1430 } else {
1431 SmallVector<unsigned> Indices = Shape.getArrayIndicesForRow(Row);
1432 Result =
1433 Indices.empty() ? Value : B.CreateInsertValue(Result, Value, Indices);
1434 }
1435 }
1436 return Result;
1437}
1438
1439void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
1440 llvm::Value *Source,
1441 const clang::DeclaratorDecl *Decl,
1442 HLSLAppliedSemanticAttr *Semantic,
1443 std::optional<unsigned> Index,
1444 SemanticSignatures &Signature) {
1445 SemanticShape Shape =
1447
1448 uint32_t SigId = Signature.size();
1449 Signature.push_back(
1450 createSemanticSignatureElement(CGM, SigId, Semantic, Index, Shape));
1451
1452 llvm::Type *RowTy = CGM.getTypes().ConvertTypeForMem(Shape.RowType);
1453
1454 llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
1455 B.getModule(), llvm::Intrinsic::dx_store_output, {RowTy});
1456
1457 SmallVector<OperandBundleDef, 1> OB;
1458 if (auto *Token = getConvergenceToken(*B.GetInsertBlock())) {
1459 llvm::Value *bundleArgs[] = {Token};
1460 OB.emplace_back("convergencectrl", bundleArgs);
1461 }
1462
1463 bool IsMatrixValue = Shape.IsMatrix && Source->getType()->isVectorTy();
1464 const unsigned NumRows = Shape.getNumRows();
1465 for (unsigned Row = 0; Row < NumRows; ++Row) {
1466 llvm::Value *Val;
1467 if (IsMatrixValue) {
1468 SmallVector<int, 4> Mask;
1469 for (unsigned Col = 0; Col < Shape.Cols; ++Col)
1470 Mask.push_back(Shape.getMatrixElementIndex(Row, Col));
1471 Val = B.CreateShuffleVector(Source, Mask);
1472 } else {
1473 SmallVector<unsigned> Indices = Shape.getArrayIndicesForRow(Row);
1474 Val = Indices.empty() ? Source : B.CreateExtractValue(Source, Indices);
1475 }
1476
1477 // Booleans use their memory representation in DXIL signatures, but direct
1478 // function results use their value representation.
1479 if (Val->getType() != RowTy) {
1480 assert(Shape.RowType->hasBooleanRepresentation() &&
1481 "unexpected semantic store type mismatch");
1482 Val = B.CreateZExt(Val, RowTy, "storedv");
1483 }
1484
1485 std::array<Value *, 4> Args{/*SigElementId=*/B.getInt32(SigId),
1486 /*RowIndex=*/B.getInt32(Row),
1487 /*ColIndex=*/B.getInt8(0), /*Value=*/Val};
1488 B.CreateCall(IntrFn, Args, OB);
1489 }
1490}
1491
1492llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
1493 IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
1494 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index,
1495 SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode) {
1496 if (CGM.getTarget().getTriple().isSPIRV())
1497 return emitSPIRVUserSemanticLoad(B, Type, Decl, Semantic, Index,
1498 InterpMode);
1499
1500 if (CGM.getTarget().getTriple().isDXIL())
1501 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index, Signature);
1502
1503 llvm_unreachable("Unsupported target for user-semantic load.");
1504}
1505
1506void CGHLSLRuntime::emitUserSemanticStore(
1507 IRBuilder<> &B, llvm::Value *Source, const clang::DeclaratorDecl *Decl,
1508 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index,
1509 SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode) {
1510 if (CGM.getTarget().getTriple().isSPIRV())
1511 return emitSPIRVUserSemanticStore(B, Source, Decl, Semantic, Index,
1512 InterpMode);
1513
1514 if (CGM.getTarget().getTriple().isDXIL())
1515 return emitDXILUserSemanticStore(B, Source, Decl, Semantic, Index,
1516 Signature);
1517
1518 llvm_unreachable("Unsupported target for user-semantic load.");
1519}
1520
1522 IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
1523 HLSLAppliedSemanticAttr *Semantic,
1524 llvm::dxbc::PSV::SemanticKind SemanticKind,
1525 llvm::Triple::EnvironmentType Stage, std::optional<unsigned> Index,
1526 SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode) {
1527 switch (SemanticKind) {
1528 case llvm::dxbc::PSV::SemanticKind::Barycentrics:
1529 assert(Stage == llvm::Triple::Pixel &&
1530 "SV_Barycentrics is in an unavailable stage and should have been "
1531 "diagnosed by Sema");
1532 if (CGM.getTarget().getTriple().isSPIRV()) {
1533 using llvm::hlsl::InterpolationMode;
1534 // Perspective is encoded by the built-in; only sampling decorations
1535 // belong on the interface variable.
1536 bool NoPerspective = false;
1537 switch (InterpMode) {
1538 case InterpolationMode::LinearNoperspective:
1539 NoPerspective = true;
1540 InterpMode = InterpolationMode::Linear;
1541 break;
1542 case InterpolationMode::LinearNoperspectiveCentroid:
1543 NoPerspective = true;
1544 InterpMode = InterpolationMode::LinearCentroid;
1545 break;
1546 case InterpolationMode::LinearNoperspectiveSample:
1547 NoPerspective = true;
1548 InterpMode = InterpolationMode::LinearSample;
1549 break;
1550 default:
1551 break;
1552 }
1553 // SPIR-V barycentric built-ins are float3, even for half3 inputs.
1554 llvm::Type *BuiltinType = llvm::FixedVectorType::get(CGM.FloatTy, 3);
1555 llvm::Value *Barycentrics = createSPIRVInputLoad(
1556 B, CGM.getModule(), BuiltinType, Semantic->getSemanticName(),
1557 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1558 NoPerspective ? /* BuiltIn::BaryCoordNoPerspKHR */ 5287
1559 : /* BuiltIn::BaryCoordKHR */ 5286,
1560 InterpMode);
1561 if (Type->getScalarType()->isHalfTy())
1562 return B.CreateFPTrunc(Barycentrics, Type);
1563 return Barycentrics;
1564 }
1565 if (CGM.getTarget().getTriple().isDXIL())
1566 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1567 Signature);
1568 break;
1569 case llvm::dxbc::PSV::SemanticKind::GroupIndex: {
1570 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1571 llvm::Triple::Amplification},
1572 Stage) &&
1573 "SV_GroupIndex is in an unavailable stage and should have been "
1574 "diagnosed by Sema");
1575 assert(Stage != llvm::Triple::Mesh &&
1576 Stage != llvm::Triple::Amplification &&
1577 "FIXME: SV_GroupIndex is not yet implemented for this shader "
1578 "stage");
1579 llvm::Function *GroupIndex =
1580 CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
1581 return B.CreateCall(FunctionCallee(GroupIndex));
1582 }
1583 case llvm::dxbc::PSV::SemanticKind::DispatchThreadID: {
1584 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1585 llvm::Triple::Amplification},
1586 Stage) &&
1587 "SV_DispatchThreadID is in an unavailable stage and should have "
1588 "been diagnosed by Sema");
1589 assert(Stage != llvm::Triple::Mesh &&
1590 Stage != llvm::Triple::Amplification &&
1591 "FIXME: SV_DispatchThreadID is not yet implemented for this "
1592 "shader stage");
1593 llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
1594 llvm::Function *ThreadIDIntrinsic =
1595 llvm::Intrinsic::isOverloaded(IntrinID)
1596 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1597 : CGM.getIntrinsic(IntrinID);
1598 return buildVectorInput(B, ThreadIDIntrinsic, Type);
1599 }
1600 case llvm::dxbc::PSV::SemanticKind::GroupThreadID: {
1601 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1602 llvm::Triple::Amplification},
1603 Stage) &&
1604 "SV_GroupThreadID is in an unavailable stage and should have been "
1605 "diagnosed by Sema");
1606 assert(Stage != llvm::Triple::Mesh &&
1607 Stage != llvm::Triple::Amplification &&
1608 "FIXME: SV_GroupThreadID is not yet implemented for this shader "
1609 "stage");
1610 llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
1611 llvm::Function *GroupThreadIDIntrinsic =
1612 llvm::Intrinsic::isOverloaded(IntrinID)
1613 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1614 : CGM.getIntrinsic(IntrinID);
1615 return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
1616 }
1617 case llvm::dxbc::PSV::SemanticKind::GroupID: {
1618 assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
1619 llvm::Triple::Amplification},
1620 Stage) &&
1621 "SV_GroupID is in an unavailable stage and should have been "
1622 "diagnosed by Sema");
1623 assert(Stage != llvm::Triple::Mesh &&
1624 Stage != llvm::Triple::Amplification &&
1625 "FIXME: SV_GroupID is not yet implemented for this shader stage");
1626 llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
1627 llvm::Function *GroupIDIntrinsic =
1628 llvm::Intrinsic::isOverloaded(IntrinID)
1629 ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
1630 : CGM.getIntrinsic(IntrinID);
1631 return buildVectorInput(B, GroupIDIntrinsic, Type);
1632 }
1633 case llvm::dxbc::PSV::SemanticKind::Position:
1634 assert(llvm::is_contained({llvm::Triple::Hull, llvm::Triple::Domain,
1635 llvm::Triple::Geometry, llvm::Triple::Pixel},
1636 Stage) &&
1637 "SV_Position is in an unavailable stage and should have been "
1638 "diagnosed by Sema");
1639 assert(Stage != llvm::Triple::Hull && Stage != llvm::Triple::Domain &&
1640 Stage != llvm::Triple::Geometry &&
1641 "FIXME: loading SV_Position is not yet implemented for this "
1642 "shader stage");
1643 if (CGM.getTarget().getTriple().isSPIRV())
1644 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1645 Semantic->getAttrName()->getName(),
1646 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1647 /* FragCoord */ 15, InterpMode);
1648 if (CGM.getTarget().getTriple().isDXIL())
1649 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1650 Signature);
1651 break;
1652 case llvm::dxbc::PSV::SemanticKind::VertexID:
1653 assert(Stage == llvm::Triple::Vertex &&
1654 "SV_VertexID is in an unavailable stage and should have been "
1655 "diagnosed by Sema");
1656 if (CGM.getTarget().getTriple().isSPIRV())
1657 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1658 Semantic->getAttrName()->getName(),
1659 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1660 /* VertexIndex */ 42, InterpMode);
1661 if (CGM.getTarget().getTriple().isDXIL())
1662 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1663 Signature);
1664 break;
1665 case llvm::dxbc::PSV::SemanticKind::InstanceID:
1666 assert(Stage == llvm::Triple::Vertex &&
1667 "SV_InstanceID is in an unavailable stage and should have been "
1668 "diagnosed by Sema");
1669 if (CGM.getTarget().getTriple().isSPIRV())
1670 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1671 Semantic->getAttrName()->getName(),
1672 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1673 /* InstanceIndex */ 43, InterpMode);
1674 if (CGM.getTarget().getTriple().isDXIL())
1675 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1676 Signature);
1677 break;
1678 case llvm::dxbc::PSV::SemanticKind::ShadingRate:
1679 assert(llvm::is_contained({llvm::Triple::Hull, llvm::Triple::Domain,
1680 llvm::Triple::Geometry, llvm::Triple::Pixel},
1681 Stage) &&
1682 "SV_ShadingRate is in an unavailable stage and should have been "
1683 "diagnosed by Sema");
1684 assert(Stage != llvm::Triple::Hull && Stage != llvm::Triple::Domain &&
1685 Stage != llvm::Triple::Geometry &&
1686 "FIXME: loading SV_ShadingRate is not yet implemented for this "
1687 "shader stage");
1688 if (CGM.getTarget().getTriple().isSPIRV())
1689 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1690 Semantic->getAttrName()->getName(),
1691 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1692 /* ShadingRateKHR */ 4444, InterpMode);
1693 if (CGM.getTarget().getTriple().isDXIL())
1694 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1695 Signature);
1696 break;
1697 case llvm::dxbc::PSV::SemanticKind::StartVertexLocation:
1698 assert(Stage == llvm::Triple::Vertex &&
1699 "SV_StartVertexLocation is in an unavailable stage and should have "
1700 "been diagnosed by Sema");
1701 if (CGM.getTarget().getTriple().isSPIRV())
1702 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1703 Semantic->getAttrName()->getName(),
1704 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1705 /* BaseVertex */ 4424, InterpMode);
1706 if (CGM.getTarget().getTriple().isDXIL())
1707 return B.CreateCall(
1708 CGM.getIntrinsic(llvm::Intrinsic::dx_start_vertex_location));
1709 break;
1710 case llvm::dxbc::PSV::SemanticKind::PrimitiveID:
1711 assert(Stage == llvm::Triple::Pixel &&
1712 "SV_PrimitiveID is in an unavailable stage and should have been "
1713 "diagnosed by Sema");
1714 if (CGM.getTarget().getTriple().isSPIRV())
1715 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1716 Semantic->getAttrName()->getName(),
1717 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1718 /* PrimitiveId */ 7, InterpMode);
1719 // Pixel shaders read the primitive ID from the input signature. The
1720 // dx.op.primitiveID operation is only available to other stages.
1721 if (CGM.getTarget().getTriple().isDXIL())
1722 return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
1723 Signature);
1724 break;
1725 case llvm::dxbc::PSV::SemanticKind::SampleIndex:
1726 assert(Stage == llvm::Triple::Pixel &&
1727 "SV_SampleIndex is in an unavailable stage and should have been "
1728 "diagnosed by Sema");
1729 if (CGM.getTarget().getTriple().isSPIRV())
1730 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1731 Semantic->getAttrName()->getName(),
1732 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1733 /* SampleId */ 18, InterpMode);
1734 if (CGM.getTarget().getTriple().isDXIL()) {
1735 assert(Type->isIntegerTy() && Type->getIntegerBitWidth() <= 32 &&
1736 "SV_SampleIndex must be a 16 or 32 bit scalar integer, as "
1737 "diagnosed by Sema");
1738 // The sample index is read with a dedicated operation, but an unpacked
1739 // element is still added to the input signature for compatibility.
1740 SemanticShape Shape =
1742 Signature.push_back(createSemanticSignatureElement(
1743 CGM, Signature.size(), Semantic, Index, Shape));
1744 llvm::Value *SampleIndex =
1745 B.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::dx_sample_index));
1746 // dx.op.sampleIndex only has an i32 overload, so a 16-bit declaration
1747 // narrows the result. The sample index always fits in 16 bits.
1748 if (Type->getIntegerBitWidth() < 32)
1749 SampleIndex = B.CreateTrunc(SampleIndex, Type);
1750 return SampleIndex;
1751 }
1752 break;
1753 case llvm::dxbc::PSV::SemanticKind::ViewID:
1754 assert(llvm::is_contained({llvm::Triple::Vertex, llvm::Triple::Hull,
1755 llvm::Triple::Domain, llvm::Triple::Geometry,
1756 llvm::Triple::Pixel, llvm::Triple::Mesh},
1757 Stage) &&
1758 "SV_ViewID is in an unavailable stage and should have been "
1759 "diagnosed by Sema");
1760 if (CGM.getTarget().getTriple().isSPIRV())
1761 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1762 Semantic->getAttrName()->getName(),
1763 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1764 /* ViewIndex */ 4440, InterpMode);
1765 if (CGM.getTarget().getTriple().isDXIL())
1766 return B.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::dx_view_id));
1767 break;
1768 case llvm::dxbc::PSV::SemanticKind::StartInstanceLocation:
1769 assert(Stage == llvm::Triple::Vertex &&
1770 "SV_StartInstanceLocation is in an unavailable stage and should "
1771 "have been diagnosed by Sema");
1772 if (CGM.getTarget().getTriple().isSPIRV())
1773 return createSPIRVInputLoad(B, CGM.getModule(), Type,
1774 Semantic->getAttrName()->getName(),
1775 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1776 /* BaseInstance */ 4425, InterpMode);
1777 if (CGM.getTarget().getTriple().isDXIL())
1778 return B.CreateCall(
1779 CGM.getIntrinsic(llvm::Intrinsic::dx_start_instance_location));
1780 break;
1781 default:
1782 break;
1783 }
1784
1785 llvm_unreachable(
1786 "Load hasn't been implemented yet for this system semantic. FIXME");
1787}
1788
1790 IRBuilder<> &B, llvm::Value *Source, const clang::DeclaratorDecl *Decl,
1791 HLSLAppliedSemanticAttr *Semantic,
1792 llvm::dxbc::PSV::SemanticKind SemanticKind,
1793 llvm::Triple::EnvironmentType Stage, std::optional<unsigned> Index,
1794 SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode) {
1795 switch (SemanticKind) {
1796 case llvm::dxbc::PSV::SemanticKind::Position:
1797 assert(llvm::is_contained({llvm::Triple::Vertex, llvm::Triple::Hull,
1798 llvm::Triple::Domain, llvm::Triple::Geometry,
1799 llvm::Triple::Mesh},
1800 Stage) &&
1801 "SV_Position is in an unavailable stage and should have been "
1802 "diagnosed by Sema");
1803 assert(Stage != llvm::Triple::Hull && Stage != llvm::Triple::Domain &&
1804 Stage != llvm::Triple::Geometry && Stage != llvm::Triple::Mesh &&
1805 "FIXME: storing SV_Position is not yet implemented for this "
1806 "shader stage");
1807 if (CGM.getTarget().getTriple().isDXIL()) {
1808 emitDXILUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
1809 return;
1810 }
1811 if (CGM.getTarget().getTriple().isSPIRV()) {
1812 createSPIRVOutputStore(B, CGM.getModule(), Source,
1813 Semantic->getAttrName()->getName(),
1814 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1815 /* Position */ 0, InterpMode);
1816 return;
1817 }
1818 break;
1819 case llvm::dxbc::PSV::SemanticKind::Target:
1820 assert(Stage == llvm::Triple::Pixel &&
1821 "SV_Target is in an unavailable stage and should have been "
1822 "diagnosed by Sema");
1823 emitUserSemanticStore(B, Source, Decl, Semantic, Index, Signature,
1824 InterpMode);
1825 return;
1826 case llvm::dxbc::PSV::SemanticKind::ShadingRate:
1827 assert(llvm::is_contained({llvm::Triple::Vertex, llvm::Triple::Hull,
1828 llvm::Triple::Domain, llvm::Triple::Geometry,
1829 llvm::Triple::Mesh},
1830 Stage) &&
1831 "SV_ShadingRate is in an unavailable stage and should have been "
1832 "diagnosed by Sema");
1833 assert(Stage != llvm::Triple::Hull && Stage != llvm::Triple::Domain &&
1834 Stage != llvm::Triple::Geometry && Stage != llvm::Triple::Mesh &&
1835 "FIXME: storing SV_ShadingRate is not yet implemented for this "
1836 "shader stage");
1837 if (CGM.getTarget().getTriple().isDXIL()) {
1838 emitDXILUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
1839 return;
1840 }
1841 if (CGM.getTarget().getTriple().isSPIRV()) {
1842 // Matches DXC: the PrimitiveShadingRateKHR built-in output does not
1843 // carry the Flat decoration implied for integer vertex outputs.
1844 createSPIRVOutputStore(B, CGM.getModule(), Source,
1845 Semantic->getAttrName()->getName(),
1846 llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
1847 /* PrimitiveShadingRateKHR */ 4432,
1848 llvm::hlsl::InterpolationMode::Undefined);
1849 return;
1850 }
1851 break;
1852 default:
1853 break;
1854 }
1855
1856 llvm_unreachable(
1857 "Store hasn't been implemented yet for this system semantic. FIXME");
1858}
1859
1861 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1862 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1863 SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode) {
1864
1865 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1866 llvm::dxbc::PSV::SemanticKind SemanticKind =
1867 llvm::hlsl::getSemanticKind(Semantic->getAttrName()->getName());
1868 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1869 assert(ShaderAttr && "Entry point has no shader attribute");
1870 llvm::hlsl::SemanticInterpretation Interpretation =
1871 llvm::hlsl::getInterpretationKind(SemanticKind, ShaderAttr->getType(),
1872 llvm::hlsl::IOType::In);
1873 assert(Interpretation != llvm::hlsl::SemanticInterpretation::Invalid &&
1874 "invalid semantic should have been diagnosed by Sema");
1875 if (CGM.getTarget().getTriple().isSPIRV())
1876 InterpMode = getSPIRVInterpolationMode(
1877 InterpMode, Type, ShaderAttr->getType(), llvm::hlsl::IOType::In);
1878 if (Interpretation == llvm::hlsl::SemanticInterpretation::Arbitrary)
1879 return emitUserSemanticLoad(B, Type, Decl, Semantic, Index, Signature,
1880 InterpMode);
1881 return emitSystemSemanticLoad(B, Type, Decl, Semantic, SemanticKind,
1882 ShaderAttr->getType(), Index, Signature,
1883 InterpMode);
1884}
1885
1887 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
1888 const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
1889 SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode) {
1890 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1891 llvm::dxbc::PSV::SemanticKind SemanticKind =
1892 llvm::hlsl::getSemanticKind(Semantic->getAttrName()->getName());
1893 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
1894 assert(ShaderAttr && "Entry point has no shader attribute");
1895
1896 llvm::hlsl::SemanticInterpretation Interpretation =
1897 llvm::hlsl::getInterpretationKind(SemanticKind, ShaderAttr->getType(),
1898 llvm::hlsl::IOType::Out);
1899 assert(Interpretation != llvm::hlsl::SemanticInterpretation::Invalid &&
1900 "invalid semantic should have been diagnosed by Sema");
1901 if (CGM.getTarget().getTriple().isSPIRV())
1902 InterpMode = getSPIRVInterpolationMode(InterpMode, Source->getType(),
1903 ShaderAttr->getType(),
1904 llvm::hlsl::IOType::Out);
1905
1906 if (Interpretation == llvm::hlsl::SemanticInterpretation::Arbitrary)
1907 return emitUserSemanticStore(B, Source, Decl, Semantic, Index, Signature,
1908 InterpMode);
1909 emitSystemSemanticStore(B, Source, Decl, Semantic, SemanticKind,
1910 ShaderAttr->getType(), Index, Signature, InterpMode);
1911}
1912
1913std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1915 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1919 SemanticSignatures &Signature,
1920 llvm::hlsl::InterpolationModifier Modifiers) {
1921 const llvm::StructType *ST = cast<StructType>(Type);
1922 const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();
1923
1924 assert(RD->getNumFields() == ST->getNumElements());
1925
1926 llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
1927 auto FieldDecl = RD->field_begin();
1928 for (unsigned I = 0; I < ST->getNumElements(); ++I) {
1929 auto [ChildValue, NextAttr] =
1930 handleSemanticLoad(B, FD, ST->getElementType(I), *FieldDecl, AttrBegin,
1931 AttrEnd, Signature, Modifiers);
1932 AttrBegin = NextAttr;
1933 assert(ChildValue);
1934 Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
1935 ++FieldDecl;
1936 }
1937
1938 return std::make_pair(Aggregate, AttrBegin);
1939}
1940
1943 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
1947 SemanticSignatures &Signature,
1948 llvm::hlsl::InterpolationModifier Modifiers) {
1949
1950 const llvm::StructType *ST = cast<StructType>(Source->getType());
1951
1952 const clang::RecordDecl *RD = nullptr;
1953 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
1955 else
1956 RD = Decl->getType()->getAsRecordDecl();
1957 assert(RD);
1958
1959 assert(RD->getNumFields() == ST->getNumElements());
1960
1961 auto FieldDecl = RD->field_begin();
1962 for (unsigned I = 0; I < ST->getNumElements(); ++I, ++FieldDecl) {
1963 llvm::Value *Extract = B.CreateExtractValue(Source, I);
1964 AttrBegin = handleSemanticStore(B, FD, Extract, *FieldDecl, AttrBegin,
1965 AttrEnd, Signature, Modifiers);
1966 }
1967
1968 return AttrBegin;
1969}
1970
1971std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1973 IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
1977 SemanticSignatures &Signature,
1978 llvm::hlsl::InterpolationModifier Modifiers) {
1979 assert(AttrBegin != AttrEnd);
1980 // Pass the enclosing declaration's mask down the traversal, replacing (not
1981 // merging) it when an inner field has its own interpolation modifiers.
1982 if (const auto *A = Decl->getAttr<HLSLInterpolationModifierAttr>())
1983 Modifiers =
1984 static_cast<llvm::hlsl::InterpolationModifier>(A->getModifiers());
1985 if (Type->isStructTy())
1986 return handleStructSemanticLoad(B, FD, Type, Decl, AttrBegin, AttrEnd,
1987 Signature, Modifiers);
1988
1989 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
1990 ++AttrBegin;
1991 size_t PreviousSize = Signature.size();
1992 auto InterpMode = llvm::hlsl::getInterpolationMode(Modifiers);
1993 llvm::Value *Value =
1994 handleScalarSemanticLoad(B, FD, Type, Decl, Attr, Signature, InterpMode);
1995 // Intrinsic-only system values and SPIR-V loads do not add DXIL signature
1996 // elements. Non-pixel inputs retain Undefined.
1997 if (Signature.size() != PreviousSize) {
1998 auto &Element = Signature.back();
1999 Element.InterpMode = llvm::hlsl::normalizeInterpolationMode(
2000 InterpMode, Element.CompType, Element.SemanticKind,
2001 FD->getAttr<HLSLShaderAttr>()->getType(), llvm::hlsl::IOType::In);
2002 }
2003 return std::make_pair(Value, AttrBegin);
2004}
2005
2008 IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
2012 SemanticSignatures &Signature,
2013 llvm::hlsl::InterpolationModifier Modifiers) {
2014 assert(AttrBegin != AttrEnd);
2015 // An inner field overrides the enclosing return declaration's modifiers.
2016 if (const auto *A = Decl->getAttr<HLSLInterpolationModifierAttr>())
2017 Modifiers =
2018 static_cast<llvm::hlsl::InterpolationModifier>(A->getModifiers());
2019 if (Source->getType()->isStructTy())
2020 return handleStructSemanticStore(B, FD, Source, Decl, AttrBegin, AttrEnd,
2021 Signature, Modifiers);
2022
2023 HLSLAppliedSemanticAttr *Attr = *AttrBegin;
2024 ++AttrBegin;
2025 size_t PreviousSize = Signature.size();
2026 auto InterpMode = llvm::hlsl::getInterpolationMode(Modifiers);
2027 handleScalarSemanticStore(B, FD, Source, Decl, Attr, Signature, InterpMode);
2028 if (Signature.size() != PreviousSize) {
2029 auto &Element = Signature.back();
2030 Element.InterpMode = llvm::hlsl::normalizeInterpolationMode(
2031 InterpMode, Element.CompType, Element.SemanticKind,
2032 FD->getAttr<HLSLShaderAttr>()->getType(), llvm::hlsl::IOType::Out);
2033 }
2034 return AttrBegin;
2035}
2036
2038 llvm::Function *Fn) {
2041
2042 llvm::Module &M = CGM.getModule();
2043 llvm::LLVMContext &Ctx = M.getContext();
2044 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
2045 Function *EntryFn =
2046 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
2047
2048 // Copy function attributes over, we have no argument or return attributes
2049 // that can be valid on the real entry.
2050 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
2051 Fn->getAttributes().getFnAttrs());
2052 EntryFn->setAttributes(NewAttrs);
2053 setHLSLEntryAttributes(FD, EntryFn);
2054
2055 // Set the called function as internal linkage.
2056 Fn->setLinkage(GlobalValue::InternalLinkage);
2057
2058 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
2059 IRBuilder<> B(BB);
2061
2063 if (CGM.shouldEmitConvergenceTokens()) {
2064 assert(EntryFn->isConvergent());
2065 llvm::Value *I =
2066 B.CreateIntrinsic(llvm::Intrinsic::experimental_convergence_entry, {});
2067 llvm::Value *bundleArgs[] = {I};
2068 OB.emplace_back("convergencectrl", bundleArgs);
2069 }
2070
2072
2073 unsigned SRetOffset = 0;
2074 for (const auto &Param : Fn->args()) {
2075 if (Param.hasStructRetAttr()) {
2076 SRetOffset = 1;
2077 llvm::Type *VarType = Param.getParamStructRetType();
2078 llvm::Value *Var =
2079 CGM.getLangOpts().EmitLogicalPointer
2080 ? cast<Instruction>(B.CreateStructuredAlloca(VarType))
2081 : cast<Instruction>(B.CreateAlloca(VarType));
2082 OutputSemantic.push_back(std::make_pair(Var, VarType));
2083 Args.push_back(Var);
2084 continue;
2085 }
2086
2087 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
2088 llvm::Value *SemanticValue = nullptr;
2089 // FIXME: support inout/out parameters for semantics.
2090 if ([[maybe_unused]] HLSLParamModifierAttr *MA =
2091 PD->getAttr<HLSLParamModifierAttr>()) {
2092 llvm_unreachable("Not handled yet");
2093 } else {
2094 llvm::Type *ParamType = nullptr;
2095 if (Param.hasByValAttr())
2096 ParamType = Param.getParamByValType();
2097 else if (PD->getType()->isRecordType())
2098 ParamType = CGM.getTypes().ConvertType(PD->getType());
2099 else
2100 ParamType = Param.getType();
2101
2102 auto AttrBegin = PD->specific_attr_begin<HLSLAppliedSemanticAttr>();
2103 auto AttrEnd = PD->specific_attr_end<HLSLAppliedSemanticAttr>();
2104 auto Result = handleSemanticLoad(B, FD, ParamType, PD, AttrBegin, AttrEnd,
2105 InputSignature);
2106 SemanticValue = Result.first;
2107 if (!SemanticValue)
2108 return;
2109 if (Param.hasByValAttr() || PD->getType()->isRecordType()) {
2110 llvm::Value *Var =
2111 CGM.getLangOpts().EmitLogicalPointer
2112 ? cast<Instruction>(B.CreateStructuredAlloca(ParamType))
2113 : cast<Instruction>(B.CreateAlloca(ParamType));
2114 B.CreateStore(SemanticValue, Var);
2115 SemanticValue = Var;
2116 }
2117 }
2118
2119 assert(SemanticValue);
2120 Args.push_back(SemanticValue);
2121 }
2122
2123 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
2124 CI->setCallingConv(Fn->getCallingConv());
2125
2126 if (Fn->getReturnType() != CGM.VoidTy)
2127 // Element type is unused, so set to dummy value (NULL).
2128 OutputSemantic.push_back(std::make_pair(CI, nullptr));
2129
2130 for (auto &SourcePair : OutputSemantic) {
2131 llvm::Value *Source = SourcePair.first;
2132 llvm::Type *ElementType = SourcePair.second;
2133 AllocaInst *AI = dyn_cast<AllocaInst>(Source);
2134 llvm::Value *SourceValue = AI ? B.CreateLoad(ElementType, Source) : Source;
2135
2136 auto AttrBegin = FD->specific_attr_begin<HLSLAppliedSemanticAttr>();
2137 auto AttrEnd = FD->specific_attr_end<HLSLAppliedSemanticAttr>();
2138 handleSemanticStore(B, FD, SourceValue, FD, AttrBegin, AttrEnd,
2139 OutputSignature);
2140 }
2141
2142 B.CreateRetVoid();
2143
2144 // Add and identify root signature to function, if applicable
2145 for (const Attr *Attr : FD->getAttrs()) {
2146 if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) {
2147 auto *RSDecl = RSAttr->getSignatureDecl();
2148 addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
2149 EntryFn, M);
2150 }
2151 }
2152
2153 if (CGM.getTarget().getTriple().isDXIL()) {
2154 // Use the entry's shader stage, not the target environment, which may be
2155 // 'library' when compiling multiple entry points.
2156 auto Stage = FD->getAttr<HLSLShaderAttr>()->getType();
2158 auto Mode = CGM.getCodeGenOpts().getHLSLSemanticSignaturePacking();
2159 for (auto IOTy : {llvm::hlsl::IOType::In, llvm::hlsl::IOType::Out}) {
2160 bool IsOutput = IOTy == llvm::hlsl::IOType::Out;
2161 auto &Signature = IsOutput ? OutputSignature : InputSignature;
2162 auto Packed = packSemanticSignature(Signature, Stage, IOTy, Mode,
2163 CGM.getLangOpts().NativeHalfType);
2164 if (!Packed) {
2165 CGM.getDiags().Report(FD->getLocation(),
2166 diag::err_hlsl_signature_packing)
2167 << IsOutput << llvm::toString(Packed.takeError());
2168 return;
2169 }
2170 // Library entry points retain stage-specific packing without warnings.
2171 if (Mode != PackingMode::Default &&
2172 CGM.getTarget().getTriple().getEnvironment() !=
2173 llvm::Triple::Library &&
2174 ((Stage == llvm::Triple::Vertex && !IsOutput) ||
2175 (Stage == llvm::Triple::Pixel && IsOutput)))
2176 CGM.getDiags().Report(FD->getLocation(),
2177 diag::warn_hlsl_signature_packing_ignored)
2178 << (Mode == PackingMode::Optimized ? "optimized" : "prefix-stable")
2179 << IsOutput;
2180 }
2181 }
2182
2183 addSemanticSignatureMD(InputSignature, OutputSignature, EntryFn, M);
2184}
2185
2186static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
2187 bool CtorOrDtor) {
2188 const auto *GV =
2189 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
2190 if (!GV)
2191 return;
2192 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
2193 if (!CA)
2194 return;
2195 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
2196 // HLSL neither supports priorities or COMDat values, so we will check those
2197 // in an assert but not handle them.
2198
2199 for (const auto &Ctor : CA->operands()) {
2201 continue;
2202 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
2203
2204 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
2205 "HLSL doesn't support setting priority for global ctors.");
2206 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
2207 "HLSL doesn't support COMDat for global ctors.");
2208 Fns.push_back(cast<Function>(CS->getOperand(1)));
2209 }
2210}
2211
2213 llvm::Module &M = CGM.getModule();
2216 gatherFunctions(CtorFns, M, true);
2217 gatherFunctions(DtorFns, M, false);
2218
2219 // Insert a call to the global constructor at the beginning of the entry block
2220 // to externally exported functions. This is a bit of a hack, but HLSL allows
2221 // global constructors, but doesn't support driver initialization of globals.
2222 for (auto &F : M.functions()) {
2223 if (!F.hasFnAttribute("hlsl.shader"))
2224 continue;
2225 auto *Token = getConvergenceToken(F.getEntryBlock());
2226 Instruction *IP = &*F.getEntryBlock().begin();
2228 if (Token) {
2229 llvm::Value *bundleArgs[] = {Token};
2230 OB.emplace_back("convergencectrl", bundleArgs);
2231 IP = Token->getNextNode();
2232 }
2233 IRBuilder<> B(IP);
2234 for (auto *Fn : CtorFns) {
2235 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
2236 CI->setCallingConv(Fn->getCallingConv());
2237 }
2238
2239 // Insert global dtors before the terminator of the last instruction
2240 B.SetInsertPoint(F.back().getTerminator());
2241 for (auto *Fn : DtorFns) {
2242 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
2243 CI->setCallingConv(Fn->getCallingConv());
2244 }
2245 }
2246
2247 // No need to keep global ctors/dtors for non-lib profile after call to
2248 // ctors/dtors added for entry.
2249 Triple T(M.getTargetTriple());
2250 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
2251 if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
2252 GV->eraseFromParent();
2253 if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
2254 GV->eraseFromParent();
2255 }
2256}
2257
2258static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
2259 Intrinsic::ID IntrID,
2261
2262 LLVMContext &Ctx = CGM.getLLVMContext();
2263 llvm::Function *InitResFunc =
2264 llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, false),
2265 llvm::GlobalValue::InternalLinkage,
2266 "_init_buffer_" + GV->getName(), CGM.getModule());
2267 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
2268
2269 llvm::BasicBlock *EntryBB =
2270 llvm::BasicBlock::Create(Ctx, "entry", InitResFunc);
2271 CGBuilderTy Builder(CGM, Ctx);
2272 const DataLayout &DL = CGM.getModule().getDataLayout();
2273 Builder.SetInsertPoint(EntryBB);
2274
2275 // Make sure the global variable is buffer resource handle
2276 llvm::Type *HandleTy = GV->getValueType();
2277 assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");
2278
2279 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
2280 /*ReturnType=*/HandleTy, IntrID, Args, nullptr,
2281 Twine(GV->getName()).concat("_h"));
2282
2283 Builder.CreateAlignedStore(CreateHandle, GV, GV->getPointerAlignment(DL));
2284 Builder.CreateRetVoid();
2285
2286 CGM.AddCXXGlobalInit(InitResFunc);
2287}
2288
2289void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
2290 llvm::GlobalVariable *GV) {
2291 ResourceBindingAttrs Binding(BufDecl);
2292 assert(Binding.hasBinding() &&
2293 "cbuffer/tbuffer should always have resource binding attribute");
2294
2295 auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
2296 auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
2297 auto *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
2298 Value *Name = buildNameForResource(BufDecl->getName(), CGM);
2299
2300 // buffer with explicit binding
2301 if (Binding.isExplicit()) {
2302 llvm::Intrinsic::ID IntrinsicID =
2303 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
2304 auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
2305 SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
2306 initializeBuffer(CGM, GV, IntrinsicID, Args);
2307 } else {
2308 // buffer with implicit binding
2309 llvm::Intrinsic::ID IntrinsicID =
2310 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
2311 auto *OrderID =
2312 llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
2313 SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
2314 initializeBuffer(CGM, GV, IntrinsicID, Args);
2315 }
2316}
2317
2319 llvm::GlobalVariable *GV) {
2320 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
2322 GV, llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn, Attr->getBuiltIn());
2323 if (auto Attr = VD->getAttr<HLSLVkExtBuiltinOutputAttr>())
2325 GV, llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn, Attr->getBuiltIn());
2326}
2327
2328llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
2329 if (!CGM.shouldEmitConvergenceTokens())
2330 return nullptr;
2331
2332 auto E = BB.end();
2333 for (auto I = BB.begin(); I != E; ++I) {
2334 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
2335 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
2336 return II;
2337 }
2338 }
2339 llvm_unreachable("Convergence token should have been emitted.");
2340 return nullptr;
2341}
2342
2343class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
2344public:
2348
2350 // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
2351 // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
2352 // traversal, the temporary containing the copy out will not have
2353 // been created yet.
2354 return false;
2355 }
2356
2358 // Traverse the source expression first.
2359 if (E->getSourceExpr())
2361
2362 // Then add this OVE if we haven't seen it before.
2363 if (Visited.insert(E).second)
2364 OVEs.push_back(E);
2365
2366 return true;
2367 }
2368};
2369
2371 InitListExpr *E) {
2372
2373 typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
2374 OpaqueValueVisitor Visitor;
2375 Visitor.TraverseStmt(E);
2376 for (auto *OVE : Visitor.OVEs) {
2377 if (CGF.isOpaqueValueEmitted(OVE))
2378 continue;
2379 if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
2380 LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
2381 OpaqueValueMappingData::bind(CGF, OVE, LV);
2382 } else {
2383 RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
2384 OpaqueValueMappingData::bind(CGF, OVE, RV);
2385 }
2386 }
2387}
2388
2390 const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
2391 assert((ArraySubsExpr->getType()->isHLSLResourceRecord() ||
2392 ArraySubsExpr->getType()->isHLSLResourceRecordArray()) &&
2393 "expected resource array subscript expression");
2394
2395 // Let clang codegen handle local and static resource array subscripts,
2396 // or when the subscript references on opaque expression (as part of
2397 // ArrayInitLoopExpr AST node).
2398 const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(
2399 getArrayDecl(CGF.CGM.getContext(), ArraySubsExpr));
2400 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
2401 ArrayDecl->getStorageClass() == SC_Static)
2402 return std::nullopt;
2403
2404 // get the resource array type
2405 ASTContext &AST = ArrayDecl->getASTContext();
2406 const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
2407 assert(ResArrayTy->isHLSLResourceRecordArray() &&
2408 "expected array of resource classes");
2409
2410 // Iterate through all nested array subscript expressions to calculate
2411 // the index in the flattened resource array (if this is a multi-
2412 // dimensional array). The index is calculated as a sum of all indices
2413 // multiplied by the total size of the array at that level.
2414 Value *Index = nullptr;
2415 const ArraySubscriptExpr *ASE = ArraySubsExpr;
2416 while (ASE != nullptr) {
2417 Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
2418 if (const auto *ArrayTy =
2419 dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
2420 Value *Multiplier = llvm::ConstantInt::get(
2421 CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy));
2422 SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
2423 }
2424 Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
2425 ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
2426 }
2427
2428 // Find binding info for the resource array. For implicit binding
2429 // an HLSLResourceBindingAttr should have been added by SemaHLSL.
2430 ResourceBindingAttrs Binding(ArrayDecl);
2431 assert(Binding.hasBinding() &&
2432 "resource array must have a binding attribute");
2433
2434 // Find the individual resource type.
2435 QualType ResultTy = ArraySubsExpr->getType();
2436 QualType ResourceTy =
2437 ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy;
2438
2439 // Create a temporary variable for the result, which is either going
2440 // to be a single resource instance or a local array of resources (we need to
2441 // return an LValue).
2442 RawAddress TmpVar = CGF.CreateMemTempWithoutCast(ResultTy);
2443 if (CGF.EmitLifetimeStart(TmpVar.getPointer()))
2445 NormalEHLifetimeMarker, TmpVar);
2446
2451
2452 // Calculate total array size (= range size).
2453 llvm::Value *Range = llvm::ConstantInt::getSigned(
2454 CGM.IntTy, getTotalArraySize(AST, ResArrayTy));
2455
2456 // If the result of the subscript operation is a single resource, call the
2457 // constructor.
2458 if (ResultTy == ResourceTy) {
2459 CallArgList Args;
2460 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
2461 CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
2462 ArrayDecl->getName(), Binding, Args);
2463
2464 if (!CreateMethod) {
2465 // This can happen if someone creates an array of structs that looks like
2466 // an HLSL resource record array but it does not have the required static
2467 // create method. No binding will be generated for it.
2468 assert(!ResourceTy->getAsCXXRecordDecl()->isImplicit() &&
2469 "create method lookup should always succeed for built-in resource "
2470 "records");
2471 return std::nullopt;
2472 }
2473
2474 callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
2475
2476 } else {
2477 // The result of the subscript operation is a local resource array which
2478 // needs to be initialized.
2479 const ConstantArrayType *ArrayTy =
2481 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
2482 CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
2483 ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)});
2484 if (!EndIndex)
2485 return std::nullopt;
2486 }
2487 return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
2488}
2489
2490// Initialize all resources of a global resource array into provided slot.
2491bool CGHLSLRuntime::initializeGlobalResourceArray(CodeGenFunction &CGF,
2492 const VarDecl *ArrayDecl,
2493 AggValueSlot &DestSlot) {
2494 assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
2495 ArrayDecl->hasGlobalStorage() &&
2496 ArrayDecl->getStorageClass() != SC_Static &&
2497 "expected global non-static resource array");
2498
2499 // Find binding info for the resource array. For implicit binding
2500 // the HLSLResourceBindingAttr should have been added by SemaHLSL.
2501 ResourceBindingAttrs Binding(ArrayDecl);
2502 assert(Binding.hasBinding() &&
2503 "resource array must have a binding attribute");
2504
2505 // Find the individual resource type.
2506 ASTContext &AST = ArrayDecl->getASTContext();
2507 QualType ResTy = AST.getBaseElementType(ArrayDecl->getType());
2508 const auto *ResArrayTy =
2510
2511 // Create Value for index and total array size (= range size).
2512 int Size = getTotalArraySize(AST, ResArrayTy);
2513 llvm::Value *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
2514 llvm::Value *Range = llvm::ConstantInt::get(CGM.IntTy, Size);
2515
2516 // Initialize individual resources in the array into DestSlot.
2517 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
2518 CGF, ResTy->getAsCXXRecordDecl(), ResArrayTy, DestSlot, Range, Zero,
2519 ArrayDecl->getName(), Binding, {Zero});
2520 return EndIndex.has_value();
2521}
2522
2523// If the expression is a global resource array, initialize all of its resources
2524// into Dest. Returns false if no initialization has been performed and the
2525// array copy should be handled by the default codegen.
2527 AggValueSlot &DestSlot) {
2528 assert(E->getType()->isHLSLResourceRecordArray() &&
2529 "expected resource array");
2530
2531 // Find the array declaration for the expression. Fallback to the default
2532 // handling if it's not a global resource array.
2533 const VarDecl *ArrayDecl =
2534 dyn_cast_or_null<VarDecl>(getArrayDecl(CGF.CGM.getContext(), E));
2535 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
2536 ArrayDecl->getStorageClass() == SC_Static)
2537 return false;
2538
2539 return initializeGlobalResourceArray(CGF, ArrayDecl, DestSlot);
2540}
2541
2542// If the expression is a global resource array, create a temporary and
2543// initialize all of its resources, and return it as an LValue. Returns nullopt
2544// if no initialization has been performed and the handling should follow the
2545// default path.
2546std::optional<LValue>
2548 const VarDecl *ArrayDecl) {
2549 assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
2550 "expected resource array declaration");
2551
2552 if (!ArrayDecl->hasGlobalStorage() ||
2553 ArrayDecl->getStorageClass() == SC_Static)
2554 return std::nullopt;
2555
2556 AggValueSlot TmpArraySlot =
2557 CGF.CreateAggTemp(ArrayDecl->getType(), "tmpResArray");
2558 if (initializeGlobalResourceArray(CGF, ArrayDecl, TmpArraySlot))
2559 return CGF.MakeAddrLValue(TmpArraySlot.getAddress(), ArrayDecl->getType(),
2561 return std::nullopt;
2562}
2563
2565 CodeGenFunction &CGF) {
2566
2567 assert(LV.getType()->isConstantMatrixType() && "expected matrix type");
2569 "expected cbuffer matrix");
2570
2571 QualType MatQualTy = LV.getType();
2572 llvm::Type *LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(MatQualTy);
2573 Address SrcAddr = LV.getAddress();
2574
2575 if (LayoutTy == CGF.ConvertTypeForMem(MatQualTy))
2576 return SrcAddr;
2577
2578 RawAddress DestAlloca =
2579 CGF.CreateMemTempWithoutCast(MatQualTy, "matrix.buf.copy");
2580 HLSLBufferCopyEmitter(CGF, DestAlloca, SrcAddr).emitCopy(MatQualTy);
2581 return DestAlloca;
2582}
2583
2585 const ArraySubscriptExpr *E, CodeGenFunction &CGF,
2586 llvm::function_ref<llvm::Value *(bool Promote)> EmitIdxAfterBase) {
2587 // Find the element type to index by first padding the element type per HLSL
2588 // buffer rules, and then padding out to a 16-byte register boundary if
2589 // necessary.
2590 llvm::Type *LayoutTy =
2592 uint64_t LayoutSizeInBits =
2593 CGM.getDataLayout().getTypeSizeInBits(LayoutTy).getFixedValue();
2594 CharUnits ElementSize = CharUnits::fromQuantity(LayoutSizeInBits / 8);
2595 CharUnits RowAlignedSize = ElementSize.alignTo(CharUnits::fromQuantity(16));
2596 if (RowAlignedSize > ElementSize) {
2597 llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding(
2598 CGM, RowAlignedSize - ElementSize);
2599 assert(Padding && "No padding type for target?");
2600 LayoutTy = llvm::StructType::get(CGF.getLLVMContext(), {LayoutTy, Padding},
2601 /*isPacked=*/true);
2602 }
2603
2604 // If the layout type doesn't introduce any padding, we don't need to do
2605 // anything special.
2606 llvm::Type *OrigTy = CGF.CGM.getTypes().ConvertTypeForMem(E->getType());
2607 if (LayoutTy == OrigTy)
2608 return std::nullopt;
2609
2610 LValueBaseInfo EltBaseInfo;
2611 TBAAAccessInfo EltTBAAInfo;
2612
2613 // Index into the object as-if we have an array of the padded element type,
2614 // and then dereference the element itself to avoid reading padding that may
2615 // be past the end of the in-memory object.
2617 llvm::Value *Idx = EmitIdxAfterBase(/*Promote*/ true);
2618 Indices.push_back(Idx);
2619 Indices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
2620
2621 if (CGF.getLangOpts().EmitLogicalPointer) {
2622 // The fact that we emit an array-to-pointer decay might be an oversight,
2623 // but for now, we simply ignore it (see #179951).
2624 const CastExpr *CE = cast<CastExpr>(E->getBase());
2625 assert(CE->getCastKind() == CastKind::CK_ArrayToPointerDecay);
2626
2627 LValue LV = CGF.EmitLValue(CE->getSubExpr());
2628 Address Addr = LV.getAddress();
2629 LayoutTy = llvm::ArrayType::get(
2630 LayoutTy,
2631 cast<llvm::ArrayType>(Addr.getElementType())->getNumElements());
2632 auto *GEP = cast<StructuredGEPInst>(CGF.Builder.CreateStructuredGEP(
2633 LayoutTy, Addr.emitRawPointer(CGF), Indices, "cbufferidx"));
2634 Addr =
2635 Address(GEP, GEP->getResultElementType(), RowAlignedSize, KnownNonNull);
2636 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
2637 }
2638
2639 Address Addr =
2640 CGF.EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
2641 llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF),
2642 Indices, "cbufferidx");
2643 Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull);
2644 return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
2645}
2646
2647std::optional<LValue>
2649 const MemberExpr *ME) {
2650 assert((ME->getType()->isHLSLResourceRecord() ||
2652 "expected resource member expression");
2653
2654 const VarDecl *ResourceVD =
2655 findAssociatedResourceDeclForStruct(CGF.CGM.getContext(), ME);
2656 if (!ResourceVD)
2657 return std::nullopt;
2658
2659 // Handle member of resource array type.
2660 if (ResourceVD->getType()->isHLSLResourceRecordArray())
2661 return emitGlobalResourceArrayAsLValue(CGF, ResourceVD);
2662
2663 GlobalVariable *ResGV =
2664 cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(ResourceVD));
2665 const DataLayout &DL = CGM.getDataLayout();
2666 llvm::Type *Ty = ResGV->getValueType();
2667 CharUnits Align = CharUnits::fromQuantity(DL.getABITypeAlign(Ty));
2668 Address Addr = Address(ResGV, Ty, Align);
2669 LValue LV = LValue::MakeAddr(Addr, ME->getType(), CGM.getContext(),
2671 CGM.getTBAAAccessInfo(ME->getType()));
2672 return LV;
2673}
2674
2676 const LValue &SrcLV,
2677 AggValueSlot &DestSlot) {
2679 "expected expression in HLSL constant address space");
2680 assert(!E->getType()->isHLSLResourceRecord() &&
2682 "direct accesses to resource types should be handled separately");
2683
2684 if (DestSlot.isIgnored())
2685 return false;
2686
2687 QualType Ty = E->getType();
2688 Address DstPtr = DestSlot.getAddress();
2689 Address SrcPtr = SrcLV.getAddress();
2690
2691 // If there are no intangible types, we don't need to lookup associated
2692 // resources.
2693 if (!Ty->isHLSLIntangibleType())
2694 return HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty);
2695
2696 // Handle structs with intangible types by setting the resource fields
2697 // of the destination struct with the resources associated with the global
2698 // struct.
2699 EmbeddedResourceNameBuilder NameBuilder;
2700 const VarDecl *VD = findStructResourceParentDeclAndBuildName(E, NameBuilder);
2701 AssociatedResourcesList AssociatedResources(VD, NameBuilder.getName());
2702
2703 // Callback to fill in the associated resource.
2704 auto EmitResFn = [&](AggValueSlot &ResSlot) {
2705 const VarDecl *ResDecl = AssociatedResources.getNextResource();
2706 assert(ResDecl && "associated resource declaration not found");
2707
2708 // Check that the resource type of dest and src matches.
2709 [[maybe_unused]] llvm::Type *DestType =
2710 ResSlot.getAddress().getElementType();
2711 [[maybe_unused]] llvm::Type *SrcConvertedType =
2712 CGM.getTypes().ConvertTypeForMem(ResDecl->getType());
2713 assert(DestType == SrcConvertedType && "resource slot type mismatch");
2714
2715 if (ResDecl->getType()->isHLSLResourceRecord())
2716 copyGlobalResource(CGF, ResDecl, ResSlot);
2717 else
2718 initializeGlobalResourceArray(CGF, ResDecl, ResSlot);
2719 };
2720
2721 auto Result =
2722 HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty, EmitResFn);
2723 assert(AssociatedResources.getNextResource() == nullptr &&
2724 "expected all associated resources to be processed");
2725 return Result;
2726}
2727
2729 const MemberExpr *E) {
2730 LValue Base =
2732 auto *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
2733 assert(Field && "Unexpected access into HLSL buffer");
2734
2735 const RecordDecl *Rec = Field->getParent();
2736
2737 // Work out the buffer layout type to index into.
2738 QualType RecType = CGM.getContext().getCanonicalTagType(Rec);
2739 assert(RecType->isStructureOrClassType() && "Invalid type in HLSL buffer");
2740 // Since this is a member of an object in the buffer and not the buffer's
2741 // struct/class itself, we shouldn't have any offsets on the members we need
2742 // to contend with.
2743 CGHLSLOffsetInfo EmptyOffsets;
2744 llvm::StructType *LayoutTy = HLSLBufferLayoutBuilder(CGM).layOutStruct(
2745 RecType->getAsCanonical<RecordType>(), EmptyOffsets);
2746
2747 // Get the field index for the layout struct, accounting for padding.
2748 unsigned FieldIdx =
2749 CGM.getTypes().getCGRecordLayout(Rec).getLLVMFieldNo(Field);
2750 assert(FieldIdx < LayoutTy->getNumElements() &&
2751 "Layout struct is smaller than member struct");
2752 unsigned Skipped = 0;
2753 for (unsigned I = 0; I <= FieldIdx;) {
2754 llvm::Type *ElementTy = LayoutTy->getElementType(I + Skipped);
2755 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(ElementTy))
2756 ++Skipped;
2757 else
2758 ++I;
2759 }
2760 FieldIdx += Skipped;
2761 assert(FieldIdx < LayoutTy->getNumElements() && "Access out of bounds");
2762
2763 // Now index into the struct, making sure that the type we return is the
2764 // buffer layout type rather than the original type in the AST.
2765 QualType FieldType = Field->getType();
2766 llvm::Type *FieldLLVMTy = CGM.getTypes().ConvertTypeForMem(FieldType);
2768 CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy));
2769
2770 Value *Ptr = CGF.getLangOpts().EmitLogicalPointer
2771 ? CGF.Builder.CreateStructuredGEP(
2772 LayoutTy, Base.getPointer(CGF),
2773 llvm::ConstantInt::get(CGM.IntTy, FieldIdx))
2774 : CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF),
2775 FieldIdx, Field->getName());
2776 Address Addr(Ptr, FieldLLVMTy, Align, KnownNonNull);
2777
2778 LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(),
2780 CGM.getTBAAAccessInfo(FieldType));
2781 LV.getQuals().addCVRQualifiers(Base.getVRQualifiers());
2782
2783 return LV;
2784}
Defines the clang::ASTContext interface.
static bool requiresFlatInterpolation(llvm::Type *Ty)
static llvm::dxil::ElementType getSignatureComponentType(CodeGenModule &CGM, QualType Ty)
static QualType getSemanticLeafType(const clang::DeclaratorDecl *Decl)
static void addSPIRVInterfaceDecorations(llvm::GlobalVariable *GV, llvm::hlsl::SPIRVInterfaceDecoration Decoration, unsigned Operand, llvm::hlsl::InterpolationMode InterpMode=llvm::hlsl::InterpolationMode::Undefined)
static llvm::hlsl::SemanticSignatureElement createSemanticSignatureElement(CodeGenModule &CGM, uint32_t SigId, HLSLAppliedSemanticAttr *Semantic, std::optional< unsigned > Index, const SemanticShape &Shape)
static void gatherFunctions(SmallVectorImpl< Function * > &Fns, llvm::Module &M, bool CtorOrDtor)
static llvm::Value * createSPIRVInputLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, llvm::hlsl::SPIRVInterfaceDecoration Decoration, unsigned Operand, llvm::hlsl::InterpolationMode InterpMode)
static llvm::hlsl::InterpolationMode getSPIRVInterpolationMode(llvm::hlsl::InterpolationMode InterpMode, llvm::Type *Ty, llvm::Triple::EnvironmentType Stage, llvm::hlsl::IOType IO)
static void createSPIRVOutputStore(IRBuilder<> &B, llvm::Module &M, llvm::Value *Source, const Twine &Name, llvm::hlsl::SPIRVInterfaceDecoration Decoration, unsigned Operand, llvm::hlsl::InterpolationMode InterpMode)
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 SemanticShape getSemanticShape(ASTContext &Ctx, QualType Ty)
TokenType getType() const
Returns the token's type, e.g.
Result
Implement __builtin_bit_cast and related operations.
llvm::MachO::Record Record
Definition MachO.h:31
Defines AST-level helper utilities for matrix types.
llvm::dxbc::PSV::SemanticKind SemanticKind
Definition SemaHLSL.cpp:62
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:245
SourceManager & getSourceManager()
Definition ASTContext.h:913
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.
const LangOptions & getLangOpts() const
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 getExtVectorType(QualType VectorType, unsigned NumElts) const
Return the unique reference to an extended vector type of the specified element type and size.
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:2790
QualType getElementType() const
Definition TypeBase.h:3832
Attr - This represents one attribute.
Definition Attr.h:47
This class is used for builtin types like 'int'.
Definition TypeBase.h:3245
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2153
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:3745
CastKind getCastKind() const
Definition Expr.h:3789
Expr * getSubExpr()
Definition Expr.h:3795
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:171
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:184
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:689
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:148
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Definition CGBuilder.h:304
Address CreateStructGEP(Address Addr, unsigned Index, const llvm::Twine &Name="")
Definition CGBuilder.h:231
Abstract information about a function or function prototype.
Definition CGCall.h:43
All available information about a concrete callee.
Definition CGCall.h:66
CGFunctionInfo - Class to encapsulate the information about a function definition.
static const uint32_t Unspecified
static bool compareOffsets(uint32_t LHS, uint32_t RHS)
Comparison function for offsets received from operator[] suitable for use in a stable_sort.
static CGHLSLOffsetInfo fromDecl(const HLSLBufferDecl &BufDecl)
Iterates over all declarations in the HLSL buffer and based on the packoffset or register(c#) annotat...
llvm::Instruction * getConvergenceToken(llvm::BasicBlock &BB)
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
llvm::Value * handleScalarSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode)
llvm::StructType * getHLSLBufferLayoutType(const RecordType *LayoutStructTy)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var)
void handleScalarSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode)
std::optional< LValue > emitResourceMemberExpr(CodeGenFunction &CGF, const MemberExpr *E)
specific_attr_iterator< HLSLAppliedSemanticAttr > handleStructSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrBegin, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrEnd, SemanticSignatures &Signature, llvm::hlsl::InterpolationModifier Modifiers)
llvm::SmallVectorImpl< llvm::hlsl::SemanticSignatureElement > SemanticSignatures
void addHLSLBufferLayoutType(const RecordType *LayoutStructTy, llvm::StructType *LayoutTy)
std::optional< LValue > emitGlobalResourceArrayAsLValue(CodeGenFunction &CGF, const VarDecl *ArrayDecl)
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::hlsl::InterpolationMode InterpMode)
bool emitBufferCopy(CodeGenFunction &CGF, const Expr *E, const LValue &SrcLV, AggValueSlot &DestSlot)
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::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, llvm::hlsl::InterpolationMode InterpMode)
llvm::Type * convertHLSLSpecificType(const Type *T, const CGHLSLOffsetInfo &OffsetInfo)
RawAddress createBufferMatrixTempAddress(const LValue &LV, CodeGenFunction &CGF)
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, llvm::hlsl::InterpolationModifier Modifiers=llvm::hlsl::InterpolationModifier::None)
void addBuffer(const HLSLBufferDecl *D)
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, llvm::hlsl::InterpolationModifier Modifiers)
bool emitGlobalResourceArray(CodeGenFunction &CGF, const Expr *E, AggValueSlot &DestSlot)
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E)
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, llvm::hlsl::InterpolationModifier Modifiers=llvm::hlsl::InterpolationModifier::None)
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:1368
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:5703
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:236
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:285
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:1661
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK)
Same as EmitLValue but additionally we generate checking code to guard against undefined behavior.
Definition CGExpr.cpp:1742
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:1777
bool isOpaqueValueEmitted(const OpaqueValueExpr *E)
isOpaqueValueEmitted - Return true if the opaque value expression has already been emitted.
Definition CGExpr.cpp:6610
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:3858
int64_t getSExtSize() const
Return the size sign-extended as a uint64_t.
Definition TypeBase.h:3940
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4622
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2108
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:582
bool hasAttrs() const
Definition DeclBase.h:527
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:602
SourceLocation getLocation() const
Definition DeclBase.h:448
specific_attr_iterator< T > specific_attr_end() const
Definition DeclBase.h:578
specific_attr_iterator< T > specific_attr_begin() const
Definition DeclBase.h:573
AttrVec & getAttrs()
Definition DeclBase.h:533
Represents a ValueDecl that came out of a declarator.
Definition Decl.h:782
This represents one expression.
Definition Expr.h:114
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3129
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:3109
QualType getType() const
Definition Expr.h:146
Represents a member of a struct/union/class.
Definition Decl.h:3341
StringRef getName() const
The name of this FileEntry.
Definition FileEntry.h:61
Represents a function declaration or definition.
Definition Decl.h:2082
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2974
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:3039
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5548
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5378
bool isCBuffer() const
Definition Decl.h:5422
const CXXRecordDecl * getLayoutStruct() const
Definition Decl.h:5425
bool hasValidPackoffset() const
Definition Decl.h:5424
buffer_decl_range buffer_decls() const
Definition Decl.h:5453
This class represents temporary values used to represent inout and out arguments in HLSL.
Definition Expr.h:7483
ArrayRef< llvm::hlsl::rootsig::RootElement > getRootElements() const
Definition Decl.h:5495
llvm::dxbc::RootSignatureVersion getVersion() const
Definition Decl.h:5493
One of these records is kept for each identifier that is lexed.
Describes an C or C++ initializer list.
Definition Expr.h:5377
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3433
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3516
Expr * getBase() const
Definition Expr.h:3510
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:297
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:303
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition Expr.h:1223
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Definition Expr.h:1273
Represents a parameter to a function.
Definition Decl.h:1832
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:8578
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8704
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:4506
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
Definition Decl.h:4722
field_iterator field_begin() const
Definition Decl.cpp:5383
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:2415
bool isIncompleteArrayType() const
Definition TypeBase.h:8922
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:8914
bool isConstantMatrixType() const
Definition TypeBase.h:8982
bool isHLSLIntangibleType() const
Definition Type.cpp:5726
bool isHLSLResourceRecord() const
Definition Type.cpp:5713
bool isStructureOrClassType() const
Definition Type.cpp:839
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:3002
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9431
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:786
bool isRecordType() const
Definition TypeBase.h:8942
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5717
bool hasBooleanRepresentation() const
Determine whether this type has a boolean representation – i.e., it is a boolean type,...
Definition Type.cpp:2572
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:714
QualType getType() const
Definition Decl.h:725
Represents a variable declaration or definition.
Definition Decl.h:934
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1249
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:1176
Represents a GCC generic vector type.
Definition TypeBase.h:4398
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:2189
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:196
bool isMatrixRowMajor(const LangOptions &LangOpts, QualType T)
Returns true if matrices of T should be laid out in row-major order.
Definition MatrixUtils.h:25
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
StorageClass
Storage classes.
Definition Specifiers.h:252
@ SC_Static
Definition Specifiers.h:256
@ SC_None
Definition Specifiers.h:254
@ 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_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 __builtin_riscv_mqwacc_i64 uint8_t
unsigned getCounterImplicitOrderID() const