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();
126 llvm_unreachable(
"Generic handling of HLSL types is not supported.");
129llvm::Triple::ArchType CGHLSLRuntime::getArch() {
133void CGHLSLRuntime::addConstant(
VarDecl *
D, Buffer &CB) {
145 codegenoptions::DebugInfoKind::LimitedDebugInfo)
146 DI->EmitGlobalVariable(cast<GlobalVariable>(GV),
D);
151 bool HasUserOffset =
false;
153 unsigned LowerBound = HasUserOffset ? Offset :
UINT_MAX;
154 CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
157void CGHLSLRuntime::addBufferDecls(
const DeclContext *DC, Buffer &CB) {
159 if (
auto *ConstDecl = dyn_cast<VarDecl>(it)) {
160 addConstant(ConstDecl, CB);
161 }
else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
163 }
else if (isa<FunctionDecl>(it)) {
172 Buffers.emplace_back(
Buffer(
D));
173 addBufferDecls(
D, Buffers.back());
179 Triple
T(M.getTargetTriple());
180 if (
T.getArch() == Triple::ArchType::dxil)
181 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
185 addDisableOptimizations(M);
187 const DataLayout &DL = M.getDataLayout();
189 for (
auto &Buf : Buffers) {
190 layoutBuffer(Buf, DL);
191 GlobalVariable *GV = replaceBuffer(Buf);
192 M.insertGlobalVariable(GV);
193 llvm::hlsl::ResourceClass RC = Buf.
IsCBuffer
194 ? llvm::hlsl::ResourceClass::CBuffer
195 : llvm::hlsl::ResourceClass::SRV;
196 llvm::hlsl::ResourceKind RK = Buf.
IsCBuffer
197 ? llvm::hlsl::ResourceKind::CBuffer
198 : llvm::hlsl::ResourceKind::TBuffer;
199 addBufferResourceAnnotation(GV, RC, RK,
false,
200 llvm::hlsl::ElementType::Invalid, Buf.
Binding);
205 : Name(
D->
getName()), IsCBuffer(
D->isCBuffer()),
206 Binding(
D->getAttr<HLSLResourceBindingAttr>()) {}
208void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
209 llvm::hlsl::ResourceClass RC,
210 llvm::hlsl::ResourceKind RK,
212 llvm::hlsl::ElementType ET,
216 NamedMDNode *ResourceMD =
nullptr;
218 case llvm::hlsl::ResourceClass::UAV:
219 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.uavs");
221 case llvm::hlsl::ResourceClass::SRV:
222 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.srvs");
224 case llvm::hlsl::ResourceClass::CBuffer:
225 ResourceMD = M.getOrInsertNamedMetadata(
"hlsl.cbufs");
228 assert(
false &&
"Unsupported buffer type!");
231 assert(ResourceMD !=
nullptr &&
232 "ResourceMD must have been set by the switch above.");
234 llvm::hlsl::FrontendResource Res(
236 ResourceMD->addOperand(Res.getMetadata());
239static llvm::hlsl::ElementType
241 using llvm::hlsl::ElementType;
246 assert(TST &&
"Resource types must be template specializations");
248 assert(!Args.empty() &&
"Resource has no element type");
252 QualType ElTy = Args[0].getAsType();
256 ElTy = VecTy->getElementType();
261 return ElementType::I16;
263 return ElementType::I32;
265 return ElementType::I64;
270 return ElementType::U16;
272 return ElementType::U32;
274 return ElementType::U64;
277 return ElementType::F16;
279 return ElementType::F32;
281 return ElementType::F64;
284 llvm_unreachable(
"Invalid element type for resource");
288 const Type *Ty =
D->getType()->getPointeeOrArrayElementType();
296 for (
auto *FD : RD->fields()) {
297 const auto *HLSLResAttr = FD->
getAttr<HLSLResourceAttr>();
298 const auto *HLSLResClassAttr = FD->getAttr<HLSLResourceClassAttr>();
299 if (!HLSLResAttr || !HLSLResClassAttr)
302 llvm::hlsl::ResourceClass RC = HLSLResClassAttr->getResourceClass();
303 llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind();
304 bool IsROV = HLSLResAttr->getIsROV();
308 addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
313 HLSLResourceBindingAttr *Binding) {
315 llvm::APInt RegInt(64, 0);
316 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
317 Reg = RegInt.getLimitedValue();
318 llvm::APInt SpaceInt(64, 0);
319 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
320 Space = SpaceInt.getLimitedValue();
328 const auto *ShaderAttr = FD->
getAttr<HLSLShaderAttr>();
329 assert(ShaderAttr &&
"All entry functions must have a HLSLShaderAttr");
330 const StringRef ShaderAttrKindStr =
"hlsl.shader";
331 Fn->addFnAttr(ShaderAttrKindStr,
332 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
333 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->
getAttr<HLSLNumThreadsAttr>()) {
334 const StringRef NumThreadsKindStr =
"hlsl.numthreads";
335 std::string NumThreadsStr =
336 formatv(
"{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
337 NumThreadsAttr->getZ());
338 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
343 if (
const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
345 for (
unsigned I = 0; I < VT->getNumElements(); ++I) {
346 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
351 return B.CreateCall(F, {B.getInt32(0)});
357 assert(
D.
hasAttrs() &&
"Entry parameter missing annotation attribute!");
358 if (
D.
hasAttr<HLSLSV_GroupIndexAttr>()) {
359 llvm::Function *DxGroupIndex =
361 return B.CreateCall(FunctionCallee(DxGroupIndex));
363 if (
D.
hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
364 llvm::Function *ThreadIDIntrinsic =
368 assert(
false &&
"Unhandled parameter attribute");
373 llvm::Function *Fn) {
375 llvm::LLVMContext &Ctx = M.getContext();
376 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
false);
378 Function::Create(EntryTy, Function::ExternalLinkage, FD->
getName(), &M);
382 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
383 Fn->getAttributes().getFnAttrs());
384 EntryFn->setAttributes(NewAttrs);
388 Fn->setLinkage(GlobalValue::InternalLinkage);
390 BasicBlock *BB = BasicBlock::Create(Ctx,
"entry", EntryFn);
395 unsigned SRetOffset = 0;
396 for (
const auto &Param : Fn->args()) {
397 if (Param.hasStructRetAttr()) {
401 Args.emplace_back(PoisonValue::get(Param.getType()));
408 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
416 llvm::Function *Fn) {
418 const StringRef ExportAttrKindStr =
"hlsl.export";
419 Fn->addFnAttr(ExportAttrKindStr);
426 M.getNamedGlobal(CtorOrDtor ?
"llvm.global_ctors" :
"llvm.global_dtors");
429 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
437 for (
const auto &Ctor : CA->operands()) {
438 if (isa<ConstantAggregateZero>(Ctor))
440 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
442 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
443 "HLSL doesn't support setting priority for global ctors.");
444 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
445 "HLSL doesn't support COMDat for global ctors.");
446 Fns.push_back(cast<Function>(CS->getOperand(1)));
460 for (
auto &F : M.functions()) {
461 if (!F.hasFnAttribute(
"hlsl.shader"))
463 IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
464 for (
auto *Fn : CtorFns)
465 B.CreateCall(FunctionCallee(Fn));
468 B.SetInsertPoint(F.back().getTerminator());
469 for (
auto *Fn : DtorFns)
470 B.CreateCall(FunctionCallee(Fn));
475 Triple
T(M.getTargetTriple());
476 if (
T.getEnvironment() != Triple::EnvironmentType::Library) {
477 if (
auto *GV = M.getNamedGlobal(
"llvm.global_ctors"))
478 GV->eraseFromParent();
479 if (
auto *GV = M.getNamedGlobal(
"llvm.global_dtors"))
480 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 setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
llvm::Type * convertHLSLSpecificType(const Type *T)
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 TargetCodeGenInfo & getTargetCodeGenInfo()
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.
virtual llvm::Type * getHLSLType(CodeGenModule &CGM, const Type *T) const
Return an LLVM type that corresponds to a HLSL type.
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.
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
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 isHLSLSpecificType() const
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)