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);
103 B.CreateGEP(Buf.
LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
106 "constant type mismatch");
109 GV->replaceAllUsesWith(GEP);
111 GV->removeDeadConstantUsers();
112 GV->eraseFromParent();
119void CGHLSLRuntime::addConstant(
VarDecl *D, Buffer &CB) {
132 DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
137 bool HasUserOffset =
false;
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());
226static llvm::hlsl::ResourceKind
229 case HLSLResourceAttr::ResourceKind::Texture1D:
230 return llvm::hlsl::ResourceKind::Texture1D;
231 case HLSLResourceAttr::ResourceKind::Texture2D:
232 return llvm::hlsl::ResourceKind::Texture2D;
233 case HLSLResourceAttr::ResourceKind::Texture2DMS:
234 return llvm::hlsl::ResourceKind::Texture2DMS;
235 case HLSLResourceAttr::ResourceKind::Texture3D:
236 return llvm::hlsl::ResourceKind::Texture3D;
237 case HLSLResourceAttr::ResourceKind::TextureCube:
238 return llvm::hlsl::ResourceKind::TextureCube;
239 case HLSLResourceAttr::ResourceKind::Texture1DArray:
240 return llvm::hlsl::ResourceKind::Texture1DArray;
241 case HLSLResourceAttr::ResourceKind::Texture2DArray:
242 return llvm::hlsl::ResourceKind::Texture2DArray;
243 case HLSLResourceAttr::ResourceKind::Texture2DMSArray:
244 return llvm::hlsl::ResourceKind::Texture2DMSArray;
245 case HLSLResourceAttr::ResourceKind::TextureCubeArray:
246 return llvm::hlsl::ResourceKind::TextureCubeArray;
247 case HLSLResourceAttr::ResourceKind::TypedBuffer:
248 return llvm::hlsl::ResourceKind::TypedBuffer;
249 case HLSLResourceAttr::ResourceKind::RawBuffer:
250 return llvm::hlsl::ResourceKind::RawBuffer;
251 case HLSLResourceAttr::ResourceKind::StructuredBuffer:
252 return llvm::hlsl::ResourceKind::StructuredBuffer;
253 case HLSLResourceAttr::ResourceKind::CBufferKind:
254 return llvm::hlsl::ResourceKind::CBuffer;
255 case HLSLResourceAttr::ResourceKind::SamplerKind:
256 return llvm::hlsl::ResourceKind::Sampler;
257 case HLSLResourceAttr::ResourceKind::TBuffer:
258 return llvm::hlsl::ResourceKind::TBuffer;
259 case HLSLResourceAttr::ResourceKind::RTAccelerationStructure:
260 return llvm::hlsl::ResourceKind::RTAccelerationStructure;
261 case HLSLResourceAttr::ResourceKind::FeedbackTexture2D:
262 return llvm::hlsl::ResourceKind::FeedbackTexture2D;
263 case HLSLResourceAttr::ResourceKind::FeedbackTexture2DArray:
264 return llvm::hlsl::ResourceKind::FeedbackTexture2DArray;
270 static_cast<uint32_t
>(
271 HLSLResourceAttr::ResourceKind::FeedbackTexture2DArray) ==
272 (
static_cast<uint32_t
>(llvm::hlsl::ResourceKind::NumEntries) - 2));
273 llvm_unreachable(
"all switch cases should be covered");
283 const auto *
Attr = RD->getAttr<HLSLResourceAttr>();
287 HLSLResourceAttr::ResourceClass RC =
Attr->getResourceType();
288 llvm::hlsl::ResourceKind RK =
294 static_cast<llvm::hlsl::ResourceClass
>(RC), RK,
299 HLSLResourceBindingAttr *Binding) {
301 llvm::APInt RegInt(64, 0);
302 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
303 Reg = RegInt.getLimitedValue();
304 llvm::APInt SpaceInt(64, 0);
305 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
306 Space = SpaceInt.getLimitedValue();
314 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
315 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
316 const StringRef ShaderAttrKindStr =
"hlsl.shader";
317 Fn->addFnAttr(ShaderAttrKindStr,
318 ShaderAttr->ConvertShaderTypeToStr(ShaderAttr->getType()));
319 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
320 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
321 std::string NumThreadsStr =
322 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
323 NumThreadsAttr->getZ());
324 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
329 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
331 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
332 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
337 return B.CreateCall(F, {B.getInt32(0)});
343 assert(D.
hasAttrs() &&
"Entry parameter missing annotation attribute!");
344 if (D.
hasAttr<HLSLSV_GroupIndexAttr>()) {
345 llvm::Function *DxGroupIndex =
347 return B.CreateCall(FunctionCallee(DxGroupIndex));
349 if (D.
hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
350 llvm::Function *DxThreadID =
CGM.
getIntrinsic(Intrinsic::dx_thread_id);
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::ResourceKind castResourceShapeToResourceKind(HLSLResourceAttr::ResourceKind RK)
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.
@ LimitedDebugInfo
Limit generated debug info to reduce size (-fno-standalone-debug).
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)