DxilLinker.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilLinker.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "dxc/HLSL/DxilLinker.h"
  10. #include "dxc/HLSL/DxilCBuffer.h"
  11. #include "dxc/HLSL/DxilFunctionProps.h"
  12. #include "dxc/HLSL/DxilModule.h"
  13. #include "dxc/HLSL/DxilOperations.h"
  14. #include "dxc/HLSL/DxilResource.h"
  15. #include "dxc/HLSL/DxilSampler.h"
  16. #include "dxc/Support/Global.h"
  17. #include "llvm/ADT/StringSet.h"
  18. #include "llvm/ADT/DenseSet.h"
  19. #include "llvm/IR/Constants.h"
  20. #include "llvm/IR/IRBuilder.h"
  21. #include "llvm/IR/Instructions.h"
  22. #include "llvm/IR/Module.h"
  23. #include "llvm/Transforms/Utils/Cloning.h"
  24. #include "llvm/ADT/StringMap.h"
  25. #include <memory>
  26. #include <vector>
  27. #include "dxc/HLSL/DxilContainer.h"
  28. #include "llvm/IR/DiagnosticPrinter.h"
  29. #include "llvm/IR/LLVMContext.h"
  30. #include "dxc/HLSL/DxilGenerationPass.h"
  31. #include "llvm/IR/LegacyPassManager.h"
  32. #include "llvm/Transforms/IPO.h"
  33. #include "llvm/Transforms/Scalar.h"
  34. using namespace llvm;
  35. using namespace hlsl;
  36. namespace {
  37. void CollectUsedFunctions(Constant *C,
  38. std::unordered_set<Function *> &funcSet) {
  39. for (User *U : C->users()) {
  40. if (Instruction *I = dyn_cast<Instruction>(U)) {
  41. funcSet.insert(I->getParent()->getParent());
  42. } else {
  43. Constant *CU = cast<Constant>(U);
  44. CollectUsedFunctions(CU, funcSet);
  45. }
  46. }
  47. }
  48. template <class T>
  49. void AddResourceMap(
  50. const std::vector<std::unique_ptr<T>> &resTab, DXIL::ResourceClass resClass,
  51. std::unordered_map<const llvm::Constant *, DxilResourceBase *> &resMap,
  52. DxilModule &DM) {
  53. for (auto &Res : resTab) {
  54. const DxilModule::ResourceLinkInfo &linkInfo =
  55. DM.GetResourceLinkInfo(resClass, Res->GetID());
  56. resMap[linkInfo.ResRangeID] = Res.get();
  57. }
  58. }
  59. void CloneFunction(Function *F, Function *NewF, ValueToValueMapTy &vmap) {
  60. SmallVector<ReturnInst *, 2> Returns;
  61. // Map params.
  62. auto paramIt = NewF->arg_begin();
  63. for (Argument &param : F->args()) {
  64. vmap[&param] = (paramIt++);
  65. }
  66. llvm::CloneFunctionInto(NewF, F, vmap, /*ModuleLevelChanges*/ true, Returns);
  67. // Remove params from vmap.
  68. for (Argument &param : F->args()) {
  69. vmap.erase(&param);
  70. }
  71. }
  72. } // namespace
  73. namespace {
  74. struct DxilFunctionLinkInfo {
  75. DxilFunctionLinkInfo(llvm::Function *F);
  76. llvm::Function *func;
  77. std::unordered_set<llvm::Function *> usedFunctions;
  78. std::unordered_set<llvm::GlobalVariable *> usedGVs;
  79. std::unordered_set<DxilResourceBase *> usedResources;
  80. };
  81. // Library to link.
  82. class DxilLib {
  83. public:
  84. DxilLib(std::unique_ptr<llvm::Module> pModule);
  85. virtual ~DxilLib() {}
  86. bool HasFunction(std::string &name);
  87. llvm::StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &GetFunctionTable() {
  88. return m_functionNameMap;
  89. }
  90. bool IsInitFunc(llvm::Function *F);
  91. bool IsResourceGlobal(const llvm::Constant *GV);
  92. DxilResourceBase *GetResource(const llvm::Constant *GV);
  93. DxilModule &GetDxilModule() { return m_DM; }
  94. void LazyLoadFunction(Function *F);
  95. void BuildGlobalUsage();
  96. void CollectUsedInitFunctions(StringSet<> &addedFunctionSet,
  97. SmallVector<StringRef, 4> &workList);
  98. private:
  99. std::unique_ptr<llvm::Module> m_pModule;
  100. DxilModule &m_DM;
  101. // Map from name to Link info for extern functions.
  102. llvm::StringMap<std::unique_ptr<DxilFunctionLinkInfo>> m_functionNameMap;
  103. // Map from resource link global to resource.
  104. std::unordered_map<const llvm::Constant *, DxilResourceBase *> m_resourceMap;
  105. // Set of initialize functions for global variable.
  106. std::unordered_set<llvm::Function *> m_initFuncSet;
  107. };
  108. struct DxilLinkJob;
  109. class DxilLinkerImpl : public hlsl::DxilLinker {
  110. public:
  111. DxilLinkerImpl(LLVMContext &Ctx, unsigned valMajor, unsigned valMinor) : DxilLinker(Ctx, valMajor, valMinor) {}
  112. virtual ~DxilLinkerImpl() {}
  113. bool HasLibNameRegistered(StringRef name) override;
  114. bool RegisterLib(StringRef name, std::unique_ptr<llvm::Module> pModule,
  115. std::unique_ptr<llvm::Module> pDebugModule) override;
  116. bool AttachLib(StringRef name) override;
  117. bool DetachLib(StringRef name) override;
  118. void DetachAll() override;
  119. std::unique_ptr<llvm::Module> Link(StringRef entry,
  120. StringRef profile) override;
  121. private:
  122. bool AttachLib(DxilLib *lib);
  123. bool DetachLib(DxilLib *lib);
  124. bool AddFunctions(SmallVector<StringRef, 4> &workList,
  125. DenseSet<DxilLib *> &libSet, StringSet<> &addedFunctionSet,
  126. DxilLinkJob &linkJob, bool bLazyLoadDone);
  127. // Attached libs to link.
  128. std::unordered_set<DxilLib *> m_attachedLibs;
  129. // Owner of all DxilLib.
  130. StringMap<std::unique_ptr<DxilLib>> m_LibMap;
  131. llvm::StringMap<std::pair<DxilFunctionLinkInfo *, DxilLib *>>
  132. m_functionNameMap;
  133. };
  134. } // namespace
  135. //------------------------------------------------------------------------------
  136. //
  137. // DxilFunctionLinkInfo methods.
  138. //
  139. DxilFunctionLinkInfo::DxilFunctionLinkInfo(Function *F) : func(F) {
  140. DXASSERT_NOMSG(F);
  141. }
  142. //------------------------------------------------------------------------------
  143. //
  144. // DxilLib methods.
  145. //
  146. DxilLib::DxilLib(std::unique_ptr<llvm::Module> pModule)
  147. : m_pModule(std::move(pModule)), m_DM(m_pModule->GetOrCreateDxilModule()) {
  148. Module &M = *m_pModule;
  149. const std::string &MID = M.getModuleIdentifier();
  150. // Collect function defines.
  151. for (Function &F : M.functions()) {
  152. if (F.isDeclaration())
  153. continue;
  154. if (F.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage) {
  155. // Add prefix to internal function.
  156. F.setName(MID + F.getName());
  157. }
  158. m_functionNameMap[F.getName()] =
  159. llvm::make_unique<DxilFunctionLinkInfo>(&F);
  160. }
  161. // Update internal global name.
  162. for (GlobalVariable &GV : M.globals()) {
  163. if (GV.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage) {
  164. // Add prefix to internal global.
  165. GV.setName(MID + GV.getName());
  166. }
  167. }
  168. }
  169. void DxilLib::LazyLoadFunction(Function *F) {
  170. DXASSERT(m_functionNameMap.count(F->getName()), "else invalid Function");
  171. DxilFunctionLinkInfo *linkInfo = m_functionNameMap[F->getName()].get();
  172. std::error_code EC = F->materialize();
  173. DXASSERT_LOCALVAR(EC, !EC, "else fail to materialize");
  174. // Build used functions for F.
  175. for (auto &BB : F->getBasicBlockList()) {
  176. for (auto &I : BB.getInstList()) {
  177. if (CallInst *CI = dyn_cast<CallInst>(&I)) {
  178. linkInfo->usedFunctions.insert(CI->getCalledFunction());
  179. }
  180. }
  181. }
  182. if (m_DM.HasDxilFunctionProps(F)) {
  183. DxilFunctionProps &props = m_DM.GetDxilFunctionProps(F);
  184. if (props.IsHS()) {
  185. // Add patch constant function to usedFunctions of entry.
  186. Function *patchConstantFunc = props.ShaderProps.HS.patchConstantFunc;
  187. linkInfo->usedFunctions.insert(patchConstantFunc);
  188. }
  189. }
  190. // Used globals will be build before link.
  191. }
  192. void DxilLib::BuildGlobalUsage() {
  193. Module &M = *m_pModule;
  194. // Collect init functions for static globals.
  195. if (GlobalVariable *Ctors = M.getGlobalVariable("llvm.global_ctors")) {
  196. if (ConstantArray *CA = dyn_cast<ConstantArray>(Ctors->getInitializer())) {
  197. for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e;
  198. ++i) {
  199. if (isa<ConstantAggregateZero>(*i))
  200. continue;
  201. ConstantStruct *CS = cast<ConstantStruct>(*i);
  202. if (isa<ConstantPointerNull>(CS->getOperand(1)))
  203. continue;
  204. // Must have a function or null ptr.
  205. if (!isa<Function>(CS->getOperand(1)))
  206. continue;
  207. Function *Ctor = cast<Function>(CS->getOperand(1));
  208. assert(Ctor->getReturnType()->isVoidTy() && Ctor->arg_size() == 0 &&
  209. "function type must be void (void)");
  210. // Add Ctor.
  211. m_initFuncSet.insert(Ctor);
  212. LazyLoadFunction(Ctor);
  213. }
  214. }
  215. }
  216. // Build used globals.
  217. for (GlobalVariable &GV : M.globals()) {
  218. std::unordered_set<Function *> funcSet;
  219. CollectUsedFunctions(&GV, funcSet);
  220. for (Function *F : funcSet) {
  221. DXASSERT(m_functionNameMap.count(F->getName()), "must exist in table");
  222. DxilFunctionLinkInfo *linkInfo = m_functionNameMap[F->getName()].get();
  223. linkInfo->usedGVs.insert(&GV);
  224. }
  225. }
  226. // Build resource map.
  227. AddResourceMap(m_DM.GetUAVs(), DXIL::ResourceClass::UAV, m_resourceMap, m_DM);
  228. AddResourceMap(m_DM.GetSRVs(), DXIL::ResourceClass::SRV, m_resourceMap, m_DM);
  229. AddResourceMap(m_DM.GetCBuffers(), DXIL::ResourceClass::CBuffer,
  230. m_resourceMap, m_DM);
  231. AddResourceMap(m_DM.GetSamplers(), DXIL::ResourceClass::Sampler,
  232. m_resourceMap, m_DM);
  233. }
  234. void DxilLib::CollectUsedInitFunctions(StringSet<> &addedFunctionSet,
  235. SmallVector<StringRef, 4> &workList) {
  236. // Add init functions to used functions.
  237. for (Function *Ctor : m_initFuncSet) {
  238. DXASSERT(m_functionNameMap.count(Ctor->getName()),
  239. "must exist in internal table");
  240. DxilFunctionLinkInfo *linkInfo = m_functionNameMap[Ctor->getName()].get();
  241. // If function other than Ctor used GV of Ctor.
  242. // Add Ctor to usedFunctions for it.
  243. for (GlobalVariable *GV : linkInfo->usedGVs) {
  244. std::unordered_set<Function *> funcSet;
  245. CollectUsedFunctions(GV, funcSet);
  246. bool bAdded = false;
  247. for (Function *F : funcSet) {
  248. if (F == Ctor)
  249. continue;
  250. // If F is added for link, add init func to workList.
  251. if (addedFunctionSet.count(F->getName())) {
  252. workList.emplace_back(Ctor->getName());
  253. bAdded = true;
  254. break;
  255. }
  256. }
  257. if (bAdded)
  258. break;
  259. }
  260. }
  261. }
  262. bool DxilLib::HasFunction(std::string &name) {
  263. return m_functionNameMap.count(name);
  264. }
  265. bool DxilLib::IsInitFunc(llvm::Function *F) { return m_initFuncSet.count(F); }
  266. bool DxilLib::IsResourceGlobal(const llvm::Constant *GV) {
  267. return m_resourceMap.count(GV);
  268. }
  269. DxilResourceBase *DxilLib::GetResource(const llvm::Constant *GV) {
  270. if (IsResourceGlobal(GV))
  271. return m_resourceMap[GV];
  272. else
  273. return nullptr;
  274. }
  275. namespace {
  276. // Create module from link defines.
  277. struct DxilLinkJob {
  278. DxilLinkJob(LLVMContext &Ctx, unsigned valMajor, unsigned valMinor) : m_ctx(Ctx), m_valMajor(valMajor), m_valMinor(valMinor) {}
  279. std::unique_ptr<llvm::Module>
  280. Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
  281. StringRef profile);
  282. void RunPreparePass(llvm::Module &M);
  283. void AddFunction(std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair);
  284. void AddFunction(llvm::Function *F);
  285. private:
  286. bool AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV);
  287. void AddResourceToDM(DxilModule &DM);
  288. std::unordered_map<DxilFunctionLinkInfo *, DxilLib *> m_functionDefs;
  289. llvm::StringMap<llvm::Function *> m_dxilFunctions;
  290. // New created functions.
  291. llvm::StringMap<llvm::Function *> m_newFunctions;
  292. // New created globals.
  293. llvm::StringMap<llvm::GlobalVariable *> m_newGlobals;
  294. // Map for resource.
  295. llvm::StringMap<std::pair<DxilResourceBase *, llvm::GlobalVariable *>>
  296. m_resourceMap;
  297. LLVMContext &m_ctx;
  298. unsigned m_valMajor, m_valMinor;
  299. };
  300. } // namespace
  301. namespace {
  302. const char kUndefFunction[] = "Cannot find definition of function ";
  303. const char kRedefineFunction[] = "Definition already exists for function ";
  304. const char kRedefineGlobal[] = "Definition already exists for global variable ";
  305. const char kInvalidProfile[] = " is invalid profile to link";
  306. const char kShaderKindMismatch[] =
  307. "Profile mismatch between entry function and target profile:";
  308. const char kNoEntryProps[] =
  309. "Cannot find function property for entry function ";
  310. const char kRedefineResource[] =
  311. "Resource already exists as ";
  312. const char kInvalidValidatorVersion[] = "Validator version does not support target profile ";
  313. } // namespace
  314. //------------------------------------------------------------------------------
  315. //
  316. // DxilLinkJob methods.
  317. //
  318. namespace {
  319. // Helper function to check type match.
  320. bool IsMatchedType(Type *Ty0, Type *Ty);
  321. StringRef RemoveNameSuffix(StringRef Name) {
  322. size_t DotPos = Name.rfind('.');
  323. if (DotPos != StringRef::npos && Name.back() != '.' &&
  324. isdigit(static_cast<unsigned char>(Name[DotPos + 1])))
  325. Name = Name.substr(0, DotPos);
  326. return Name;
  327. }
  328. bool IsMatchedStructType(StructType *ST0, StructType *ST) {
  329. StringRef Name0 = RemoveNameSuffix(ST0->getName());
  330. StringRef Name = RemoveNameSuffix(ST->getName());
  331. if (Name0 != Name)
  332. return false;
  333. if (ST0->getNumElements() != ST->getNumElements())
  334. return false;
  335. if (ST0->isLayoutIdentical(ST))
  336. return true;
  337. for (unsigned i = 0; i < ST->getNumElements(); i++) {
  338. Type *Ty = ST->getElementType(i);
  339. Type *Ty0 = ST0->getElementType(i);
  340. if (!IsMatchedType(Ty, Ty0))
  341. return false;
  342. }
  343. return true;
  344. }
  345. bool IsMatchedArrayType(ArrayType *AT0, ArrayType *AT) {
  346. if (AT0->getNumElements() != AT->getNumElements())
  347. return false;
  348. return IsMatchedType(AT0->getElementType(), AT->getElementType());
  349. }
  350. bool IsMatchedType(Type *Ty0, Type *Ty) {
  351. if (Ty0->isStructTy() && Ty->isStructTy()) {
  352. StructType *ST0 = cast<StructType>(Ty0);
  353. StructType *ST = cast<StructType>(Ty);
  354. return IsMatchedStructType(ST0, ST);
  355. }
  356. if (Ty0->isArrayTy() && Ty->isArrayTy()) {
  357. ArrayType *AT0 = cast<ArrayType>(Ty0);
  358. ArrayType *AT = cast<ArrayType>(Ty);
  359. return IsMatchedArrayType(AT0, AT);
  360. }
  361. if (Ty0->isPointerTy() && Ty->isPointerTy()) {
  362. if (Ty0->getPointerAddressSpace() != Ty->getPointerAddressSpace())
  363. return false;
  364. return IsMatchedType(Ty0->getPointerElementType(),
  365. Ty->getPointerElementType());
  366. }
  367. return Ty0 == Ty;
  368. }
  369. } // namespace
  370. bool DxilLinkJob::AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV) {
  371. if (m_resourceMap.count(res->GetGlobalName())) {
  372. DxilResourceBase *res0 = m_resourceMap[res->GetGlobalName()].first;
  373. Type *Ty0 = res0->GetGlobalSymbol()->getType()->getPointerElementType();
  374. Type *Ty = res->GetGlobalSymbol()->getType()->getPointerElementType();
  375. // Make sure res0 match res.
  376. bool bMatch = IsMatchedType(Ty0, Ty);
  377. if (!bMatch) {
  378. // Report error.
  379. m_ctx.emitError(Twine(kRedefineResource) + res->GetResClassName() + " for " +
  380. res->GetGlobalName());
  381. return false;
  382. }
  383. } else {
  384. m_resourceMap[res->GetGlobalName()] = std::make_pair(res, GV);
  385. }
  386. return true;
  387. }
  388. void DxilLinkJob::AddResourceToDM(DxilModule &DM) {
  389. for (auto &it : m_resourceMap) {
  390. DxilResourceBase *res = it.second.first;
  391. GlobalVariable *GV = it.second.second;
  392. unsigned ID = 0;
  393. DxilResourceBase *basePtr = nullptr;
  394. switch (res->GetClass()) {
  395. case DXIL::ResourceClass::UAV: {
  396. std::unique_ptr<DxilResource> pUAV = llvm::make_unique<DxilResource>();
  397. DxilResource *ptr = pUAV.get();
  398. // Copy the content.
  399. *ptr = *(static_cast<DxilResource *>(res));
  400. ID = DM.AddUAV(std::move(pUAV));
  401. basePtr = &DM.GetUAV(ID);
  402. } break;
  403. case DXIL::ResourceClass::SRV: {
  404. std::unique_ptr<DxilResource> pSRV = llvm::make_unique<DxilResource>();
  405. DxilResource *ptr = pSRV.get();
  406. // Copy the content.
  407. *ptr = *(static_cast<DxilResource *>(res));
  408. ID = DM.AddSRV(std::move(pSRV));
  409. basePtr = &DM.GetSRV(ID);
  410. } break;
  411. case DXIL::ResourceClass::CBuffer: {
  412. std::unique_ptr<DxilCBuffer> pCBuf = llvm::make_unique<DxilCBuffer>();
  413. DxilCBuffer *ptr = pCBuf.get();
  414. // Copy the content.
  415. *ptr = *(static_cast<DxilCBuffer *>(res));
  416. ID = DM.AddCBuffer(std::move(pCBuf));
  417. basePtr = &DM.GetCBuffer(ID);
  418. } break;
  419. case DXIL::ResourceClass::Sampler: {
  420. std::unique_ptr<DxilSampler> pSampler = llvm::make_unique<DxilSampler>();
  421. DxilSampler *ptr = pSampler.get();
  422. // Copy the content.
  423. *ptr = *(static_cast<DxilSampler *>(res));
  424. ID = DM.AddSampler(std::move(pSampler));
  425. basePtr = &DM.GetSampler(ID);
  426. }
  427. default:
  428. DXASSERT(res->GetClass() == DXIL::ResourceClass::Sampler,
  429. "else invalid resource");
  430. break;
  431. }
  432. // Update ID.
  433. basePtr->SetID(ID);
  434. Constant *rangeID = ConstantInt::get(GV->getType()->getElementType(), ID);
  435. for (User *U : GV->users()) {
  436. LoadInst *LI = cast<LoadInst>(U);
  437. LI->replaceAllUsesWith(rangeID);
  438. }
  439. }
  440. }
  441. std::unique_ptr<Module>
  442. DxilLinkJob::Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
  443. StringRef profile) {
  444. Function *entryFunc = entryLinkPair.first->func;
  445. DxilModule &entryDM = entryLinkPair.second->GetDxilModule();
  446. if (!entryDM.HasDxilFunctionProps(entryFunc)) {
  447. // Cannot get function props.
  448. m_ctx.emitError(Twine(kNoEntryProps) + entryFunc->getName());
  449. return nullptr;
  450. }
  451. DxilFunctionProps props = entryDM.GetDxilFunctionProps(entryFunc);
  452. if (props.shaderKind == DXIL::ShaderKind::Library ||
  453. props.shaderKind == DXIL::ShaderKind::Invalid ||
  454. (props.shaderKind >= DXIL::ShaderKind::RayGeneration &&
  455. props.shaderKind <= DXIL::ShaderKind::Callable)) {
  456. m_ctx.emitError(profile + Twine(kInvalidProfile));
  457. // Invalid profile.
  458. return nullptr;
  459. }
  460. const ShaderModel *pSM = ShaderModel::GetByName(profile.data());
  461. if (pSM->GetKind() != props.shaderKind) {
  462. // Shader kind mismatch.
  463. m_ctx.emitError(Twine(kShaderKindMismatch) + profile + " and " +
  464. ShaderModel::GetKindName(props.shaderKind));
  465. return nullptr;
  466. }
  467. // Create new module.
  468. std::unique_ptr<Module> pM =
  469. llvm::make_unique<Module>(entryFunc->getName(), entryDM.GetCtx());
  470. // Set target.
  471. pM->setTargetTriple(entryDM.GetModule()->getTargetTriple());
  472. // Add dxil operation functions before create DxilModule.
  473. for (auto &it : m_dxilFunctions) {
  474. Function *F = it.second;
  475. Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
  476. F->getName(), pM.get());
  477. NewF->setAttributes(F->getAttributes());
  478. m_newFunctions[NewF->getName()] = NewF;
  479. }
  480. // Create DxilModule.
  481. const bool bSkipInit = true;
  482. DxilModule &DM = pM->GetOrCreateDxilModule(bSkipInit);
  483. DM.SetShaderModel(pSM);
  484. // Set Validator version, verifying that it supports the requested profile
  485. unsigned minValMajor, minValMinor;
  486. DM.GetMinValidatorVersion(minValMajor, minValMinor);
  487. if (minValMajor > m_valMajor || (minValMajor == m_valMajor && minValMinor > m_valMinor)) {
  488. m_ctx.emitError(Twine(kInvalidValidatorVersion) + profile);
  489. return nullptr;
  490. }
  491. DM.SetValidatorVersion(m_valMajor, m_valMinor);
  492. // Add type sys
  493. DxilTypeSystem &typeSys = DM.GetTypeSystem();
  494. ValueToValueMapTy vmap;
  495. std::unordered_set<Function *> initFuncSet;
  496. // Add function
  497. for (auto &it : m_functionDefs) {
  498. DxilFunctionLinkInfo *linkInfo = it.first;
  499. DxilLib *pLib = it.second;
  500. DxilModule &tmpDM = pLib->GetDxilModule();
  501. DxilTypeSystem &tmpTypeSys = tmpDM.GetTypeSystem();
  502. Function *F = linkInfo->func;
  503. Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
  504. F->getName(), pM.get());
  505. NewF->setAttributes(F->getAttributes());
  506. if (!NewF->hasFnAttribute(llvm::Attribute::NoInline))
  507. NewF->addFnAttr(llvm::Attribute::AlwaysInline);
  508. if (DxilFunctionAnnotation *funcAnnotation =
  509. tmpTypeSys.GetFunctionAnnotation(F)) {
  510. // Clone funcAnnotation to typeSys.
  511. typeSys.CopyFunctionAnnotation(NewF, F, tmpTypeSys);
  512. }
  513. // Add to function map.
  514. m_newFunctions[NewF->getName()] = NewF;
  515. if (pLib->IsInitFunc(F))
  516. initFuncSet.insert(NewF);
  517. vmap[F] = NewF;
  518. }
  519. // Set Entry
  520. Function *NewEntryFunc = m_newFunctions[entryFunc->getName()];
  521. DM.SetEntryFunction(NewEntryFunc);
  522. DM.SetEntryFunctionName(entryFunc->getName());
  523. if (entryDM.HasDxilEntrySignature(entryFunc)) {
  524. // Add signature.
  525. DxilEntrySignature &entrySig = entryDM.GetDxilEntrySignature(entryFunc);
  526. std::unique_ptr<DxilEntrySignature> newSig =
  527. std::make_unique<DxilEntrySignature>(entrySig);
  528. DM.ResetEntrySignature(newSig.release());
  529. }
  530. if (NewEntryFunc->hasFnAttribute(llvm::Attribute::AlwaysInline))
  531. NewEntryFunc->removeFnAttr(llvm::Attribute::AlwaysInline);
  532. if (props.IsHS()) {
  533. Function *patchConstantFunc = props.ShaderProps.HS.patchConstantFunc;
  534. Function *newPatchConstantFunc =
  535. m_newFunctions[patchConstantFunc->getName()];
  536. props.ShaderProps.HS.patchConstantFunc = newPatchConstantFunc;
  537. if (newPatchConstantFunc->hasFnAttribute(llvm::Attribute::AlwaysInline))
  538. newPatchConstantFunc->removeFnAttr(llvm::Attribute::AlwaysInline);
  539. }
  540. // Set EntryProps
  541. DM.SetShaderProperties(&props);
  542. // Debug info.
  543. // Add global
  544. bool bSuccess = true;
  545. for (auto &it : m_functionDefs) {
  546. DxilFunctionLinkInfo *linkInfo = it.first;
  547. DxilLib *pLib = it.second;
  548. for (GlobalVariable *GV : linkInfo->usedGVs) {
  549. // Skip added globals.
  550. if (m_newGlobals.count(GV->getName())) {
  551. if (vmap.find(GV) == vmap.end()) {
  552. if (DxilResourceBase *res = pLib->GetResource(GV)) {
  553. // For resource of same name, if class and type match, just map to
  554. // same NewGV.
  555. GlobalVariable *NewGV = m_newGlobals[GV->getName()];
  556. if (AddResource(res, NewGV)) {
  557. vmap[GV] = NewGV;
  558. } else {
  559. bSuccess = false;
  560. }
  561. continue;
  562. }
  563. // Redefine of global.
  564. m_ctx.emitError(Twine(kRedefineGlobal) + GV->getName());
  565. bSuccess = false;
  566. }
  567. continue;
  568. }
  569. Constant *Initializer = nullptr;
  570. if (GV->hasInitializer())
  571. Initializer = GV->getInitializer();
  572. GlobalVariable *NewGV = new GlobalVariable(
  573. *pM, GV->getType()->getElementType(), GV->isConstant(),
  574. GV->getLinkage(), Initializer, GV->getName(),
  575. /*InsertBefore*/ nullptr, GV->getThreadLocalMode(),
  576. GV->getType()->getAddressSpace(), GV->isExternallyInitialized());
  577. m_newGlobals[GV->getName()] = NewGV;
  578. vmap[GV] = NewGV;
  579. if (DxilResourceBase *res = pLib->GetResource(GV)) {
  580. bSuccess &= AddResource(res, NewGV);
  581. }
  582. }
  583. }
  584. if (!bSuccess)
  585. return nullptr;
  586. // Clone functions.
  587. for (auto &it : m_functionDefs) {
  588. DxilFunctionLinkInfo *linkInfo = it.first;
  589. Function *F = linkInfo->func;
  590. Function *NewF = m_newFunctions[F->getName()];
  591. // Add dxil functions to vmap.
  592. for (Function *UsedF : linkInfo->usedFunctions) {
  593. if (!vmap.count(UsedF)) {
  594. // Extern function need match by name
  595. DXASSERT(m_newFunctions.count(UsedF->getName()),
  596. "Must have new function.");
  597. vmap[UsedF] = m_newFunctions[UsedF->getName()];
  598. }
  599. }
  600. CloneFunction(F, NewF, vmap);
  601. }
  602. // Call global constrctor.
  603. IRBuilder<> Builder(
  604. DM.GetEntryFunction()->getEntryBlock().getFirstInsertionPt());
  605. for (auto &it : m_functionDefs) {
  606. DxilFunctionLinkInfo *linkInfo = it.first;
  607. DxilLib *pLib = it.second;
  608. Function *F = linkInfo->func;
  609. if (pLib->IsInitFunc(F)) {
  610. Function *NewF = m_newFunctions[F->getName()];
  611. Builder.CreateCall(NewF);
  612. }
  613. }
  614. // Refresh intrinsic cache.
  615. DM.GetOP()->RefreshCache();
  616. // Add resource to DM.
  617. // This should be after functions cloned.
  618. AddResourceToDM(DM);
  619. RunPreparePass(*pM);
  620. return pM;
  621. }
  622. void DxilLinkJob::AddFunction(
  623. std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair) {
  624. m_functionDefs[linkPair.first] = linkPair.second;
  625. }
  626. void DxilLinkJob::AddFunction(llvm::Function *F) {
  627. m_dxilFunctions[F->getName()] = F;
  628. }
  629. void DxilLinkJob::RunPreparePass(Module &M) {
  630. legacy::PassManager PM;
  631. PM.add(createAlwaysInlinerPass(/*InsertLifeTime*/ false));
  632. PM.add(createDxilDeadFunctionEliminationPass());
  633. // mem2reg.
  634. PM.add(createPromoteMemoryToRegisterPass());
  635. // Remove unused functions.
  636. PM.add(createDeadCodeEliminationPass());
  637. PM.add(createGlobalDCEPass());
  638. PM.add(createSimplifyInstPass());
  639. PM.add(createCFGSimplificationPass());
  640. PM.add(createDxilCondenseResourcesPass());
  641. PM.add(createDxilFinalizeModulePass());
  642. PM.add(createComputeViewIdStatePass());
  643. PM.add(createDxilDeadFunctionEliminationPass());
  644. PM.add(createNoPausePassesPass());
  645. PM.add(createDxilEmitMetadataPass());
  646. PM.run(M);
  647. }
  648. //------------------------------------------------------------------------------
  649. //
  650. // DxilLinkerImpl methods.
  651. //
  652. bool DxilLinkerImpl::HasLibNameRegistered(StringRef name) {
  653. return m_LibMap.count(name);
  654. }
  655. bool DxilLinkerImpl::RegisterLib(StringRef name,
  656. std::unique_ptr<llvm::Module> pModule,
  657. std::unique_ptr<llvm::Module> pDebugModule) {
  658. if (m_LibMap.count(name))
  659. return false;
  660. std::unique_ptr<llvm::Module> pM =
  661. pDebugModule ? std::move(pDebugModule) : std::move(pModule);
  662. if (!pM)
  663. return false;
  664. pM->setModuleIdentifier(name);
  665. std::unique_ptr<DxilLib> pLib =
  666. std::make_unique<DxilLib>(std::move(pM));
  667. m_LibMap[name] = std::move(pLib);
  668. return true;
  669. }
  670. bool DxilLinkerImpl::AttachLib(StringRef name) {
  671. auto iter = m_LibMap.find(name);
  672. if (iter == m_LibMap.end()) {
  673. return false;
  674. }
  675. return AttachLib(iter->second.get());
  676. }
  677. bool DxilLinkerImpl::DetachLib(StringRef name) {
  678. auto iter = m_LibMap.find(name);
  679. if (iter == m_LibMap.end()) {
  680. return false;
  681. }
  682. return DetachLib(iter->second.get());
  683. }
  684. void DxilLinkerImpl::DetachAll() {
  685. m_functionNameMap.clear();
  686. m_attachedLibs.clear();
  687. }
  688. bool DxilLinkerImpl::AttachLib(DxilLib *lib) {
  689. if (!lib) {
  690. // Invalid arg.
  691. return false;
  692. }
  693. if (m_attachedLibs.count(lib))
  694. return false;
  695. StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &funcTable =
  696. lib->GetFunctionTable();
  697. bool bSuccess = true;
  698. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  699. StringRef name = it->getKey();
  700. if (m_functionNameMap.count(name)) {
  701. // Redefine of function.
  702. m_ctx.emitError(Twine(kRedefineFunction) + name);
  703. bSuccess = false;
  704. continue;
  705. }
  706. m_functionNameMap[name] = std::make_pair(it->second.get(), lib);
  707. }
  708. if (bSuccess) {
  709. m_attachedLibs.insert(lib);
  710. } else {
  711. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  712. StringRef name = it->getKey();
  713. auto iter = m_functionNameMap.find(name);
  714. if (iter == m_functionNameMap.end())
  715. continue;
  716. // Remove functions of lib.
  717. if (m_functionNameMap[name].second == lib)
  718. m_functionNameMap.erase(name);
  719. }
  720. }
  721. return bSuccess;
  722. }
  723. bool DxilLinkerImpl::DetachLib(DxilLib *lib) {
  724. if (!lib) {
  725. // Invalid arg.
  726. return false;
  727. }
  728. if (!m_attachedLibs.count(lib))
  729. return false;
  730. m_attachedLibs.erase(lib);
  731. // Remove functions from lib.
  732. StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &funcTable =
  733. lib->GetFunctionTable();
  734. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  735. StringRef name = it->getKey();
  736. m_functionNameMap.erase(name);
  737. }
  738. return true;
  739. }
  740. bool DxilLinkerImpl::AddFunctions(SmallVector<StringRef, 4> &workList,
  741. DenseSet<DxilLib *> &libSet,
  742. StringSet<> &addedFunctionSet,
  743. DxilLinkJob &linkJob, bool bLazyLoadDone) {
  744. while (!workList.empty()) {
  745. StringRef name = workList.pop_back_val();
  746. // Ignore added function.
  747. if (addedFunctionSet.count(name))
  748. continue;
  749. if (!m_functionNameMap.count(name)) {
  750. // Cannot find function, report error.
  751. m_ctx.emitError(Twine(kUndefFunction) + name);
  752. return false;
  753. }
  754. std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair =
  755. m_functionNameMap[name];
  756. linkJob.AddFunction(linkPair);
  757. DxilLib *pLib = linkPair.second;
  758. libSet.insert(pLib);
  759. if (!bLazyLoadDone) {
  760. Function *F = linkPair.first->func;
  761. pLib->LazyLoadFunction(F);
  762. }
  763. for (Function *F : linkPair.first->usedFunctions) {
  764. if (hlsl::OP::IsDxilOpFunc(F)) {
  765. // Add dxil operations directly.
  766. linkJob.AddFunction(F);
  767. } else {
  768. // Push function name to work list.
  769. workList.emplace_back(F->getName());
  770. }
  771. }
  772. addedFunctionSet.insert(name);
  773. }
  774. return true;
  775. }
  776. std::unique_ptr<llvm::Module> DxilLinkerImpl::Link(StringRef entry,
  777. StringRef profile) {
  778. StringSet<> addedFunctionSet;
  779. SmallVector<StringRef, 4> workList;
  780. workList.emplace_back(entry);
  781. DxilLinkJob linkJob(m_ctx, m_valMajor, m_valMinor);
  782. DenseSet<DxilLib *> libSet;
  783. if (!AddFunctions(workList, libSet, addedFunctionSet, linkJob,
  784. /*bLazyLoadDone*/ false))
  785. return nullptr;
  786. // Save global users.
  787. for (auto &pLib : libSet) {
  788. pLib->BuildGlobalUsage();
  789. }
  790. // Save global ctor users.
  791. for (auto &pLib : libSet) {
  792. pLib->CollectUsedInitFunctions(addedFunctionSet, workList);
  793. }
  794. // Add init functions if used.
  795. // All init function already loaded in BuildGlobalUsage, so set bLazyLoad
  796. // false here.
  797. if (!AddFunctions(workList, libSet, addedFunctionSet, linkJob,
  798. /*bLazyLoadDone*/ true))
  799. return nullptr;
  800. std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair =
  801. m_functionNameMap[entry];
  802. return linkJob.Link(entryLinkPair, profile);
  803. }
  804. namespace hlsl {
  805. DxilLinker *DxilLinker::CreateLinker(LLVMContext &Ctx, unsigned valMajor, unsigned valMinor) {
  806. return new DxilLinkerImpl(Ctx, valMajor, valMinor);
  807. }
  808. } // namespace hlsl