20#include "llvm/IR/Metadata.h"
21#include "llvm/IR/Module.h"
22#include "llvm/Support/FormatVariadic.h"
25using namespace CodeGen;
31void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
35 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
36 Version.getSubminor() || !Version.getMinor()) {
41 uint64_t Minor = *Version.getMinor();
43 auto &Ctx = M.getContext();
44 IRBuilder<> B(M.getContext());
45 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
46 ConstantAsMetadata::get(B.getInt32(Minor))});
47 StringRef DXILValKey =
"dx.valver";
48 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
49 DXILValMD->addOperand(Val);
51void addDisableOptimizations(llvm::Module &M) {
52 StringRef Key =
"dx.disable_optimizations";
53 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
79 std::vector<llvm::Type *> EltTys;
81 GlobalVariable *GV =
Const.first;
82 Const.second = EltTys.size();
83 llvm::Type *Ty = GV->getValueType();
84 EltTys.emplace_back(Ty);
86 Buf.
LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
91 GlobalVariable *CBGV =
new GlobalVariable(
93 GlobalValue::LinkageTypes::ExternalLinkage,
nullptr,
94 llvm::formatv(
"{0}{1}", Buf.
Name, Buf.
IsCBuffer ?
".cb." :
".tb."),
95 GlobalValue::NotThreadLocal);
97 IRBuilder<> B(CBGV->getContext());
98 Value *ZeroIdx = B.getInt32(0);
100 for (
auto &[GV, Offset] : Buf.
Constants) {
102 B.CreateGEP(Buf.
LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
104 assert(Buf.
LayoutStruct->getElementType(Offset) == GV->getValueType() &&
105 "constant type mismatch");
108 GV->replaceAllUsesWith(GEP);
110 GV->removeDeadConstantUsers();
111 GV->eraseFromParent();
118llvm::Triple::ArchType CGHLSLRuntime::getArch() {
122void CGHLSLRuntime::addConstant(
VarDecl *D, Buffer &CB) {
134 codegenoptions::DebugInfoKind::LimitedDebugInfo)
135 DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
140 bool HasUserOffset =
false;
142 unsigned LowerBound = HasUserOffset ? Offset :
UINT_MAX;
143 CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
146void CGHLSLRuntime::addBufferDecls(
const DeclContext *DC, Buffer &CB) {
148 if (
auto *ConstDecl = dyn_cast<VarDecl>(it)) {
149 addConstant(ConstDecl, CB);
150 }
else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
152 }
else if (isa<FunctionDecl>(it)) {
161 Buffers.emplace_back(
Buffer(D));
162 addBufferDecls(D, Buffers.back());
168 Triple
T(M.getTargetTriple());
169 if (
T.getArch() == Triple::ArchType::dxil)
170 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
174 addDisableOptimizations(M);
176 const DataLayout &DL = M.getDataLayout();
178 for (
auto &Buf : Buffers) {
179 layoutBuffer(Buf, DL);
180 GlobalVariable *GV = replaceBuffer(Buf);
181 M.insertGlobalVariable(GV);
182 llvm::hlsl::ResourceClass RC = Buf.
IsCBuffer
183 ? llvm::hlsl::ResourceClass::CBuffer
184 : llvm::hlsl::ResourceClass::SRV;
185 llvm::hlsl::ResourceKind RK = Buf.
IsCBuffer
186 ? llvm::hlsl::ResourceKind::CBuffer
187 : llvm::hlsl::ResourceKind::TBuffer;
188 addBufferResourceAnnotation(GV, RC, RK,
false,
189 llvm::hlsl::ElementType::Invalid, Buf.
Binding);
194 : Name(D->
getName()), IsCBuffer(D->isCBuffer()),
195 Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
197void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
198 llvm::hlsl::ResourceClass RC,
199 llvm::hlsl::ResourceKind RK,
201 llvm::hlsl::ElementType ET,
205 NamedMDNode *ResourceMD =
nullptr;
207 case llvm::hlsl::ResourceClass::UAV:
208 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.uavs");
210 case llvm::hlsl::ResourceClass::SRV:
211 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.srvs");
213 case llvm::hlsl::ResourceClass::CBuffer:
214 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.cbufs");
217 assert(
false &&
"Unsupported buffer type!");
220 assert(ResourceMD !=
nullptr &&
221 "ResourceMD must have been set by the switch above.");
223 llvm::hlsl::FrontendResource Res(
225 ResourceMD->addOperand(Res.getMetadata());
228static llvm::hlsl::ElementType
230 using llvm::hlsl::ElementType;
235 assert(TST &&
"Resource types must be template specializations");
237 assert(!Args.empty() &&
"Resource has no element type");
241 QualType ElTy = Args[0].getAsType();
245 ElTy = VecTy->getElementType();
250 return ElementType::I16;
252 return ElementType::I32;
254 return ElementType::I64;
259 return ElementType::U16;
261 return ElementType::U32;
263 return ElementType::U64;
266 return ElementType::F16;
268 return ElementType::F32;
270 return ElementType::F64;
273 llvm_unreachable(
"Invalid element type for resource");
283 const auto *
Attr = RD->getAttr<HLSLResourceAttr>();
287 llvm::hlsl::ResourceClass RC =
Attr->getResourceClass();
288 llvm::hlsl::ResourceKind RK =
Attr->getResourceKind();
289 bool IsROV =
Attr->getIsROV();
293 addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
297 HLSLResourceBindingAttr *Binding) {
299 llvm::APInt RegInt(64, 0);
300 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
301 Reg = RegInt.getLimitedValue();
302 llvm::APInt SpaceInt(64, 0);
303 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
304 Space = SpaceInt.getLimitedValue();
312 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
313 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
314 const StringRef ShaderAttrKindStr =
"hlsl.shader";
315 Fn->addFnAttr(ShaderAttrKindStr,
316 ShaderAttr->ConvertShaderTypeToStr(ShaderAttr->getType()));
317 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
318 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
319 std::string NumThreadsStr =
320 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
321 NumThreadsAttr->getZ());
322 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
327 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
329 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
330 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
335 return B.CreateCall(F, {B.getInt32(0)});
341 assert(D.
hasAttrs() &&
"Entry parameter missing annotation attribute!");
342 if (D.
hasAttr<HLSLSV_GroupIndexAttr>()) {
343 llvm::Function *DxGroupIndex =
345 return B.CreateCall(FunctionCallee(DxGroupIndex));
347 if (D.
hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
348 llvm::Function *ThreadIDIntrinsic =
352 assert(
false &&
"Unhandled parameter attribute");
357 llvm::Function *Fn) {
359 llvm::LLVMContext &Ctx = M.getContext();
360 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
false);
362 Function::Create(EntryTy, Function::ExternalLinkage, FD->
getName(), &M);
366 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
367 Fn->getAttributes().getFnAttrs());
368 EntryFn->setAttributes(NewAttrs);
372 Fn->setLinkage(GlobalValue::InternalLinkage);
374 BasicBlock *BB = BasicBlock::Create(Ctx,
"entry", EntryFn);
379 unsigned SRetOffset = 0;
380 for (
const auto &Param : Fn->args()) {
381 if (Param.hasStructRetAttr()) {
385 Args.emplace_back(PoisonValue::get(Param.getType()));
392 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
402 M.getNamedGlobal(CtorOrDtor ?
"llvm.global_ctors" :
"llvm.global_dtors");
405 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
413 for (
const auto &Ctor : CA->operands()) {
414 if (isa<ConstantAggregateZero>(Ctor))
416 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
418 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
419 "HLSL doesn't support setting priority for global ctors.");
420 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
421 "HLSL doesn't support COMDat for global ctors.");
422 Fns.push_back(cast<Function>(CS->getOperand(1)));
436 for (
auto &F : M.functions()) {
437 if (!F.hasFnAttribute(
"hlsl.shader"))
439 IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
440 for (
auto *Fn : CtorFns)
441 B.CreateCall(FunctionCallee(Fn));
444 B.SetInsertPoint(F.back().getTerminator());
445 for (
auto *Fn : DtorFns)
446 B.CreateCall(FunctionCallee(Fn));
451 Triple
T(M.getTargetTriple());
452 if (
T.getEnvironment() != Triple::EnvironmentType::Library) {
453 if (
auto *GV = M.getNamedGlobal(
"llvm.global_ctors"))
454 GV->eraseFromParent();
455 if (
auto *GV = M.getNamedGlobal(
"llvm.global_dtors"))
456 GV->eraseFromParent();
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 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.
Attr - This represents one attribute.
This class gathers all debug information during compilation and is responsible for emitting to llvm g...
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
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()
llvm::Module & getModule() const
CGDebugInfo * getModuleDebugInfo()
const TargetInfo & getTarget() const
void EmitGlobal(GlobalDecl D)
Emit code for a single global function or var decl.
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 CodeGenOptions & getCodeGenOpts() const
llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys=std::nullopt)
void EmitTopLevelDecl(Decl *D)
Emit code for a single top level declaration.
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.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
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.
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...
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...
const Type * getPointeeOrArrayElementType() const
If this is a pointer type, return the pointee type.
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 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.
StorageClass getStorageClass() const
Returns the storage class as written in the source.
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::optional< unsigned > Reg
BufferResBinding(HLSLResourceBindingAttr *Attr)
std::vector< std::pair< llvm::GlobalVariable *, unsigned > > Constants
llvm::StructType * LayoutStruct
Buffer(const HLSLBufferDecl *D)