[docs] Fix build-docs.sh
[llvm-project.git] / clang / lib / CodeGen / CGHLSLRuntime.cpp
blob8e0088784e548560a0bac0b19b134a18a5d7f79f
1 //===----- CGHLSLRuntime.cpp - Interface to HLSL Runtimes -----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This provides an abstract class for HLSL code generation. Concrete
10 // subclasses of this implement code generation for specific HLSL
11 // runtime libraries.
13 //===----------------------------------------------------------------------===//
15 #include "CGHLSLRuntime.h"
16 #include "CodeGenModule.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/Basic/TargetOptions.h"
19 #include "llvm/IR/IntrinsicsDirectX.h"
20 #include "llvm/IR/Metadata.h"
21 #include "llvm/IR/Module.h"
23 using namespace clang;
24 using namespace CodeGen;
25 using namespace hlsl;
26 using namespace llvm;
28 namespace {
29 void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
30 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
31 // Assume ValVersionStr is legal here.
32 VersionTuple Version;
33 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
34 Version.getSubminor() || !Version.getMinor()) {
35 return;
38 uint64_t Major = Version.getMajor();
39 uint64_t Minor = *Version.getMinor();
41 auto &Ctx = M.getContext();
42 IRBuilder<> B(M.getContext());
43 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
44 ConstantAsMetadata::get(B.getInt32(Minor))});
45 StringRef DXILValKey = "dx.valver";
46 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
47 DXILValMD->addOperand(Val);
49 void addDisableOptimizations(llvm::Module &M) {
50 StringRef Key = "dx.disable_optimizations";
51 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
54 } // namespace
56 void CGHLSLRuntime::finishCodeGen() {
57 auto &TargetOpts = CGM.getTarget().getTargetOpts();
58 llvm::Module &M = CGM.getModule();
59 Triple T(M.getTargetTriple());
60 if (T.getArch() == Triple::ArchType::dxil)
61 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
63 generateGlobalCtorDtorCalls();
64 if (CGM.getCodeGenOpts().OptimizationLevel == 0)
65 addDisableOptimizations(M);
68 void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
69 const Type *Ty = D->getType()->getPointeeOrArrayElementType();
70 if (!Ty)
71 return;
72 const auto *RD = Ty->getAsCXXRecordDecl();
73 if (!RD)
74 return;
75 const auto *Attr = RD->getAttr<HLSLResourceAttr>();
76 if (!Attr)
77 return;
79 HLSLResourceAttr::ResourceClass RC = Attr->getResourceType();
80 uint32_t Counter = ResourceCounters[static_cast<uint32_t>(RC)]++;
82 NamedMDNode *ResourceMD = nullptr;
83 switch (RC) {
84 case HLSLResourceAttr::ResourceClass::UAV:
85 ResourceMD = CGM.getModule().getOrInsertNamedMetadata("hlsl.uavs");
86 break;
87 default:
88 assert(false && "Unsupported buffer type!");
89 return;
92 assert(ResourceMD != nullptr &&
93 "ResourceMD must have been set by the switch above.");
95 auto &Ctx = CGM.getModule().getContext();
96 IRBuilder<> B(Ctx);
97 QualType QT(Ty, 0);
98 ResourceMD->addOperand(MDNode::get(
99 Ctx, {ValueAsMetadata::get(GV), MDString::get(Ctx, QT.getAsString()),
100 ConstantAsMetadata::get(B.getInt32(Counter))}));
103 void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes(
104 const FunctionDecl *FD, llvm::Function *Fn) {
105 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
106 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
107 const StringRef ShaderAttrKindStr = "hlsl.shader";
108 Fn->addFnAttr(ShaderAttrKindStr,
109 ShaderAttr->ConvertShaderTypeToStr(ShaderAttr->getType()));
112 llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
113 const ParmVarDecl &D) {
114 assert(D.hasAttrs() && "Entry parameter missing annotation attribute!");
115 if (D.hasAttr<HLSLSV_GroupIndexAttr>()) {
116 llvm::Function *DxGroupIndex =
117 CGM.getIntrinsic(Intrinsic::dx_flattened_thread_id_in_group);
118 return B.CreateCall(FunctionCallee(DxGroupIndex));
120 assert(false && "Unhandled parameter attribute");
121 return nullptr;
124 void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
125 llvm::Function *Fn) {
126 llvm::Module &M = CGM.getModule();
127 llvm::LLVMContext &Ctx = M.getContext();
128 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
129 Function *EntryFn =
130 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
132 // Copy function attributes over, we have no argument or return attributes
133 // that can be valid on the real entry.
134 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
135 Fn->getAttributes().getFnAttrs());
136 EntryFn->setAttributes(NewAttrs);
137 setHLSLEntryAttributes(FD, EntryFn);
139 // Set the called function as internal linkage.
140 Fn->setLinkage(GlobalValue::InternalLinkage);
142 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
143 IRBuilder<> B(BB);
144 llvm::SmallVector<Value *> Args;
145 // FIXME: support struct parameters where semantics are on members.
146 for (const auto *Param : FD->parameters()) {
147 Args.push_back(emitInputSemantic(B, *Param));
150 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
151 (void)CI;
152 // FIXME: Handle codegen for return type semantics.
153 B.CreateRetVoid();
156 static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
157 bool CtorOrDtor) {
158 const auto *GV =
159 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
160 if (!GV)
161 return;
162 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
163 if (!CA)
164 return;
165 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
166 // HLSL neither supports priorities or COMDat values, so we will check those
167 // in an assert but not handle them.
169 llvm::SmallVector<Function *> CtorFns;
170 for (const auto &Ctor : CA->operands()) {
171 if (isa<ConstantAggregateZero>(Ctor))
172 continue;
173 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
175 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
176 "HLSL doesn't support setting priority for global ctors.");
177 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
178 "HLSL doesn't support COMDat for global ctors.");
179 Fns.push_back(cast<Function>(CS->getOperand(1)));
183 void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
184 llvm::Module &M = CGM.getModule();
185 SmallVector<Function *> CtorFns;
186 SmallVector<Function *> DtorFns;
187 gatherFunctions(CtorFns, M, true);
188 gatherFunctions(DtorFns, M, false);
190 // Insert a call to the global constructor at the beginning of the entry block
191 // to externally exported functions. This is a bit of a hack, but HLSL allows
192 // global constructors, but doesn't support driver initialization of globals.
193 for (auto &F : M.functions()) {
194 if (!F.hasFnAttribute("hlsl.shader"))
195 continue;
196 IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
197 for (auto *Fn : CtorFns)
198 B.CreateCall(FunctionCallee(Fn));
200 // Insert global dtors before the terminator of the last instruction
201 B.SetInsertPoint(F.back().getTerminator());
202 for (auto *Fn : DtorFns)
203 B.CreateCall(FunctionCallee(Fn));