20#include "llvm/IR/IntrinsicsDirectX.h"
21#include "llvm/IR/IntrinsicsSPIRV.h"
22#include "llvm/IR/Metadata.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Support/FormatVariadic.h"
27using namespace CodeGen;
33void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
37 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
38 Version.getSubminor() || !Version.getMinor()) {
43 uint64_t Minor = *Version.getMinor();
45 auto &Ctx = M.getContext();
46 IRBuilder<> B(M.getContext());
47 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
48 ConstantAsMetadata::get(B.getInt32(Minor))});
49 StringRef DXILValKey =
"dx.valver";
50 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
51 DXILValMD->addOperand(Val);
53void addDisableOptimizations(llvm::Module &M) {
54 StringRef Key =
"dx.disable_optimizations";
55 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
81 std::vector<llvm::Type *> EltTys;
83 GlobalVariable *GV =
Const.first;
84 Const.second = EltTys.size();
85 llvm::Type *Ty = GV->getValueType();
86 EltTys.emplace_back(Ty);
88 Buf.
LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
93 GlobalVariable *CBGV =
new GlobalVariable(
95 GlobalValue::LinkageTypes::ExternalLinkage,
nullptr,
96 llvm::formatv(
"{0}{1}", Buf.
Name, Buf.
IsCBuffer ?
".cb." :
".tb."),
97 GlobalValue::NotThreadLocal);
99 IRBuilder<> B(CBGV->getContext());
100 Value *ZeroIdx = B.getInt32(0);
102 for (
auto &[GV, Offset] : Buf.
Constants) {
104 B.CreateGEP(Buf.
LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
106 assert(Buf.
LayoutStruct->getElementType(Offset) == GV->getValueType() &&
107 "constant type mismatch");
110 GV->replaceAllUsesWith(GEP);
112 GV->removeDeadConstantUsers();
113 GV->eraseFromParent();
120void CGHLSLRuntime::addConstant(
VarDecl *D, Buffer &CB) {
132 codegenoptions::DebugInfoKind::LimitedDebugInfo)
133 DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
138 bool HasUserOffset =
false;
140 unsigned LowerBound = HasUserOffset ? Offset :
UINT_MAX;
141 CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
144void CGHLSLRuntime::addBufferDecls(
const DeclContext *DC, Buffer &CB) {
146 if (
auto *ConstDecl = dyn_cast<VarDecl>(it)) {
147 addConstant(ConstDecl, CB);
148 }
else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
150 }
else if (isa<FunctionDecl>(it)) {
159 Buffers.emplace_back(
Buffer(D));
160 addBufferDecls(D, Buffers.back());
166 Triple T(M.getTargetTriple());
167 if (T.getArch() == Triple::ArchType::dxil)
168 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
172 addDisableOptimizations(M);
174 const DataLayout &DL = M.getDataLayout();
176 for (
auto &Buf : Buffers) {
177 layoutBuffer(Buf, DL);
178 GlobalVariable *GV = replaceBuffer(Buf);
179 M.insertGlobalVariable(GV);
180 llvm::hlsl::ResourceClass RC = Buf.
IsCBuffer
181 ? llvm::hlsl::ResourceClass::CBuffer
182 : llvm::hlsl::ResourceClass::SRV;
183 llvm::hlsl::ResourceKind RK = Buf.
IsCBuffer
184 ? llvm::hlsl::ResourceKind::CBuffer
185 : llvm::hlsl::ResourceKind::TBuffer;
186 addBufferResourceAnnotation(GV, RC, RK,
false,
187 llvm::hlsl::ElementType::Invalid, Buf.
Binding);
192 : Name(D->
getName()), IsCBuffer(D->isCBuffer()),
193 Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
195void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
196 llvm::hlsl::ResourceClass RC,
197 llvm::hlsl::ResourceKind RK,
199 llvm::hlsl::ElementType ET,
203 NamedMDNode *ResourceMD =
nullptr;
205 case llvm::hlsl::ResourceClass::UAV:
206 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.uavs");
208 case llvm::hlsl::ResourceClass::SRV:
209 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.srvs");
211 case llvm::hlsl::ResourceClass::CBuffer:
212 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.cbufs");
215 assert(
false &&
"Unsupported buffer type!");
218 assert(ResourceMD !=
nullptr &&
219 "ResourceMD must have been set by the switch above.");
221 llvm::hlsl::FrontendResource Res(
223 ResourceMD->addOperand(Res.getMetadata());
226static llvm::hlsl::ElementType
228 using llvm::hlsl::ElementType;
233 assert(TST &&
"Resource types must be template specializations");
235 assert(!Args.empty() &&
"Resource has no element type");
239 QualType ElTy = Args[0].getAsType();
243 ElTy = VecTy->getElementType();
248 return ElementType::I16;
250 return ElementType::I32;
252 return ElementType::I64;
257 return ElementType::U16;
259 return ElementType::U32;
261 return ElementType::U64;
264 return ElementType::F16;
266 return ElementType::F32;
268 return ElementType::F64;
271 llvm_unreachable(
"Invalid element type for resource");
281 const auto *
Attr = RD->getAttr<HLSLResourceAttr>();
285 llvm::hlsl::ResourceClass RC =
Attr->getResourceClass();
286 llvm::hlsl::ResourceKind RK =
Attr->getResourceKind();
287 bool IsROV =
Attr->getIsROV();
291 addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
295 HLSLResourceBindingAttr *Binding) {
297 llvm::APInt RegInt(64, 0);
298 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
299 Reg = RegInt.getLimitedValue();
300 llvm::APInt SpaceInt(64, 0);
301 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
302 Space = SpaceInt.getLimitedValue();
310 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
311 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
312 const StringRef ShaderAttrKindStr =
"hlsl.shader";
313 Fn->addFnAttr(ShaderAttrKindStr,
314 ShaderAttr->ConvertShaderTypeToStr(ShaderAttr->getType()));
315 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
316 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
317 std::string NumThreadsStr =
318 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
319 NumThreadsAttr->getZ());
320 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
325 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
327 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
328 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
333 return B.CreateCall(F, {B.getInt32(0)});
339 assert(D.
hasAttrs() &&
"Entry parameter missing annotation attribute!");
340 if (D.
hasAttr<HLSLSV_GroupIndexAttr>()) {
341 llvm::Function *DxGroupIndex =
343 return B.CreateCall(FunctionCallee(DxGroupIndex));
345 if (D.
hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
346 llvm::Function *ThreadIDIntrinsic;
348 case llvm::Triple::dxil:
351 case llvm::Triple::spirv:
355 llvm_unreachable(
"Input semantic not supported by target");
360 assert(
false &&
"Unhandled parameter attribute");
365 llvm::Function *Fn) {
367 llvm::LLVMContext &Ctx = M.getContext();
368 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
false);
370 Function::Create(EntryTy, Function::ExternalLinkage, FD->
getName(), &M);
374 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
375 Fn->getAttributes().getFnAttrs());
376 EntryFn->setAttributes(NewAttrs);
380 Fn->setLinkage(GlobalValue::InternalLinkage);
382 BasicBlock *BB = BasicBlock::Create(Ctx,
"entry", EntryFn);
387 unsigned SRetOffset = 0;
388 for (
const auto &Param : Fn->args()) {
389 if (Param.hasStructRetAttr()) {
393 Args.emplace_back(PoisonValue::get(Param.getType()));
400 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
410 M.getNamedGlobal(CtorOrDtor ?
"llvm.global_ctors" :
"llvm.global_dtors");
413 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
421 for (
const auto &Ctor : CA->operands()) {
422 if (isa<ConstantAggregateZero>(Ctor))
424 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
426 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
427 "HLSL doesn't support setting priority for global ctors.");
428 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
429 "HLSL doesn't support COMDat for global ctors.");
430 Fns.push_back(cast<Function>(CS->getOperand(1)));
444 for (
auto &F : M.functions()) {
445 if (!F.hasFnAttribute(
"hlsl.shader"))
447 IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
448 for (
auto *Fn : CtorFns)
449 B.CreateCall(FunctionCallee(Fn));
452 B.SetInsertPoint(F.back().getTerminator());
453 for (
auto *Fn : DtorFns)
454 B.CreateCall(FunctionCallee(Fn));
459 Triple T(M.getTargetTriple());
460 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
461 if (
auto *GV = M.getNamedGlobal(
"llvm.global_ctors"))
462 GV->eraseFromParent();
463 if (
auto *GV = M.getNamedGlobal(
"llvm.global_dtors"))
464 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.
YAML serialization mapping.
std::optional< unsigned > Reg
BufferResBinding(HLSLResourceBindingAttr *Attr)
std::vector< std::pair< llvm::GlobalVariable *, unsigned > > Constants
llvm::StructType * LayoutStruct
Buffer(const HLSLBufferDecl *D)