21#include "llvm/IR/GlobalVariable.h"
22#include "llvm/IR/LLVMContext.h"
23#include "llvm/IR/Metadata.h"
24#include "llvm/IR/Module.h"
25#include "llvm/IR/Value.h"
26#include "llvm/Support/Alignment.h"
28#include "llvm/Support/FormatVariadic.h"
31using namespace CodeGen;
37void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
41 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
42 Version.getSubminor() || !Version.getMinor()) {
47 uint64_t Minor = *Version.getMinor();
49 auto &Ctx = M.getContext();
50 IRBuilder<> B(M.getContext());
51 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
52 ConstantAsMetadata::get(B.getInt32(Minor))});
53 StringRef DXILValKey =
"dx.valver";
54 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
55 DXILValMD->addOperand(Val);
57void addDisableOptimizations(llvm::Module &M) {
58 StringRef Key =
"dx.disable_optimizations";
59 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
85 std::vector<llvm::Type *> EltTys;
87 GlobalVariable *GV =
Const.first;
88 Const.second = EltTys.size();
89 llvm::Type *Ty = GV->getValueType();
90 EltTys.emplace_back(Ty);
92 Buf.
LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
97 GlobalVariable *CBGV =
new GlobalVariable(
99 GlobalValue::LinkageTypes::ExternalLinkage,
nullptr,
100 llvm::formatv(
"{0}{1}", Buf.
Name, Buf.
IsCBuffer ?
".cb." :
".tb."),
101 GlobalValue::NotThreadLocal);
115 llvm_unreachable(
"Generic handling of HLSL types is not supported.");
118llvm::Triple::ArchType CGHLSLRuntime::getArch() {
122void CGHLSLRuntime::addConstant(
VarDecl *
D, Buffer &CB) {
131 GV->setExternallyInitialized(
true);
135 codegenoptions::DebugInfoKind::LimitedDebugInfo)
136 DI->EmitGlobalVariable(cast<GlobalVariable>(GV),
D);
141 bool HasUserOffset =
false;
143 unsigned LowerBound = HasUserOffset ? Offset :
UINT_MAX;
144 CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
147void CGHLSLRuntime::addBufferDecls(
const DeclContext *DC, Buffer &CB) {
149 if (
auto *ConstDecl = dyn_cast<VarDecl>(it)) {
150 addConstant(ConstDecl, CB);
151 }
else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
153 }
else if (isa<FunctionDecl>(it)) {
162 Buffers.emplace_back(
Buffer(
D));
163 addBufferDecls(
D, Buffers.back());
169 Triple
T(M.getTargetTriple());
170 if (
T.getArch() == Triple::ArchType::dxil)
171 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
175 addDisableOptimizations(M);
177 const DataLayout &DL = M.getDataLayout();
179 for (
auto &Buf : Buffers) {
180 layoutBuffer(Buf, DL);
181 GlobalVariable *GV = replaceBuffer(Buf);
182 M.insertGlobalVariable(GV);
183 llvm::hlsl::ResourceClass RC = Buf.
IsCBuffer
184 ? llvm::hlsl::ResourceClass::CBuffer
185 : llvm::hlsl::ResourceClass::SRV;
186 llvm::hlsl::ResourceKind RK = Buf.
IsCBuffer
187 ? llvm::hlsl::ResourceKind::CBuffer
188 : llvm::hlsl::ResourceKind::TBuffer;
189 addBufferResourceAnnotation(GV, RC, RK,
false,
190 llvm::hlsl::ElementType::Invalid, Buf.
Binding);
195 : Name(
D->
getName()), IsCBuffer(
D->isCBuffer()),
196 Binding(
D->getAttr<HLSLResourceBindingAttr>()) {}
198void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
199 llvm::hlsl::ResourceClass RC,
200 llvm::hlsl::ResourceKind RK,
202 llvm::hlsl::ElementType ET,
203 BufferResBinding &Binding) {
206 NamedMDNode *ResourceMD =
nullptr;
208 case llvm::hlsl::ResourceClass::UAV:
209 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.uavs");
211 case llvm::hlsl::ResourceClass::SRV:
212 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.srvs");
214 case llvm::hlsl::ResourceClass::CBuffer:
215 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.cbufs");
218 assert(
false &&
"Unsupported buffer type!");
221 assert(ResourceMD !=
nullptr &&
222 "ResourceMD must have been set by the switch above.");
224 llvm::hlsl::FrontendResource Res(
225 GV, RK, ET, IsROV, Binding.Reg.value_or(
UINT_MAX), Binding.Space);
226 ResourceMD->addOperand(Res.getMetadata());
229static llvm::hlsl::ElementType
231 using llvm::hlsl::ElementType;
236 assert(TST &&
"Resource types must be template specializations");
238 assert(!Args.empty() &&
"Resource has no element type");
242 QualType ElTy = Args[0].getAsType();
246 ElTy = VecTy->getElementType();
251 return ElementType::I16;
253 return ElementType::I32;
255 return ElementType::I64;
260 return ElementType::U16;
262 return ElementType::U32;
264 return ElementType::U64;
267 return ElementType::F16;
269 return ElementType::F32;
271 return ElementType::F64;
274 llvm_unreachable(
"Invalid element type for resource");
278 const Type *Ty =
D->getType()->getPointeeOrArrayElementType();
286 for (
auto *FD : RD->fields()) {
287 const auto *HLSLResAttr = FD->
getAttr<HLSLResourceAttr>();
289 dyn_cast<HLSLAttributedResourceType>(FD->getType().getTypePtr());
290 if (!HLSLResAttr || !AttrResType)
293 llvm::hlsl::ResourceClass RC = AttrResType->getAttrs().ResourceClass;
294 if (RC == llvm::hlsl::ResourceClass::UAV ||
295 RC == llvm::hlsl::ResourceClass::SRV)
304 bool IsROV = AttrResType->getAttrs().IsROV;
305 llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind();
308 BufferResBinding Binding(
D->
getAttr<HLSLResourceBindingAttr>());
309 addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
313CGHLSLRuntime::BufferResBinding::BufferResBinding(
314 HLSLResourceBindingAttr *Binding) {
316 llvm::APInt RegInt(64, 0);
317 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
318 Reg = RegInt.getLimitedValue();
319 llvm::APInt SpaceInt(64, 0);
320 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
321 Space = SpaceInt.getLimitedValue();
329 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
330 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
331 const StringRef ShaderAttrKindStr =
"hlsl.shader";
332 Fn->addFnAttr(ShaderAttrKindStr,
333 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
334 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
335 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
336 std::string NumThreadsStr =
337 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
338 NumThreadsAttr->getZ());
339 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
341 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->
getAttr<HLSLWaveSizeAttr>()) {
342 const StringRef WaveSizeKindStr =
"hlsl.wavesize";
343 std::string WaveSizeStr =
344 formatv(
"{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(),
345 WaveSizeAttr->getPreferred());
346 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
348 Fn->addFnAttr(llvm::Attribute::NoInline);
352 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
354 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
355 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
360 return B.CreateCall(F, {B.getInt32(0)});
366 assert(
D.
hasAttrs() &&
"Entry parameter missing annotation attribute!");
367 if (
D.
hasAttr<HLSLSV_GroupIndexAttr>()) {
368 llvm::Function *DxGroupIndex =
370 return B.CreateCall(FunctionCallee(DxGroupIndex));
372 if (
D.
hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
373 llvm::Function *ThreadIDIntrinsic =
377 if (
D.
hasAttr<HLSLSV_GroupThreadIDAttr>()) {
378 llvm::Function *GroupThreadIDIntrinsic =
382 if (
D.
hasAttr<HLSLSV_GroupIDAttr>()) {
383 llvm::Function *GroupIDIntrinsic =
CGM.
getIntrinsic(getGroupIdIntrinsic());
386 assert(
false &&
"Unhandled parameter attribute");
391 llvm::Function *Fn) {
393 llvm::LLVMContext &Ctx = M.getContext();
394 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
false);
396 Function::Create(EntryTy, Function::ExternalLinkage, FD->
getName(), &M);
400 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
401 Fn->getAttributes().getFnAttrs());
402 EntryFn->setAttributes(NewAttrs);
406 Fn->setLinkage(GlobalValue::InternalLinkage);
408 BasicBlock *BB = BasicBlock::Create(Ctx,
"entry", EntryFn);
414 assert(EntryFn->isConvergent());
415 llvm::Value *I = B.CreateIntrinsic(
416 llvm::Intrinsic::experimental_convergence_entry, {}, {});
417 llvm::Value *bundleArgs[] = {I};
418 OB.emplace_back(
"convergencectrl", bundleArgs);
423 unsigned SRetOffset = 0;
424 for (
const auto &Param : Fn->args()) {
425 if (Param.hasStructRetAttr()) {
429 Args.emplace_back(PoisonValue::get(Param.getType()));
436 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
437 CI->setCallingConv(Fn->getCallingConv());
444 llvm::Function *Fn) {
446 const StringRef ExportAttrKindStr =
"hlsl.export";
447 Fn->addFnAttr(ExportAttrKindStr);
454 M.getNamedGlobal(CtorOrDtor ?
"llvm.global_ctors" :
"llvm.global_dtors");
457 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
465 for (
const auto &Ctor : CA->operands()) {
466 if (isa<ConstantAggregateZero>(Ctor))
468 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
470 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
471 "HLSL doesn't support setting priority for global ctors.");
472 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
473 "HLSL doesn't support COMDat for global ctors.");
474 Fns.push_back(cast<Function>(CS->getOperand(1)));
488 for (
auto &F : M.functions()) {
489 if (!F.hasFnAttribute(
"hlsl.shader"))
492 Instruction *IP = &*F.getEntryBlock().begin();
495 llvm::Value *bundleArgs[] = {
Token};
496 OB.emplace_back(
"convergencectrl", bundleArgs);
497 IP =
Token->getNextNode();
500 for (
auto *Fn : CtorFns) {
501 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
502 CI->setCallingConv(Fn->getCallingConv());
506 B.SetInsertPoint(F.back().getTerminator());
507 for (
auto *Fn : DtorFns) {
508 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB);
509 CI->setCallingConv(Fn->getCallingConv());
515 Triple
T(M.getTargetTriple());
516 if (
T.getEnvironment() != Triple::EnvironmentType::Library) {
517 if (
auto *GV = M.getNamedGlobal(
"llvm.global_ctors"))
518 GV->eraseFromParent();
519 if (
auto *GV = M.getNamedGlobal(
"llvm.global_dtors"))
520 GV->eraseFromParent();
530 llvm::GlobalVariable *GV,
unsigned Slot,
533 llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);
535 llvm::Function *InitResFunc = llvm::Function::Create(
536 llvm::FunctionType::get(
CGM.
VoidTy,
false),
537 llvm::GlobalValue::InternalLinkage,
539 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
541 llvm::BasicBlock *EntryBB =
542 llvm::BasicBlock::Create(Ctx,
"entry", InitResFunc);
545 Builder.SetInsertPoint(EntryBB);
554 assert(AttrResType !=
nullptr &&
555 "Resource class must have a handle of HLSLAttributedResourceType");
557 llvm::Type *TargetTy =
559 assert(TargetTy !=
nullptr &&
560 "Failed to convert resource handle to target type");
562 llvm::Value *Args[] = {
563 llvm::ConstantInt::get(
CGM.
IntTy, Space),
564 llvm::ConstantInt::get(
CGM.
IntTy, Slot),
566 llvm::ConstantInt::get(
CGM.
IntTy, 1),
567 llvm::ConstantInt::get(
CGM.
IntTy, 0),
569 llvm::ConstantInt::get(Int1Ty,
false)
571 llvm::Value *CreateHandle = Builder.CreateIntrinsic(
574 Twine(VD->
getName()).concat(
"_h"));
576 llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
577 Builder.CreateAlignedStore(CreateHandle, HandleRef,
578 HandleRef->getPointerAlignment(DL));
579 Builder.CreateRetVoid();
585 llvm::GlobalVariable *GV) {
589 const HLSLResourceBindingAttr *RBA = VD->
getAttr<HLSLResourceBindingAttr>();
602 RBA->getSpaceNumber());
610 for (
auto I = BB.begin(); I !=
E; ++I) {
611 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I);
612 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) {
616 llvm_unreachable(
"Convergence token should have been emitted.");
static llvm::hlsl::ElementType calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy)
static void gatherFunctions(SmallVectorImpl< Function * > &Fns, llvm::Module &M, bool CtorOrDtor)
static Value * buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty)
static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD, llvm::GlobalVariable *GV, unsigned Slot, unsigned Space)
static bool isResourceRecordType(const clang::Type *Ty)
static std::string getName(const CallEvent &Call)
Defines the clang::TargetOptions class.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
This class gathers all debug information during compilation and is responsible for emitting to llvm g...
llvm::Instruction * getConvergenceToken(llvm::BasicBlock &BB)
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var)
llvm::Type * convertHLSLSpecificType(const Type *T)
llvm::Value * emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D, llvm::Type *Ty)
void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV)
void addBuffer(const HLSLBufferDecl *D)
void generateGlobalCtorDtorCalls()
This class organizes the cross-function state that is used while generating LLVM code.
CGHLSLRuntime & getHLSLRuntime()
Return a reference to the configured HLSL runtime.
llvm::Module & getModule() const
CGDebugInfo * getModuleDebugInfo()
void AddCXXGlobalInit(llvm::Function *F)
const TargetInfo & getTarget() const
void EmitGlobal(GlobalDecl D)
Emit code for a single global function or var decl.
bool shouldEmitConvergenceTokens() 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()
llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys={})
void EmitTopLevelDecl(Decl *D)
Emit code for a single top level declaration.
virtual llvm::Type * getHLSLType(CodeGenModule &CGM, const Type *T) const
Return an LLVM type that corresponds to a HLSL type.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Decl - This represents one declaration (or definition), e.g.
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
static const HLSLAttributedResourceType * findHandleTypeOnResource(const Type *RT)
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Represents a parameter to a function.
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
TargetOptions & getTargetOpts() const
Retrieve the target options.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Represents a type template specialization; the template must be a class template, a type alias templa...
Token - This structure provides full information about a lexed token.
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
bool isHLSLSpecificType() const
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
const T * getAs() const
Member-template getAs<specific type>'.
Represents a variable declaration or definition.
Represents a GCC generic vector type.
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.
std::vector< std::pair< llvm::GlobalVariable *, unsigned > > Constants
llvm::StructType * LayoutStruct
Buffer(const HLSLBufferDecl *D)
llvm::IntegerType * IntTy
int