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");
277 const Type *Ty =
D->getType()->getPointeeOrArrayElementType();
283 const auto *HLSLResAttr = RD->
getAttr<HLSLResourceAttr>();
284 const auto *HLSLResClassAttr = RD->getAttr<HLSLResourceClassAttr>();
285 if (!HLSLResAttr || !HLSLResClassAttr)
288 llvm::hlsl::ResourceClass RC = HLSLResClassAttr->getResourceClass();
289 llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind();
290 bool IsROV = HLSLResAttr->getIsROV();
294 addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
298 HLSLResourceBindingAttr *Binding) {
300 llvm::APInt RegInt(64, 0);
301 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
302 Reg = RegInt.getLimitedValue();
303 llvm::APInt SpaceInt(64, 0);
304 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
305 Space = SpaceInt.getLimitedValue();
313 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
314 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
315 const StringRef ShaderAttrKindStr =
"hlsl.shader";
316 Fn->addFnAttr(ShaderAttrKindStr,
317 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
318 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
319 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
320 std::string NumThreadsStr =
321 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
322 NumThreadsAttr->getZ());
323 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
328 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
330 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
331 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
336 return B.CreateCall(F, {B.getInt32(0)});
342 assert(
D.
hasAttrs() &&
"Entry parameter missing annotation attribute!");
343 if (
D.
hasAttr<HLSLSV_GroupIndexAttr>()) {
344 llvm::Function *DxGroupIndex =
346 return B.CreateCall(FunctionCallee(DxGroupIndex));
348 if (
D.
hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
349 llvm::Function *ThreadIDIntrinsic =
353 assert(
false &&
"Unhandled parameter attribute");
358 llvm::Function *Fn) {
360 llvm::LLVMContext &Ctx = M.getContext();
361 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
false);
363 Function::Create(EntryTy, Function::ExternalLinkage, FD->
getName(), &M);
367 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
368 Fn->getAttributes().getFnAttrs());
369 EntryFn->setAttributes(NewAttrs);
373 Fn->setLinkage(GlobalValue::InternalLinkage);
375 BasicBlock *BB = BasicBlock::Create(Ctx,
"entry", EntryFn);
380 unsigned SRetOffset = 0;
381 for (
const auto &Param : Fn->args()) {
382 if (Param.hasStructRetAttr()) {
386 Args.emplace_back(PoisonValue::get(Param.getType()));
393 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
403 M.getNamedGlobal(CtorOrDtor ?
"llvm.global_ctors" :
"llvm.global_dtors");
406 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
414 for (
const auto &Ctor : CA->operands()) {
415 if (isa<ConstantAggregateZero>(Ctor))
417 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
419 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
420 "HLSL doesn't support setting priority for global ctors.");
421 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
422 "HLSL doesn't support COMDat for global ctors.");
423 Fns.push_back(cast<Function>(CS->getOperand(1)));
437 for (
auto &F : M.functions()) {
438 if (!F.hasFnAttribute(
"hlsl.shader"))
440 IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
441 for (
auto *Fn : CtorFns)
442 B.CreateCall(FunctionCallee(Fn));
445 B.SetInsertPoint(F.back().getTerminator());
446 for (
auto *Fn : DtorFns)
447 B.CreateCall(FunctionCallee(Fn));
452 Triple
T(M.getTargetTriple());
453 if (
T.getEnvironment() != Triple::EnvironmentType::Library) {
454 if (
auto *GV = M.getNamedGlobal(
"llvm.global_ctors"))
455 GV->eraseFromParent();
456 if (
auto *GV = M.getNamedGlobal(
"llvm.global_dtors"))
457 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.
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...
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.
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)