20#include "llvm/IR/IntrinsicsDirectX.h"
21#include "llvm/IR/Metadata.h"
22#include "llvm/IR/Module.h"
23#include "llvm/Support/FormatVariadic.h"
26using namespace CodeGen;
32void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
36 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
37 Version.getSubminor() || !Version.getMinor()) {
42 uint64_t Minor = *Version.getMinor();
44 auto &Ctx = M.getContext();
45 IRBuilder<> B(M.getContext());
46 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
47 ConstantAsMetadata::get(B.getInt32(Minor))});
48 StringRef DXILValKey =
"dx.valver";
49 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
50 DXILValMD->addOperand(Val);
52void addDisableOptimizations(llvm::Module &M) {
53 StringRef Key =
"dx.disable_optimizations";
54 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
80 std::vector<llvm::Type *> EltTys;
82 GlobalVariable *GV =
Const.first;
83 Const.second = EltTys.size();
84 llvm::Type *Ty = GV->getValueType();
85 EltTys.emplace_back(Ty);
87 Buf.
LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
92 GlobalVariable *CBGV =
new GlobalVariable(
94 GlobalValue::LinkageTypes::ExternalLinkage,
nullptr,
95 llvm::formatv(
"{0}{1}", Buf.
Name, Buf.
IsCBuffer ?
".cb." :
".tb."),
96 GlobalValue::NotThreadLocal);
98 IRBuilder<> B(CBGV->getContext());
99 Value *ZeroIdx = B.getInt32(0);
101 for (
auto &[GV, Offset] : Buf.
Constants) {
103 B.CreateGEP(Buf.
LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
105 assert(Buf.
LayoutStruct->getElementType(Offset) == GV->getValueType() &&
106 "constant type mismatch");
109 GV->replaceAllUsesWith(GEP);
111 GV->removeDeadConstantUsers();
112 GV->eraseFromParent();
119void CGHLSLRuntime::addConstant(
VarDecl *D, Buffer &CB) {
131 codegenoptions::DebugInfoKind::LimitedDebugInfo)
132 DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
137 bool HasUserOffset =
false;
139 unsigned LowerBound = HasUserOffset ? Offset :
UINT_MAX;
140 CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
143void CGHLSLRuntime::addBufferDecls(
const DeclContext *DC, Buffer &CB) {
145 if (
auto *ConstDecl = dyn_cast<VarDecl>(it)) {
146 addConstant(ConstDecl, CB);
147 }
else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
149 }
else if (isa<FunctionDecl>(it)) {
158 Buffers.emplace_back(
Buffer(D));
159 addBufferDecls(D, Buffers.back());
165 Triple T(M.getTargetTriple());
166 if (T.getArch() == Triple::ArchType::dxil)
167 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
171 addDisableOptimizations(M);
173 const DataLayout &DL = M.getDataLayout();
175 for (
auto &Buf : Buffers) {
176 layoutBuffer(Buf, DL);
177 GlobalVariable *GV = replaceBuffer(Buf);
178 M.insertGlobalVariable(GV);
179 llvm::hlsl::ResourceClass RC = Buf.
IsCBuffer
180 ? llvm::hlsl::ResourceClass::CBuffer
181 : llvm::hlsl::ResourceClass::SRV;
182 llvm::hlsl::ResourceKind RK = Buf.
IsCBuffer
183 ? llvm::hlsl::ResourceKind::CBuffer
184 : llvm::hlsl::ResourceKind::TBuffer;
187 addBufferResourceAnnotation(GV, TyName, RC, RK, Buf.
Binding);
192 : Name(D->
getName()), IsCBuffer(D->isCBuffer()),
193 Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
195void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
196 llvm::StringRef TyName,
197 llvm::hlsl::ResourceClass RC,
198 llvm::hlsl::ResourceKind RK,
202 NamedMDNode *ResourceMD =
nullptr;
204 case llvm::hlsl::ResourceClass::UAV:
205 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.uavs");
207 case llvm::hlsl::ResourceClass::SRV:
208 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.srvs");
210 case llvm::hlsl::ResourceClass::CBuffer:
211 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.cbufs");
214 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());
233 const auto *
Attr = RD->getAttr<HLSLResourceAttr>();
237 llvm::hlsl::ResourceClass RC =
Attr->getResourceClass();
238 llvm::hlsl::ResourceKind RK =
Attr->getResourceKind();
242 addBufferResourceAnnotation(GV, QT.
getAsString(), RC, RK, Binding);
246 HLSLResourceBindingAttr *Binding) {
248 llvm::APInt RegInt(64, 0);
249 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
250 Reg = RegInt.getLimitedValue();
251 llvm::APInt SpaceInt(64, 0);
252 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
253 Space = SpaceInt.getLimitedValue();
261 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
262 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
263 const StringRef ShaderAttrKindStr =
"hlsl.shader";
264 Fn->addFnAttr(ShaderAttrKindStr,
265 ShaderAttr->ConvertShaderTypeToStr(ShaderAttr->getType()));
266 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
267 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
268 std::string NumThreadsStr =
269 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
270 NumThreadsAttr->getZ());
271 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
276 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
278 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
279 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
284 return B.CreateCall(F, {B.getInt32(0)});
290 assert(D.
hasAttrs() &&
"Entry parameter missing annotation attribute!");
291 if (D.
hasAttr<HLSLSV_GroupIndexAttr>()) {
292 llvm::Function *DxGroupIndex =
294 return B.CreateCall(FunctionCallee(DxGroupIndex));
296 if (D.
hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
297 llvm::Function *DxThreadID =
CGM.
getIntrinsic(Intrinsic::dx_thread_id);
300 assert(
false &&
"Unhandled parameter attribute");
305 llvm::Function *Fn) {
307 llvm::LLVMContext &Ctx = M.getContext();
308 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
false);
310 Function::Create(EntryTy, Function::ExternalLinkage, FD->
getName(), &M);
314 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
315 Fn->getAttributes().getFnAttrs());
316 EntryFn->setAttributes(NewAttrs);
320 Fn->setLinkage(GlobalValue::InternalLinkage);
322 BasicBlock *BB = BasicBlock::Create(Ctx,
"entry", EntryFn);
327 unsigned SRetOffset = 0;
328 for (
const auto &Param : Fn->args()) {
329 if (Param.hasStructRetAttr()) {
333 Args.emplace_back(PoisonValue::get(Param.getType()));
340 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
350 M.getNamedGlobal(CtorOrDtor ?
"llvm.global_ctors" :
"llvm.global_dtors");
353 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
361 for (
const auto &Ctor : CA->operands()) {
362 if (isa<ConstantAggregateZero>(Ctor))
364 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
366 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
367 "HLSL doesn't support setting priority for global ctors.");
368 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
369 "HLSL doesn't support COMDat for global ctors.");
370 Fns.push_back(cast<Function>(CS->getOperand(1)));
384 for (
auto &F : M.functions()) {
385 if (!F.hasFnAttribute(
"hlsl.shader"))
387 IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
388 for (
auto *Fn : CtorFns)
389 B.CreateCall(FunctionCallee(Fn));
392 B.SetInsertPoint(F.back().getTerminator());
393 for (
auto *Fn : DtorFns)
394 B.CreateCall(FunctionCallee(Fn));
399 Triple T(M.getTargetTriple());
400 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
401 if (
auto *GV = M.getNamedGlobal(
"llvm.global_ctors"))
402 GV->eraseFromParent();
403 if (
auto *GV = M.getNamedGlobal(
"llvm.global_dtors"))
404 GV->eraseFromParent();
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.
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.
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.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
TargetOptions & getTargetOpts() const
Retrieve the target options.
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.
Represents a variable declaration or definition.
StorageClass getStorageClass() const
Returns the storage class as written in the source.
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
@ 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)