33#include "llvm/ADT/DenseMap.h"
34#include "llvm/ADT/STLExtras.h"
35#include "llvm/ADT/ScopeExit.h"
36#include "llvm/ADT/SmallString.h"
37#include "llvm/ADT/SmallVector.h"
38#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
39#include "llvm/IR/Constants.h"
40#include "llvm/IR/DerivedTypes.h"
41#include "llvm/IR/GlobalVariable.h"
42#include "llvm/IR/IntrinsicInst.h"
43#include "llvm/IR/LLVMContext.h"
44#include "llvm/IR/Metadata.h"
45#include "llvm/IR/Module.h"
46#include "llvm/IR/Type.h"
47#include "llvm/IR/Value.h"
48#include "llvm/Support/Alignment.h"
49#include "llvm/Support/ErrorHandling.h"
50#include "llvm/Support/FormatVariadic.h"
51#include "llvm/Support/Path.h"
52#include "llvm/Transforms/Utils/ModuleUtils.h"
61using llvm::hlsl::CBufferRowSizeInBytes;
65void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
69 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
70 Version.getSubminor() || !Version.getMinor()) {
74 uint64_t Major = Version.getMajor();
75 uint64_t Minor = *Version.getMinor();
77 auto &Ctx = M.getContext();
78 IRBuilder<> B(M.getContext());
79 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
80 ConstantAsMetadata::get(B.getInt32(Minor))});
81 StringRef DXILValKey =
"dx.valver";
82 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
83 DXILValMD->addOperand(Val);
86void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
88 llvm::Function *Fn, llvm::Module &M) {
89 auto &Ctx = M.getContext();
91 llvm::hlsl::rootsig::MetadataBuilder RSBuilder(Ctx, Elements);
92 MDNode *RootSignature = RSBuilder.BuildRootSignature();
94 ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get(
95 llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer)));
96 ValueAsMetadata *EntryFunc =
Fn ? ValueAsMetadata::get(Fn) :
nullptr;
97 MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version});
99 StringRef RootSignatureValKey =
"dx.rootsignatures";
100 auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey);
101 RootSignatureValMD->addOperand(MDVals);
106 GlobalVariable *ResGV =
108 assert(ResGV &&
"expected valid global variable");
125static const VarDecl *findStructResourceParentDeclAndBuildName(
132 if (
const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
134 "member expr base is not a var decl");
140 WorkList.push_back(E);
141 if (
const auto *MExp = dyn_cast<MemberExpr>(E))
143 else if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
144 E = ICE->getSubExpr();
145 else if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
152 llvm_unreachable(
"unexpected expr type in resource member access");
154 assert(E &&
"expected valid expression");
157 while (!WorkList.empty()) {
158 E = WorkList.pop_back_val();
159 if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
161 ME->getMemberNameInfo().getName().getAsIdentifierInfo()->getName());
162 }
else if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
163 if (ICE->getCastKind() == CK_UncheckedDerivedToBase) {
165 ICE->getSubExpr()->getType()->getAsCXXRecordDecl();
166 CXXRecordDecl *BaseRD = ICE->getType()->getAsCXXRecordDecl();
169 }
else if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
170 const Expr *IdxExpr = ASE->getIdx();
171 std::optional<llvm::APSInt>
Value =
174 "expected constant index in struct with resource array access");
177 llvm_unreachable(
"unexpected expr type in resource member access");
191 findStructResourceParentDeclAndBuildName(ME, NameBuilder);
200 if (
const auto *ADA = dyn_cast<HLSLAssociatedResourceDeclAttr>(A)) {
201 VarDecl *AssocResVD = ADA->getResDecl();
213 auto &Ctx = M.getContext();
216 llvm::NamedMDNode *DXContents =
217 M.getOrInsertNamedMetadata(
"dx.source.contents");
218 auto addFile = [&](
const std::pair<StringRef, StringRef> &NameContent) {
219 llvm::MDTuple *FileInfo =
220 llvm::MDNode::get(Ctx, {llvm::MDString::get(Ctx, NameContent.first),
221 llvm::MDString::get(Ctx, NameContent.second)});
222 DXContents->addOperand(FileInfo);
228 assert(!
Invalid &&
"Main file SLocEntry must not be invalid!");
233 std::optional<SmallString<256>> MainFileName;
234 Files.reserve(
SM.local_sloc_entry_size());
235 for (
unsigned I : llvm::seq(
SM.local_sloc_entry_size())) {
250 llvm::sys::path::native(Path);
254 SM.getDiagnostics().Report(diag::warn_hlsl_failed_to_embed_source)
259 if (&MainCCEntry != &CCEntry) {
260 Files.emplace_back(Path, Buffer->getBuffer());
263 addFile(std::make_pair(Path, Buffer->getBuffer()));
264 MainFileName.emplace(Path);
267 assert(MainFileName &&
"Main file not found.");
272 for (
unsigned I = 1; I < Files.size(); ++I)
273 assert((Files[I - 1].first != Files[I].first) &&
274 "duplicate files in dx.source.contents");
276 llvm::for_each(Files, addFile);
279 Defines.reserve(
Macros.size());
283 Defines.emplace_back(llvm::MDString::get(Ctx,
Macro.first));
285 M.getOrInsertNamedMetadata(
"dx.source.defines")
286 ->addOperand(llvm::MDNode::get(Ctx, Defines));
288 if (!CodeGenOpts.MainFileName.empty())
289 llvm::sys::path::native(CodeGenOpts.MainFileName, *MainFileName);
290 M.getOrInsertNamedMetadata(
"dx.source.mainFileName")
292 llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, *MainFileName)));
295 Args.reserve(CodeGenOpts.HLSLParsedCommandLine.size());
296 if (!CodeGenOpts.HLSLParsedCommandLine.empty())
297 for (
const auto &Arg : llvm::drop_begin(CodeGenOpts.HLSLParsedCommandLine))
298 Args.push_back(llvm::MDString::get(Ctx, Arg));
299 M.getOrInsertNamedMetadata(
"dx.source.args")
300 ->addOperand(llvm::MDNode::get(Ctx, Args));
306 if (
const auto *DRE = dyn_cast_or_null<DeclRefExpr>(E))
307 return DRE->getDecl();
308 if (
auto *OVE = dyn_cast<OpaqueValueExpr>(E))
318 const Expr *E =
nullptr;
319 while (ASE !=
nullptr) {
323 ASE = dyn_cast<ArraySubscriptExpr>(E);
325 return getArrayDecl(AST, E);
331 assert(Ty->
isArrayType() &&
"expected array type");
337static Value *buildNameForResource(llvm::StringRef BaseName,
346 for (
auto *Method :
Record->methods()) {
347 if (Method->getStorageClass() == SC && Method->getName() == Name)
357 assert(Binding.
hasBinding() &&
"at least one binding attribute expected");
361 Value *NameStr = buildNameForResource(Name, CGM);
366 "resources with counter handle must have a binding with counter "
367 "implicit order ID");
370 auto *RegSlot = llvm::ConstantInt::get(CGM.
IntTy, Binding.
getSlot());
373 ?
"__createFromBindingWithImplicitCounter"
374 :
"__createFromBinding";
375 CreateMethod = lookupMethod(ResourceDecl, Name,
SC_Static);
382 ?
"__createFromImplicitBindingWithImplicitCounter"
383 :
"__createFromImplicitBinding";
384 CreateMethod = lookupMethod(ResourceDecl, Name,
SC_Static);
392 auto *CounterOrderID = llvm::ConstantInt::get(CGM.
IntTy, CounterBinding);
409 CGF.
EmitCall(FnInfo, Callee, ReturnValue, Args,
nullptr);
418static std::optional<llvm::Value *> initializeResourceArrayFromGlobal(
421 llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
425 llvm::IntegerType *IntTy = CGF.
CGM.
IntTy;
426 llvm::Value *Index = StartIndex;
427 llvm::Value *One = llvm::ConstantInt::get(IntTy, 1);
435 GEPIndices.push_back(llvm::ConstantInt::get(IntTy, 0));
440 for (uint64_t I = 0; I < ArraySize; I++) {
442 Index = CGF.
Builder.CreateAdd(Index, One);
443 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
445 std::optional<llvm::Value *> MaybeIndex =
446 initializeResourceArrayFromGlobal(CGF, ResourceDecl, SubArrayTy,
447 ValueSlot, Range, Index,
448 ResourceName, Binding, GEPIndices);
462 for (uint64_t I = 0; I < ArraySize; I++) {
464 Index = CGF.
Builder.CreateAdd(Index, One);
465 GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
471 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
472 CGF.
CGM, ResourceDecl, Range, Index, ResourceName, Binding, Args);
480 callResourceInitMethod(CGF, CreateMethod, Args, ReturnAddress);
487class HLSLBufferCopyEmitter {
488 CodeGenFunction &CGF;
491 llvm::Type *LayoutTy =
nullptr;
493 SmallVector<llvm::Value *> CurStoreIndices;
494 SmallVector<llvm::Value *> CurLoadIndices;
496 using EmitResourceFnTy = llvm::function_ref<void(AggValueSlot &)>;
500 llvm::Value *emitAccessChain(llvm::Type *BaseTy, llvm::Value *Base,
501 ArrayRef<llvm::Value *> Indices) {
502 bool EmitLogical = CGF.getLangOpts().EmitLogicalPointer;
504 return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, Indices);
506 llvm::SmallVector<llvm::Value *> GEPIndices;
507 GEPIndices.reserve(Indices.size() + 1);
508 GEPIndices.push_back(llvm::ConstantInt::get(CGF.IntTy, 0));
509 GEPIndices.append(Indices.begin(), Indices.end());
510 return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, GEPIndices);
513 bool isBufferLayoutArray(llvm::StructType *ST) {
519 if (!ST || ST->getNumElements() != 2)
522 auto *PaddedEltsTy = dyn_cast<llvm::ArrayType>(ST->getElementType(0));
526 auto *PaddedTy = dyn_cast<llvm::StructType>(PaddedEltsTy->getElementType());
527 if (!PaddedTy || PaddedTy->getNumElements() != 2)
530 if (!CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(
531 PaddedTy->getElementType(1)))
534 llvm::Type *ElementTy = ST->getElementType(1);
535 if (PaddedTy->getElementType(0) != ElementTy)
546 bool isResourceOrResourceArray(llvm::Type *Ty) {
547 while (
auto *AT = dyn_cast<llvm::ArrayType>(Ty))
548 Ty = AT->getElementType();
550 auto *ST = dyn_cast<llvm::StructType>(Ty);
551 if (!ST || ST->getNumElements() < 1)
554 auto *TargetTy = dyn_cast<llvm::TargetExtType>(ST->getElementType(0));
555 return TargetTy !=
nullptr;
558 void emitResourceOrResourceArray(
Value *Dst, llvm::Type *DstTy,
559 EmitResourceFnTy EmitResFn) {
562 Address DstAddr(Dst, DstTy, DstAlign);
571 void emitBufferLayoutCopy(
Value *Src, llvm::StructType *SrcTy,
Value *Dst,
572 llvm::ArrayType *DstTy,
573 EmitResourceFnTy EmitResFn) {
576 assert(SrcPaddedArrayTy->getNumElements() + 1 == DstTy->getNumElements());
578 ->getElementType(0) == SrcTy->getElementType(1));
580 auto *SrcDataTy = SrcTy->getElementType(1);
581 auto Zero = llvm::ConstantInt::get(CGF.IntTy, 0);
583 for (
unsigned I = 0; I < SrcPaddedArrayTy->getNumElements(); ++I) {
584 auto Index = llvm::ConstantInt::get(CGF.IntTy, I);
585 auto *SrcElt = emitAccessChain(SrcTy, Src, {
Zero, Index,
Zero});
586 auto *DstElt = emitAccessChain(DstTy, Dst, {Index});
587 emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType(),
592 emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, 1)});
593 auto *DstElt = emitAccessChain(
595 {llvm::ConstantInt::get(CGF.IntTy, DstTy->getNumElements() - 1)});
596 emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType(),
600 void emitCopy(
Value *Src, llvm::StructType *SrcTy,
Value *Dst,
601 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
602 assert(!isResourceOrResourceArray(DstTy) &&
603 "direct access to resources or resource arrays should be handled "
606 if (isBufferLayoutArray(SrcTy))
610 unsigned SrcIndex = 0;
611 unsigned DstIndex = 0;
618 while (DstIndex < DstST->getNumElements()) {
619 llvm::Type *DstEltTy = DstST->getElementType(DstIndex);
620 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(DstEltTy)) {
624 if (isResourceOrResourceArray(DstEltTy)) {
625 auto *DstElt = emitAccessChain(
626 DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, DstIndex)});
627 emitResourceOrResourceArray(DstElt, DstEltTy, EmitResFn);
632 assert(SrcIndex < SrcTy->getNumElements());
633 llvm::Type *SrcEltTy = SrcTy->getElementType(SrcIndex);
634 if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(SrcEltTy)) {
639 auto *SrcElt = emitAccessChain(
640 SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, SrcIndex)});
641 auto *DstElt = emitAccessChain(
642 DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, DstIndex)});
643 emitElementCopy(SrcElt, SrcEltTy, DstElt, DstEltTy, EmitResFn);
649 void emitCopy(
Value *Src, llvm::ArrayType *SrcTy,
Value *Dst,
650 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
651 for (
unsigned I = 0, E = SrcTy->getNumElements(); I < E; ++I) {
653 emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, I)});
655 emitAccessChain(DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, I)});
656 emitElementCopy(SrcElt, SrcTy->getElementType(), DstElt,
662 void emitElementCopy(
Value *Src, llvm::Type *SrcTy,
Value *Dst,
663 llvm::Type *DstTy, EmitResourceFnTy EmitResFn) {
664 if (
auto *AT = dyn_cast<llvm::ArrayType>(SrcTy))
665 return emitCopy(Src, AT, Dst, DstTy, EmitResFn);
666 if (
auto *ST = dyn_cast<llvm::StructType>(SrcTy))
667 return emitCopy(Src, ST, Dst, DstTy, EmitResFn);
674 Address SrcAddr(Src, SrcTy, SrcAlign);
675 Address DstAddr(Dst, DstTy, DstAlign);
676 llvm::Value *
Load = CGF.Builder.CreateLoad(SrcAddr,
"cbuf.load");
677 CGF.Builder.CreateStore(Load, DstAddr);
681 HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DstPtr, Address SrcPtr)
682 : CGF(CGF), DstPtr(DstPtr), SrcPtr(SrcPtr) {}
684 bool emitCopy(QualType CType, EmitResourceFnTy EmitResFn =
nullptr) {
685 LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(CType);
692 emitElementCopy(SrcPtr.getBasePointer(), LayoutTy, DstPtr.getBasePointer(),
693 DstPtr.getElementType(), EmitResFn);
704class AssociatedResourcesList {
709 specific_attr_iterator<HLSLAssociatedResourceDeclAttr> Begin, End, Next;
712 AssociatedResourcesList(
const VarDecl *StructVD,
713 StringRef ResourceNamePrefix) {
719 !I->getResDecl()->getName().starts_with(ResourceNamePrefix))
721 assert(I != E &&
"expected associated resource not found");
726 while (I != E && ((HLSLAssociatedResourceDeclAttr *)*I)
729 .starts_with(ResourceNamePrefix))
735 const VarDecl *getNextResource() {
739 const VarDecl *Res = Next->getResDecl();
750 assert(T->isHLSLSpecificType() &&
"Not an HLSL specific type!");
753 if (llvm::Type *TargetTy =
757 llvm_unreachable(
"Generic handling of HLSL types is not supported.");
760llvm::Triple::ArchType CGHLSLRuntime::getArch() {
766void CGHLSLRuntime::emitBufferGlobalsAndMetadata(
772 llvm::Type *BufType = BufGV->getValueType();
777 size_t OffsetIdx = 0;
787 VarDecl *VD = dyn_cast<VarDecl>(D);
803 DeclsWithOffset.emplace_back(VD, OffsetInfo[OffsetIdx++]);
806 if (!OffsetInfo.
empty())
807 llvm::stable_sort(DeclsWithOffset, [](
const auto &LHS,
const auto &RHS) {
812 SmallVector<llvm::Metadata *> BufGlobals;
813 BufGlobals.reserve(DeclsWithOffset.size() + 1);
814 BufGlobals.push_back(ValueAsMetadata::get(BufGV));
816 auto ElemIt = LayoutStruct->element_begin();
817 for (
auto &[VD, _] : DeclsWithOffset) {
821 assert(ElemIt != LayoutStruct->element_end() &&
822 "number of elements in layout struct does not match");
823 llvm::Type *LayoutType = *ElemIt++;
825 GlobalVariable *ElemGV =
827 BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
829 assert(ElemIt == LayoutStruct->element_end() &&
830 "number of elements in layout struct does not match");
834 .getOrInsertNamedMetadata(
"hlsl.cbs")
835 ->addOperand(MDNode::get(Ctx, BufGlobals));
839static const clang::HLSLAttributedResourceType *
844 HLSLAttributedResourceType::Attributes(ResourceClass::CBuffer));
859 VarDecl *VD = dyn_cast<VarDecl>(D);
870 if (
auto *POA = dyn_cast<HLSLPackOffsetAttr>(
Attr)) {
871 Offset = POA->getOffsetInBytes();
874 auto *RBA = dyn_cast<HLSLResourceBindingAttr>(
Attr);
876 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
877 Offset = RBA->getSlotNumber() * CBufferRowSizeInBytes;
881 Result.Offsets.push_back(Offset);
889 assert(BufDecl->
isCBuffer() &&
"tbuffer codegen is not supported yet");
892 const clang::HLSLAttributedResourceType *ResHandleTy =
896 if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
902 llvm::GlobalVariable *BufGV =
new GlobalVariable(
904 GlobalValue::LinkageTypes::InternalLinkage, PoisonValue::get(LayoutTy),
905 llvm::formatv(
"{0}{1}", BufDecl->
getName(),
907 GlobalValue::NotThreadLocal);
910 M.insertGlobalVariable(BufGV);
915 llvm::appendToCompilerUsed(M, {BufGV});
918 emitBufferGlobalsAndMetadata(BufDecl, BufGV, OffsetInfo);
921 initializeBufferFromBinding(BufDecl, BufGV);
927 Triple T(M.getTargetTriple());
930 if (T.getEnvironment() != Triple::EnvironmentType::RootSignature)
933 addRootSignatureMD(SignatureDecl->
getVersion(),
939 const auto Entry = LayoutTypes.find(StructType);
940 if (Entry != LayoutTypes.end())
941 return Entry->getSecond();
946 llvm::StructType *LayoutTy) {
948 "layout type for this struct already exist");
949 LayoutTypes[StructType] = LayoutTy;
957 Triple T(M.getTargetTriple());
958 if (T.getArch() == Triple::ArchType::dxil)
959 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
960 if (!CodeGenOpts.DisableDXSourceMetadata &&
961 CodeGenOpts.getDebugInfo() >=
962 llvm::codegenoptions::DebugInfoKind::DebugInfoConstructor)
963 addSourceInfo(CGM, M);
964 if (CodeGenOpts.ResMayAlias)
965 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error,
"dx.resmayalias", 1);
966 if (CodeGenOpts.AllResourcesBound)
967 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error,
968 "dx.allresourcesbound", 1);
969 if (CodeGenOpts.OptimizationLevel == 0)
970 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override,
971 "dx.disable_optimizations", 1);
976 if (LangOpts.NativeHalfType)
977 M.setModuleFlag(llvm::Module::ModFlagBehavior::Error,
"dx.nativelowprec",
980 if (LangOpts.HLSLSpvPreserveInterface && T.isSPIRV()) {
986 for (GlobalVariable &GV : M.globals()) {
987 unsigned AS = GV.getAddressSpace();
988 if (AS == InputAS || AS == OutputAS)
989 InterfaceVars.push_back(&GV);
991 if (!InterfaceVars.empty())
992 appendToCompilerUsed(M, InterfaceVars);
1000 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
1001 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
1002 const StringRef ShaderAttrKindStr =
"hlsl.shader";
1003 Fn->addFnAttr(ShaderAttrKindStr,
1004 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
1005 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
1006 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
1007 std::string NumThreadsStr =
1008 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
1009 NumThreadsAttr->getZ());
1010 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
1012 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->
getAttr<HLSLWaveSizeAttr>()) {
1013 const StringRef WaveSizeKindStr =
"hlsl.wavesize";
1014 std::string WaveSizeStr =
1015 formatv(
"{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
1016 WaveSizeAttr->getPreferred());
1017 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
1024 Fn->addFnAttr(llvm::Attribute::NoInline);
1026 if (CGM.
getLangOpts().HLSLSpvEnableMaximalReconvergence) {
1027 Fn->addFnAttr(
"enable-maximal-reconvergence",
"true");
1032 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
1034 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
1035 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
1040 return B.CreateCall(F, {B.getInt32(0)});
1045 LLVMContext &Ctx = GV->getContext();
1046 IRBuilder<> B(GV->getContext());
1047 MDNode *Operands = MDNode::get(
1049 {ConstantAsMetadata::get(B.getInt32( 11)),
1050 ConstantAsMetadata::get(B.getInt32(BuiltIn))});
1051 MDNode *Decoration = MDNode::get(Ctx, {Operands});
1052 GV->addMetadata(
"spirv.Decorations", *Decoration);
1056 LLVMContext &Ctx = GV->getContext();
1057 IRBuilder<> B(GV->getContext());
1059 MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32( 30)),
1060 ConstantAsMetadata::get(B.getInt32(Location))});
1061 MDNode *Decoration = MDNode::get(Ctx, {Operands});
1062 GV->addMetadata(
"spirv.Decorations", *Decoration);
1066 llvm::Type *Ty,
const Twine &Name,
1067 unsigned BuiltInID) {
1068 auto *GV =
new llvm::GlobalVariable(
1069 M, Ty,
true, llvm::GlobalValue::ExternalLinkage,
1070 nullptr, Name,
nullptr,
1071 llvm::GlobalVariable::GeneralDynamicTLSModel,
1074 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1075 return B.CreateLoad(Ty, GV);
1079 llvm::Type *Ty,
unsigned Location,
1081 auto *GV =
new llvm::GlobalVariable(
1082 M, Ty,
true, llvm::GlobalValue::ExternalLinkage,
1083 nullptr, Name,
nullptr,
1084 llvm::GlobalVariable::GeneralDynamicTLSModel,
1086 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1088 return B.CreateLoad(Ty, GV);
1091llvm::Value *CGHLSLRuntime::emitSPIRVUserSemanticLoad(
1092 llvm::IRBuilder<> &B, llvm::Type *
Type,
const clang::DeclaratorDecl *
Decl,
1093 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
1094 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1095 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1097 unsigned Location = SPIRVLastAssignedInputSemanticLocation;
1098 if (
auto *L =
Decl->getAttr<HLSLVkLocationAttr>())
1099 Location = L->getLocation();
1103 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(
Type);
1104 unsigned ElementCount = AT ? AT->getNumElements() : 1;
1105 SPIRVLastAssignedInputSemanticLocation += ElementCount;
1108 VariableName.str());
1112 llvm::Value *Source,
unsigned Location,
1114 auto *GV =
new llvm::GlobalVariable(
1115 M, Source->getType(),
false,
1116 llvm::GlobalValue::ExternalLinkage,
1117 nullptr, Name,
nullptr,
1118 llvm::GlobalVariable::GeneralDynamicTLSModel,
1120 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1122 B.CreateStore(Source, GV);
1125void CGHLSLRuntime::emitSPIRVUserSemanticStore(
1126 llvm::IRBuilder<> &B, llvm::Value *Source,
1127 const clang::DeclaratorDecl *
Decl, HLSLAppliedSemanticAttr *Semantic,
1128 std::optional<unsigned> Index) {
1129 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1130 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1132 unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
1133 if (
auto *L =
Decl->getAttr<HLSLVkLocationAttr>())
1134 Location = L->getLocation();
1138 llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
1139 unsigned ElementCount = AT ? AT->getNumElements() : 1;
1140 SPIRVLastAssignedOutputSemanticLocation += ElementCount;
1142 VariableName.str());
1146CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *
Type,
1147 HLSLAppliedSemanticAttr *Semantic,
1148 std::optional<unsigned> Index) {
1149 Twine BaseName = Twine(Semantic->getAttrName()->getName());
1150 Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
1155 SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
1157 llvm::PoisonValue::get(B.getInt32Ty())};
1159 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
1161 SmallVector<OperandBundleDef, 1> OB;
1163 llvm::Value *bundleArgs[] = {Token};
1164 OB.emplace_back(
"convergencectrl", bundleArgs);
1167 llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
1168 B.GetInsertBlock()->getModule(), IntrinsicID, {Type});
1169 llvm::Value *
Value = B.CreateCall(IntrFn, Args, OB, VariableName);
1173void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
1174 llvm::Value *Source,
1175 HLSLAppliedSemanticAttr *Semantic,
1176 std::optional<unsigned> Index) {
1179 SmallVector<Value *> Args{B.getInt32(4),
1183 llvm::PoisonValue::get(B.getInt32Ty()),
1186 llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
1188 SmallVector<OperandBundleDef, 1> OB;
1190 llvm::Value *bundleArgs[] = {Token};
1191 OB.emplace_back(
"convergencectrl", bundleArgs);
1194 llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
1195 B.GetInsertBlock()->getModule(), IntrinsicID, {Source->getType()});
1196 B.CreateCall(IntrFn, Args, OB);
1199llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
1200 IRBuilder<> &B, llvm::Type *
Type,
const clang::DeclaratorDecl *
Decl,
1201 HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
1203 return emitSPIRVUserSemanticLoad(B,
Type,
Decl, Semantic, Index);
1206 return emitDXILUserSemanticLoad(B,
Type, Semantic, Index);
1208 llvm_unreachable(
"Unsupported target for user-semantic load.");
1211void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
1212 const clang::DeclaratorDecl *
Decl,
1213 HLSLAppliedSemanticAttr *Semantic,
1214 std::optional<unsigned> Index) {
1216 return emitSPIRVUserSemanticStore(B, Source,
Decl, Semantic, Index);
1219 return emitDXILUserSemanticStore(B, Source, Semantic, Index);
1221 llvm_unreachable(
"Unsupported target for user-semantic load.");
1227 std::optional<unsigned> Index) {
1229 std::string SemanticName = Semantic->getAttrName()->getName().upper();
1230 if (SemanticName ==
"SV_GROUPINDEX") {
1231 llvm::Function *GroupIndex =
1232 CGM.
getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
1233 return B.CreateCall(FunctionCallee(GroupIndex));
1236 if (SemanticName ==
"SV_DISPATCHTHREADID") {
1237 llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
1238 llvm::Function *ThreadIDIntrinsic =
1239 llvm::Intrinsic::isOverloaded(IntrinID)
1245 if (SemanticName ==
"SV_GROUPTHREADID") {
1246 llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
1247 llvm::Function *GroupThreadIDIntrinsic =
1248 llvm::Intrinsic::isOverloaded(IntrinID)
1254 if (SemanticName ==
"SV_GROUPID") {
1255 llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
1256 llvm::Function *GroupIDIntrinsic =
1257 llvm::Intrinsic::isOverloaded(IntrinID)
1263 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
1264 assert(ShaderAttr &&
"Entry point has no shader attribute");
1265 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
1267 if (SemanticName ==
"SV_POSITION") {
1268 if (ST == Triple::EnvironmentType::Pixel) {
1271 Semantic->getAttrName()->getName(),
1274 return emitDXILUserSemanticLoad(B,
Type, Semantic, Index);
1277 if (ST == Triple::EnvironmentType::Vertex) {
1278 return emitUserSemanticLoad(B,
Type,
Decl, Semantic, Index);
1282 if (SemanticName ==
"SV_VERTEXID") {
1283 if (ST == Triple::EnvironmentType::Vertex) {
1286 Semantic->getAttrName()->getName(),
1289 return emitDXILUserSemanticLoad(B,
Type, Semantic, Index);
1294 "Load hasn't been implemented yet for this system semantic. FIXME");
1298 llvm::Value *Source,
const Twine &Name,
1299 unsigned BuiltInID) {
1300 auto *GV =
new llvm::GlobalVariable(
1301 M, Source->getType(),
false,
1302 llvm::GlobalValue::ExternalLinkage,
1303 nullptr, Name,
nullptr,
1304 llvm::GlobalVariable::GeneralDynamicTLSModel,
1307 GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
1308 B.CreateStore(Source, GV);
1313 HLSLAppliedSemanticAttr *Semantic,
1314 std::optional<unsigned> Index) {
1316 std::string SemanticName = Semantic->getAttrName()->getName().upper();
1317 if (SemanticName ==
"SV_POSITION") {
1319 emitDXILUserSemanticStore(B, Source, Semantic, Index);
1325 Semantic->getAttrName()->getName(),
1331 if (SemanticName ==
"SV_TARGET") {
1332 emitUserSemanticStore(B, Source,
Decl, Semantic, Index);
1337 "Store hasn't been implemented yet for this system semantic. FIXME");
1344 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1345 if (Semantic->getAttrName()->getName().starts_with_insensitive(
"SV_"))
1347 return emitUserSemanticLoad(B,
Type,
Decl, Semantic, Index);
1351 IRBuilder<> &B,
const FunctionDecl *FD, llvm::Value *Source,
1353 std::optional<unsigned> Index = Semantic->getSemanticIndex();
1354 if (Semantic->getAttrName()->getName().starts_with_insensitive(
"SV_"))
1357 emitUserSemanticStore(B, Source,
Decl, Semantic, Index);
1360std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1373 for (
unsigned I = 0; I < ST->getNumElements(); ++I) {
1375 B, FD, ST->getElementType(I), *
FieldDecl, AttrBegin, AttrEnd);
1376 AttrBegin = NextAttr;
1382 return std::make_pair(
Aggregate, AttrBegin);
1387 IRBuilder<> &B,
const FunctionDecl *FD, llvm::Value *Source,
1398 RD =
Decl->getType()->getAsRecordDecl();
1404 for (
unsigned I = 0; I < ST->getNumElements(); ++I, ++
FieldDecl) {
1405 llvm::Value *Extract = B.CreateExtractValue(Source, I);
1413std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
1419 assert(AttrBegin != AttrEnd);
1420 if (
Type->isStructTy())
1423 HLSLAppliedSemanticAttr *
Attr = *AttrBegin;
1431 IRBuilder<> &B,
const FunctionDecl *FD, llvm::Value *Source,
1435 assert(AttrBegin != AttrEnd);
1436 if (Source->getType()->isStructTy())
1439 HLSLAppliedSemanticAttr *
Attr = *AttrBegin;
1446 llvm::Function *Fn) {
1448 llvm::LLVMContext &Ctx = M.getContext();
1449 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
false);
1451 Function::Create(EntryTy, Function::ExternalLinkage, FD->
getName(), &M);
1455 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
1456 Fn->getAttributes().getFnAttrs());
1457 EntryFn->setAttributes(NewAttrs);
1461 Fn->setLinkage(GlobalValue::InternalLinkage);
1463 BasicBlock *BB = BasicBlock::Create(Ctx,
"entry", EntryFn);
1469 assert(EntryFn->isConvergent());
1471 B.CreateIntrinsic(llvm::Intrinsic::experimental_convergence_entry, {});
1472 llvm::Value *bundleArgs[] = {I};
1473 OB.emplace_back(
"convergencectrl", bundleArgs);
1478 unsigned SRetOffset = 0;
1479 for (
const auto &Param : Fn->args()) {
1480 if (Param.hasStructRetAttr()) {
1482 llvm::Type *VarType = Param.getParamStructRetType();
1487 OutputSemantic.push_back(std::make_pair(Var, VarType));
1488 Args.push_back(Var);
1493 llvm::Value *SemanticValue =
nullptr;
1495 if ([[maybe_unused]] HLSLParamModifierAttr *MA =
1496 PD->
getAttr<HLSLParamModifierAttr>()) {
1497 llvm_unreachable(
"Not handled yet");
1499 llvm::Type *ParamType =
nullptr;
1500 if (Param.hasByValAttr())
1501 ParamType = Param.getParamByValType();
1505 ParamType = Param.getType();
1511 SemanticValue =
Result.first;
1519 B.CreateStore(SemanticValue, Var);
1520 SemanticValue = Var;
1524 assert(SemanticValue);
1525 Args.push_back(SemanticValue);
1528 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
1529 CI->setCallingConv(Fn->getCallingConv());
1531 if (Fn->getReturnType() != CGM.
VoidTy)
1533 OutputSemantic.push_back(std::make_pair(CI,
nullptr));
1535 for (
auto &SourcePair : OutputSemantic) {
1536 llvm::Value *Source = SourcePair.first;
1537 llvm::Type *ElementType = SourcePair.second;
1538 AllocaInst *AI = dyn_cast<AllocaInst>(Source);
1539 llvm::Value *SourceValue = AI ? B.CreateLoad(ElementType, Source) : Source;
1550 if (
const auto *RSAttr = dyn_cast<RootSignatureAttr>(
Attr)) {
1551 auto *RSDecl = RSAttr->getSignatureDecl();
1552 addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
1561 M.getNamedGlobal(CtorOrDtor ?
"llvm.global_ctors" :
"llvm.global_dtors");
1564 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
1571 for (
const auto &Ctor : CA->operands()) {
1577 "HLSL doesn't support setting priority for global ctors.");
1579 "HLSL doesn't support COMDat for global ctors.");
1594 for (
auto &F : M.functions()) {
1595 if (!F.hasFnAttribute(
"hlsl.shader"))
1598 Instruction *IP = &*F.getEntryBlock().begin();
1601 llvm::Value *bundleArgs[] = {
Token};
1602 OB.emplace_back(
"convergencectrl", bundleArgs);
1603 IP =
Token->getNextNode();
1606 for (
auto *Fn : CtorFns) {
1607 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1608 CI->setCallingConv(Fn->getCallingConv());
1612 B.SetInsertPoint(F.back().getTerminator());
1613 for (
auto *Fn : DtorFns) {
1614 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
1615 CI->setCallingConv(Fn->getCallingConv());
1621 Triple T(M.getTargetTriple());
1622 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
1623 if (
auto *GV = M.getNamedGlobal(
"llvm.global_ctors"))
1624 GV->eraseFromParent();
1625 if (
auto *GV = M.getNamedGlobal(
"llvm.global_dtors"))
1626 GV->eraseFromParent();
1631 Intrinsic::ID IntrID,
1635 llvm::Function *InitResFunc =
1636 llvm::Function::Create(llvm::FunctionType::get(CGM.
VoidTy,
false),
1637 llvm::GlobalValue::InternalLinkage,
1638 "_init_buffer_" + GV->getName(), CGM.
getModule());
1639 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1641 llvm::BasicBlock *EntryBB =
1642 llvm::BasicBlock::Create(Ctx,
"entry", InitResFunc);
1644 const DataLayout &DL = CGM.
getModule().getDataLayout();
1645 Builder.SetInsertPoint(EntryBB);
1648 llvm::Type *HandleTy = GV->getValueType();
1649 assert(HandleTy->isTargetExtTy() &&
"unexpected type of the buffer global");
1651 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
1652 HandleTy, IntrID, Args,
nullptr,
1653 Twine(GV->getName()).concat(
"_h"));
1655 Builder.CreateAlignedStore(CreateHandle, GV, GV->getPointerAlignment(DL));
1656 Builder.CreateRetVoid();
1661void CGHLSLRuntime::initializeBufferFromBinding(
const HLSLBufferDecl *BufDecl,
1662 llvm::GlobalVariable *GV) {
1663 ResourceBindingAttrs Binding(BufDecl);
1665 "cbuffer/tbuffer should always have resource binding attribute");
1667 auto *Index = llvm::ConstantInt::get(CGM.
IntTy, 0);
1668 auto *RangeSize = llvm::ConstantInt::get(CGM.
IntTy, 1);
1669 auto *Space = llvm::ConstantInt::get(CGM.
IntTy, Binding.
getSpace());
1670 Value *Name = buildNameForResource(BufDecl->
getName(), CGM);
1674 llvm::Intrinsic::ID IntrinsicID =
1676 auto *RegSlot = llvm::ConstantInt::get(CGM.
IntTy, Binding.
getSlot());
1677 SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
1681 llvm::Intrinsic::ID IntrinsicID =
1682 CGM.
getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
1685 SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
1691 llvm::GlobalVariable *GV) {
1692 if (
auto Attr = VD->
getAttr<HLSLVkExtBuiltinInputAttr>())
1694 if (
auto Attr = VD->
getAttr<HLSLVkExtBuiltinOutputAttr>())
1703 for (
auto I = BB.begin(); I != E; ++I) {
1704 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
1705 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
1709 llvm_unreachable(
"Convergence token should have been emitted.");
1746 for (
auto *OVE : Visitor.
OVEs) {
1749 if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
1751 OpaqueValueMappingData::bind(CGF, OVE, LV);
1754 OpaqueValueMappingData::bind(CGF, OVE, RV);
1763 "expected resource array subscript expression");
1768 const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(
1772 return std::nullopt;
1778 "expected array of resource classes");
1784 Value *Index =
nullptr;
1786 while (ASE !=
nullptr) {
1788 if (
const auto *ArrayTy =
1790 Value *Multiplier = llvm::ConstantInt::get(
1792 SubIndex = CGF.
Builder.CreateMul(SubIndex, Multiplier);
1794 Index = Index ? CGF.
Builder.CreateAdd(Index, SubIndex) : SubIndex;
1802 "resource array must have a binding attribute");
1823 llvm::Value *Range = llvm::ConstantInt::getSigned(
1824 CGM.
IntTy, getTotalArraySize(AST, ResArrayTy));
1828 if (ResultTy == ResourceTy) {
1830 CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
1832 ArrayDecl->
getName(), Binding, Args);
1834 if (!CreateMethod) {
1839 "create method lookup should always succeed for built-in resource "
1841 return std::nullopt;
1844 callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
1851 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
1853 ArrayDecl->
getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)});
1855 return std::nullopt;
1861bool CGHLSLRuntime::initializeGlobalResourceArray(
CodeGenFunction &CGF,
1867 "expected global non-static resource array");
1873 "resource array must have a binding attribute");
1878 const auto *ResArrayTy =
1882 int Size = getTotalArraySize(AST, ResArrayTy);
1883 llvm::Value *
Zero = llvm::ConstantInt::get(CGM.
IntTy, 0);
1884 llvm::Value *Range = llvm::ConstantInt::get(CGM.
IntTy, Size);
1887 std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
1889 ArrayDecl->
getName(), Binding, {Zero});
1890 return EndIndex.has_value();
1899 "expected resource array");
1904 dyn_cast_or_null<VarDecl>(getArrayDecl(CGF.
CGM.
getContext(), E));
1909 return initializeGlobalResourceArray(CGF, ArrayDecl, DestSlot);
1916std::optional<LValue>
1920 "expected resource array declaration");
1924 return std::nullopt;
1928 if (initializeGlobalResourceArray(CGF, ArrayDecl, TmpArraySlot))
1931 return std::nullopt;
1939 "expected cbuffer matrix");
1950 HLSLBufferCopyEmitter(CGF, DestAlloca, SrcAddr).emitCopy(MatQualTy);
1956 llvm::function_ref<llvm::Value *(
bool Promote)> EmitIdxAfterBase) {
1960 llvm::Type *LayoutTy =
1962 uint64_t LayoutSizeInBits =
1963 CGM.
getDataLayout().getTypeSizeInBits(LayoutTy).getFixedValue();
1966 if (RowAlignedSize > ElementSize) {
1968 CGM, RowAlignedSize - ElementSize);
1969 assert(Padding &&
"No padding type for target?");
1970 LayoutTy = llvm::StructType::get(CGF.
getLLVMContext(), {LayoutTy, Padding},
1977 if (LayoutTy == OrigTy)
1978 return std::nullopt;
1987 llvm::Value *Idx = EmitIdxAfterBase(
true);
1988 Indices.push_back(Idx);
1989 Indices.push_back(llvm::ConstantInt::get(CGF.
Int32Ty, 0));
1995 assert(CE->
getCastKind() == CastKind::CK_ArrayToPointerDecay);
1999 LayoutTy = llvm::ArrayType::get(
2003 LayoutTy,
Addr.emitRawPointer(CGF), Indices,
"cbufferidx"));
2012 Indices,
"cbufferidx");
2017std::optional<LValue>
2022 "expected resource member expression");
2025 findAssociatedResourceDeclForStruct(CGF.
CGM.
getContext(), ME);
2027 return std::nullopt;
2033 GlobalVariable *ResGV =
2036 llvm::Type *Ty = ResGV->getValueType();
2049 "expected expression in HLSL constant address space");
2052 "direct accesses to resource types should be handled separately");
2064 return HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty);
2070 const VarDecl *VD = findStructResourceParentDeclAndBuildName(E, NameBuilder);
2071 AssociatedResourcesList AssociatedResources(VD, NameBuilder.
getName());
2075 const VarDecl *ResDecl = AssociatedResources.getNextResource();
2076 assert(ResDecl &&
"associated resource declaration not found");
2079 [[maybe_unused]] llvm::Type *DestType =
2080 ResSlot.getAddress().getElementType();
2081 [[maybe_unused]] llvm::Type *SrcConvertedType =
2083 assert(DestType == SrcConvertedType &&
"resource slot type mismatch");
2086 copyGlobalResource(CGF, ResDecl, ResSlot);
2088 initializeGlobalResourceArray(CGF, ResDecl, ResSlot);
2092 HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(Ty, EmitResFn);
2093 assert(AssociatedResources.getNextResource() ==
nullptr &&
2094 "expected all associated resources to be processed");
2103 assert(Field &&
"Unexpected access into HLSL buffer");
2120 assert(FieldIdx < LayoutTy->getNumElements() &&
2121 "Layout struct is smaller than member struct");
2122 unsigned Skipped = 0;
2123 for (
unsigned I = 0; I <= FieldIdx;) {
2124 llvm::Type *ElementTy = LayoutTy->getElementType(I + Skipped);
2130 FieldIdx += Skipped;
2131 assert(FieldIdx < LayoutTy->getNumElements() &&
"Access out of bounds");
2135 QualType FieldType = Field->getType();
2141 ? CGF.
Builder.CreateStructuredGEP(
2142 LayoutTy,
Base.getPointer(CGF),
2143 llvm::ConstantInt::get(CGM.
IntTy, FieldIdx))
2145 FieldIdx, Field->getName());
Defines the clang::ASTContext interface.
static llvm::Value * createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, unsigned BuiltInID)
static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, unsigned BuiltIn)
static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M, llvm::Value *Source, unsigned Location, StringRef Name)
static void gatherFunctions(SmallVectorImpl< Function * > &Fns, llvm::Module &M, bool CtorOrDtor)
static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location)
static llvm::Value * createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, unsigned Location, StringRef Name)
static Value * buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty)
static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV, Intrinsic::ID IntrID, ArrayRef< llvm::Value * > Args)
static const clang::HLSLAttributedResourceType * createBufferHandleType(const HLSLBufferDecl *BufDecl)
static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M, llvm::Value *Source, const Twine &Name, unsigned BuiltInID)
Result
Implement __builtin_bit_cast and related operations.
llvm::MachO::Record Record
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 ...
SourceManager & getSourceManager()
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedIntTy
QualType getHLSLAttributedResourceType(QualType Wrapped, QualType Contained, const HLSLAttributedResourceType::Attributes &Attrs)
uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const
Return number of constant array elements.
CanQualType getCanonicalTagType(const TagDecl *TD) const
unsigned getTargetAddressSpace(LangAS AS) const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
QualType getElementType() const
Attr - This represents one attribute.
Represents a static or instance method of a struct/union/class.
Represents a C++ struct/union/class.
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...
CastKind getCastKind() const
CharUnits - This is an opaque type for sizes expressed in character units.
CharUnits alignmentOfArrayElement(CharUnits elementSize) const
Given that this is the alignment of the first element of an array, return the minimum alignment of an...
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
CharUnits getAlignment() const
Address getAddress() const
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.
llvm::StoreInst * CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile=false)
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Address CreateStructGEP(Address Addr, unsigned Index, const llvm::Twine &Name="")
Abstract information about a function or function prototype.
All available information about a concrete callee.
CGFunctionInfo - Class to encapsulate the information about a function definition.
static const uint32_t Unspecified
static bool compareOffsets(uint32_t LHS, uint32_t RHS)
Comparison function for offsets received from operator[] suitable for use in a stable_sort.
static CGHLSLOffsetInfo fromDecl(const HLSLBufferDecl &BufDecl)
Iterates over all declarations in the HLSL buffer and based on the packoffset or register(c#) annotat...
llvm::Instruction * getConvergenceToken(llvm::BasicBlock &BB)
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
specific_attr_iterator< HLSLAppliedSemanticAttr > handleSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrBegin, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrEnd)
llvm::StructType * getHLSLBufferLayoutType(const RecordType *LayoutStructTy)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var)
void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, std::optional< unsigned > Index)
std::pair< llvm::Value *, specific_attr_iterator< HLSLAppliedSemanticAttr > > handleStructSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > begin, specific_attr_iterator< HLSLAppliedSemanticAttr > end)
std::optional< LValue > emitResourceMemberExpr(CodeGenFunction &CGF, const MemberExpr *E)
specific_attr_iterator< HLSLAppliedSemanticAttr > handleStructSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrBegin, specific_attr_iterator< HLSLAppliedSemanticAttr > AttrEnd)
llvm::Value * handleScalarSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic)
void addHLSLBufferLayoutType(const RecordType *LayoutStructTy, llvm::StructType *LayoutTy)
std::optional< LValue > emitGlobalResourceArrayAsLValue(CodeGenFunction &CGF, const VarDecl *ArrayDecl)
void handleScalarSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic)
bool emitBufferCopy(CodeGenFunction &CGF, const Expr *E, const LValue &SrcLV, AggValueSlot &DestSlot)
std::pair< llvm::Value *, specific_attr_iterator< HLSLAppliedSemanticAttr > > handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, specific_attr_iterator< HLSLAppliedSemanticAttr > begin, specific_attr_iterator< HLSLAppliedSemanticAttr > end)
std::optional< LValue > emitBufferArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF, llvm::function_ref< llvm::Value *(bool Promote)> EmitIdxAfterBase)
std::optional< LValue > emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF)
void addRootSignature(const HLSLRootSignatureDecl *D)
LValue emitBufferMemberExpr(CodeGenFunction &CGF, const MemberExpr *E)
llvm::Type * convertHLSLSpecificType(const Type *T, const CGHLSLOffsetInfo &OffsetInfo)
RawAddress createBufferMatrixTempAddress(const LValue &LV, CodeGenFunction &CGF)
quad_read_across_diagonal resource_getpointer resource_handlefrombinding resource_nonuniformindex device_memory_barrier_with_group_sync resource_getdimensions_levels_xy GENERATE_HLSL_INTRINSIC_FUNCTION(CalculateLodUnclamped, resource_calculate_lod_unclamped) protected llvm::Value * emitSystemSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, std::optional< unsigned > Index)
void addBuffer(const HLSLBufferDecl *D)
void generateGlobalCtorDtorCalls()
bool emitGlobalResourceArray(CodeGenFunction &CGF, const Expr *E, AggValueSlot &DestSlot)
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E)
unsigned getLLVMFieldNo(const FieldDecl *FD) const
Return llvm::StructType element number that corresponds to the field FD.
CallArgList - Type for representing both the value and type of arguments in a call.
void add(RValue rvalue, QualType type)
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.
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,...
RawAddress CreateMemTempWithoutCast(QualType T, const Twine &Name="tmp")
CreateMemTemp - Create a temporary memory object of the given type, with appropriate alignmen without...
ASTContext & getContext() const
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.
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...
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK)
Same as EmitLValue but additionally we generate checking code to guard against undefined behavior.
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.
bool isOpaqueValueEmitted(const OpaqueValueExpr *E)
isOpaqueValueEmitted - Return true if the opaque value expression has already been emitted.
llvm::LLVMContext & getLLVMContext()
This class organizes the cross-function state that is used while generating LLVM code.
const PreprocessorOptions & getPreprocessorOpts() const
CGHLSLRuntime & getHLSLRuntime()
Return a reference to the configured HLSL runtime.
llvm::Module & getModule() const
llvm::Constant * GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty=nullptr, bool ForVTable=false, bool DontDefer=false, ForDefinition_t IsForDefinition=NotForDefinition)
Return the address of the given function.
void AddCXXGlobalInit(llvm::Function *F)
const LangOptions & getLangOpts() const
CodeGenTypes & getTypes()
const TargetInfo & getTarget() const
void EmitGlobal(GlobalDecl D)
Emit code for a single global function or var decl.
const llvm::DataLayout & getDataLayout() const
bool shouldEmitConvergenceTokens() const
TBAAAccessInfo getTBAAAccessInfo(QualType AccessType)
getTBAAAccessInfo - Get TBAA information that describes an access to an object of the given type.
ASTContext & getContext() const
llvm::Constant * GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty=nullptr, ForDefinition_t IsForDefinition=NotForDefinition)
Return the llvm::Constant for the address of the given global variable.
const TargetCodeGenInfo & getTargetCodeGenInfo()
const CodeGenOptions & getCodeGenOpts() const
llvm::LLVMContext & getLLVMContext()
llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys={})
void EmitTopLevelDecl(Decl *D)
Emit code for a single top level declaration.
ConstantAddress GetAddrOfConstantCString(const std::string &Str, StringRef GlobalName=".str")
Returns a pointer to a character array containing the literal and a terminating '\0' character.
llvm::Type * ConvertType(QualType T)
ConvertType - Convert type T into a llvm::Type.
const CGRecordLayout & getCGRecordLayout(const RecordDecl *)
getCGRecordLayout - Return record layout info for the given record decl.
llvm::Type * ConvertTypeForMem(QualType T)
ConvertTypeForMem - Convert type T into a llvm::Type.
const CGFunctionInfo & arrangeFreeFunctionCall(const CallArgList &Args, const FunctionType *Ty, bool ChainCall)
Figure out the rules for calling a function with the given formal type using the given arguments.
llvm::Constant * getPointer() const
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.
static LValue MakeAddr(Address Addr, QualType type, ASTContext &Context, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo)
const Qualifiers & getQuals() const
Address getAddress() const
RValue - This trivial value class is used to represent the result of an expression that is evaluated.
static RValue get(llvm::Value *V)
An abstract representation of an aligned address.
llvm::Value * getPointer() const
ReturnValueSlot - Contains the address where the return value of a function can be stored,...
virtual bool isHLSLPadding(llvm::Type *Ty) const
Return true if this is an HLSL padding type.
virtual llvm::Type * getHLSLPadding(CodeGenModule &CGM, CharUnits NumBytes) const
Return an LLVM type that corresponds to padding in HLSL types.
virtual llvm::Type * getHLSLType(CodeGenModule &CGM, const Type *T, const CGHLSLOffsetInfo &OffsetInfo) const
Return an LLVM type that corresponds to a HLSL type.
Represents the canonical version of C arrays with a specified constant size.
int64_t getSExtSize() const
Return the size sign-extended as a uint64_t.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
specific_attr_iterator< T > specific_attr_end() const
specific_attr_iterator< T > specific_attr_begin() const
Represents a ValueDecl that came out of a declarator.
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) 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.
Represents a member of a struct/union/class.
StringRef getName() const
The name of this FileEntry.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
Represents a prototype with parameter type info, e.g.
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
const CXXRecordDecl * getLayoutStruct() const
bool hasValidPackoffset() const
buffer_decl_range buffer_decls() const
This class represents temporary values used to represent inout and out arguments in HLSL.
ArrayRef< llvm::hlsl::rootsig::RootElement > getRootElements() const
llvm::dxbc::RootSignatureVersion getVersion() const
One of these records is kept for each identifier that is lexed.
Describes an C or C++ initializer list.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Represents a parameter to a function.
std::vector< std::pair< std::string, bool > > Macros
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
LangAS getAddressSpace() const
Return the address space of this type.
The collection of all-type qualifiers we support.
void addCVRQualifiers(unsigned mask)
Represents a struct/union/class.
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
field_iterator field_begin() const
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Encodes a location in the source.
One instance of this struct is kept for every file loaded or used.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM, SourceLocation Loc=SourceLocation()) const
Returns the memory buffer for the associated content.
OptionalFileEntryRef OrigEntry
Reference to the file entry representing this ContentCache.
Information about a FileID, basically just the logical file that it represents and include stack info...
const ContentCache & getContentCache() const
CharacteristicKind getFileCharacteristic() const
Return whether this is a system header or not.
This is a discriminated union of FileInfo and ExpansionInfo.
const FileInfo & getFile() const
TargetOptions & getTargetOpts() const
Retrieve the target options.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Token - This structure provides full information about a lexed token.
The base class of the type hierarchy.
bool isIncompleteArrayType() const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isConstantMatrixType() const
bool isHLSLIntangibleType() const
bool isHLSLResourceRecord() const
bool isStructureOrClassType() const
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
const T * getAs() const
Member-template getAs<specific type>'.
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
bool isRecordType() const
bool isHLSLResourceRecordArray() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
StorageClass getStorageClass() const
Returns the storage class as written in the source.
void pushName(llvm::StringRef N)
void pushArrayIndex(uint64_t Index)
llvm::StringRef getName() const
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.
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
bool hasCounterHandle(const CXXRecordDecl *RD)
StringRef getName(const HeaderType T)
@ Address
A pointer to a ValueDecl.
bool Load(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
std::vector< std::string > Macros
A list of macros of the form <definition>=<expansion> .
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
StorageClass
Storage classes.
@ Result
The result type of a method or function.
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
llvm::IntegerType * Int32Ty
llvm::IntegerType * IntTy
int
unsigned getImplicitOrderID() const
bool hasCounterImplicitOrderID() const
unsigned getSpace() const
unsigned getCounterImplicitOrderID() const