DxilLinker.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  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) : DxilLinker(Ctx) {}
  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) : m_ctx(Ctx) {}
  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. };
  299. } // namespace
  300. namespace {
  301. const char kUndefFunction[] = "Cannot find definition of function ";
  302. const char kRedefineFunction[] = "Definition already exists for function ";
  303. const char kRedefineGlobal[] = "Definition already exists for global variable ";
  304. const char kInvalidProfile[] = " is invalid profile to link";
  305. const char kShaderKindMismatch[] =
  306. "Profile mismatch between entry function and target profile:";
  307. const char kNoEntryProps[] =
  308. "Cannot find function property for entry function ";
  309. const char kRedefineResource[] =
  310. "Resource already exists as ";
  311. } // namespace
  312. //------------------------------------------------------------------------------
  313. //
  314. // DxilLinkJob methods.
  315. //
  316. namespace {
  317. // Helper function to check type match.
  318. bool IsMatchedType(Type *Ty0, Type *Ty);
  319. StringRef RemoveNameSuffix(StringRef Name) {
  320. size_t DotPos = Name.rfind('.');
  321. if (DotPos != StringRef::npos && Name.back() != '.' &&
  322. isdigit(static_cast<unsigned char>(Name[DotPos + 1])))
  323. Name = Name.substr(0, DotPos);
  324. return Name;
  325. }
  326. bool IsMatchedStructType(StructType *ST0, StructType *ST) {
  327. StringRef Name0 = RemoveNameSuffix(ST0->getName());
  328. StringRef Name = RemoveNameSuffix(ST->getName());
  329. if (Name0 != Name)
  330. return false;
  331. if (ST0->getNumElements() != ST->getNumElements())
  332. return false;
  333. if (ST0->isLayoutIdentical(ST))
  334. return true;
  335. for (unsigned i = 0; i < ST->getNumElements(); i++) {
  336. Type *Ty = ST->getElementType(i);
  337. Type *Ty0 = ST0->getElementType(i);
  338. if (!IsMatchedType(Ty, Ty0))
  339. return false;
  340. }
  341. return true;
  342. }
  343. bool IsMatchedArrayType(ArrayType *AT0, ArrayType *AT) {
  344. if (AT0->getNumElements() != AT->getNumElements())
  345. return false;
  346. return IsMatchedType(AT0->getElementType(), AT->getElementType());
  347. }
  348. bool IsMatchedType(Type *Ty0, Type *Ty) {
  349. if (Ty0->isStructTy() && Ty->isStructTy()) {
  350. StructType *ST0 = cast<StructType>(Ty0);
  351. StructType *ST = cast<StructType>(Ty);
  352. return IsMatchedStructType(ST0, ST);
  353. }
  354. if (Ty0->isArrayTy() && Ty->isArrayTy()) {
  355. ArrayType *AT0 = cast<ArrayType>(Ty0);
  356. ArrayType *AT = cast<ArrayType>(Ty);
  357. return IsMatchedArrayType(AT0, AT);
  358. }
  359. if (Ty0->isPointerTy() && Ty->isPointerTy()) {
  360. if (Ty0->getPointerAddressSpace() != Ty->getPointerAddressSpace())
  361. return false;
  362. return IsMatchedType(Ty0->getPointerElementType(),
  363. Ty->getPointerElementType());
  364. }
  365. return Ty0 == Ty;
  366. }
  367. } // namespace
  368. bool DxilLinkJob::AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV) {
  369. if (m_resourceMap.count(res->GetGlobalName())) {
  370. DxilResourceBase *res0 = m_resourceMap[res->GetGlobalName()].first;
  371. Type *Ty0 = res0->GetGlobalSymbol()->getType()->getPointerElementType();
  372. Type *Ty = res->GetGlobalSymbol()->getType()->getPointerElementType();
  373. // Make sure res0 match res.
  374. bool bMatch = IsMatchedType(Ty0, Ty);
  375. if (!bMatch) {
  376. // Report error.
  377. m_ctx.emitError(Twine(kRedefineResource) + res->GetResClassName() + " for " +
  378. res->GetGlobalName());
  379. return false;
  380. }
  381. } else {
  382. m_resourceMap[res->GetGlobalName()] = std::make_pair(res, GV);
  383. }
  384. return true;
  385. }
  386. void DxilLinkJob::AddResourceToDM(DxilModule &DM) {
  387. for (auto &it : m_resourceMap) {
  388. DxilResourceBase *res = it.second.first;
  389. GlobalVariable *GV = it.second.second;
  390. unsigned ID = 0;
  391. DxilResourceBase *basePtr = nullptr;
  392. switch (res->GetClass()) {
  393. case DXIL::ResourceClass::UAV: {
  394. std::unique_ptr<DxilResource> pUAV = llvm::make_unique<DxilResource>();
  395. DxilResource *ptr = pUAV.get();
  396. // Copy the content.
  397. *ptr = *(static_cast<DxilResource *>(res));
  398. ID = DM.AddUAV(std::move(pUAV));
  399. basePtr = &DM.GetUAV(ID);
  400. } break;
  401. case DXIL::ResourceClass::SRV: {
  402. std::unique_ptr<DxilResource> pSRV = llvm::make_unique<DxilResource>();
  403. DxilResource *ptr = pSRV.get();
  404. // Copy the content.
  405. *ptr = *(static_cast<DxilResource *>(res));
  406. ID = DM.AddSRV(std::move(pSRV));
  407. basePtr = &DM.GetSRV(ID);
  408. } break;
  409. case DXIL::ResourceClass::CBuffer: {
  410. std::unique_ptr<DxilCBuffer> pCBuf = llvm::make_unique<DxilCBuffer>();
  411. DxilCBuffer *ptr = pCBuf.get();
  412. // Copy the content.
  413. *ptr = *(static_cast<DxilCBuffer *>(res));
  414. ID = DM.AddCBuffer(std::move(pCBuf));
  415. basePtr = &DM.GetCBuffer(ID);
  416. } break;
  417. case DXIL::ResourceClass::Sampler: {
  418. std::unique_ptr<DxilSampler> pSampler = llvm::make_unique<DxilSampler>();
  419. DxilSampler *ptr = pSampler.get();
  420. // Copy the content.
  421. *ptr = *(static_cast<DxilSampler *>(res));
  422. ID = DM.AddSampler(std::move(pSampler));
  423. basePtr = &DM.GetSampler(ID);
  424. }
  425. default:
  426. DXASSERT(res->GetClass() == DXIL::ResourceClass::Sampler,
  427. "else invalid resource");
  428. break;
  429. }
  430. // Update ID.
  431. basePtr->SetID(ID);
  432. Constant *rangeID = ConstantInt::get(GV->getType()->getElementType(), ID);
  433. for (User *U : GV->users()) {
  434. LoadInst *LI = cast<LoadInst>(U);
  435. LI->replaceAllUsesWith(rangeID);
  436. }
  437. }
  438. }
  439. std::unique_ptr<Module>
  440. DxilLinkJob::Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
  441. StringRef profile) {
  442. Function *entryFunc = entryLinkPair.first->func;
  443. DxilModule &entryDM = entryLinkPair.second->GetDxilModule();
  444. if (!entryDM.HasDxilFunctionProps(entryFunc)) {
  445. // Cannot get function props.
  446. m_ctx.emitError(Twine(kNoEntryProps) + entryFunc->getName());
  447. return nullptr;
  448. }
  449. DxilFunctionProps props = entryDM.GetDxilFunctionProps(entryFunc);
  450. if (props.shaderKind == DXIL::ShaderKind::Library ||
  451. props.shaderKind == DXIL::ShaderKind::Invalid) {
  452. m_ctx.emitError(profile + Twine(kInvalidProfile));
  453. // Invalid profile.
  454. return nullptr;
  455. }
  456. const ShaderModel *pSM = ShaderModel::GetByName(profile.data());
  457. if (pSM->GetKind() != props.shaderKind) {
  458. // Shader kind mismatch.
  459. m_ctx.emitError(Twine(kShaderKindMismatch) + profile + " and " +
  460. ShaderModel::GetKindName(props.shaderKind));
  461. return nullptr;
  462. }
  463. // Create new module.
  464. std::unique_ptr<Module> pM =
  465. llvm::make_unique<Module>(entryFunc->getName(), entryDM.GetCtx());
  466. // Set target.
  467. pM->setTargetTriple(entryDM.GetModule()->getTargetTriple());
  468. // Add dxil operation functions before create DxilModule.
  469. for (auto &it : m_dxilFunctions) {
  470. Function *F = it.second;
  471. Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
  472. F->getName(), pM.get());
  473. NewF->setAttributes(F->getAttributes());
  474. m_newFunctions[NewF->getName()] = NewF;
  475. }
  476. // Create DxilModule.
  477. const bool bSkipInit = true;
  478. DxilModule &DM = pM->GetOrCreateDxilModule(bSkipInit);
  479. DM.SetShaderModel(pSM);
  480. // Add type sys
  481. DxilTypeSystem &typeSys = DM.GetTypeSystem();
  482. ValueToValueMapTy vmap;
  483. std::unordered_set<Function *> initFuncSet;
  484. // Add function
  485. for (auto &it : m_functionDefs) {
  486. DxilFunctionLinkInfo *linkInfo = it.first;
  487. DxilLib *pLib = it.second;
  488. DxilModule &tmpDM = pLib->GetDxilModule();
  489. DxilTypeSystem &tmpTypeSys = tmpDM.GetTypeSystem();
  490. Function *F = linkInfo->func;
  491. Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
  492. F->getName(), pM.get());
  493. NewF->setAttributes(F->getAttributes());
  494. if (!NewF->hasFnAttribute(llvm::Attribute::NoInline))
  495. NewF->addFnAttr(llvm::Attribute::AlwaysInline);
  496. if (DxilFunctionAnnotation *funcAnnotation =
  497. tmpTypeSys.GetFunctionAnnotation(F)) {
  498. // Clone funcAnnotation to typeSys.
  499. typeSys.CopyFunctionAnnotation(NewF, F, tmpTypeSys);
  500. }
  501. // Add to function map.
  502. m_newFunctions[NewF->getName()] = NewF;
  503. if (pLib->IsInitFunc(F))
  504. initFuncSet.insert(NewF);
  505. vmap[F] = NewF;
  506. }
  507. // Set Entry
  508. Function *NewEntryFunc = m_newFunctions[entryFunc->getName()];
  509. DM.SetEntryFunction(NewEntryFunc);
  510. DM.SetEntryFunctionName(entryFunc->getName());
  511. if (entryDM.HasDxilEntrySignature(entryFunc)) {
  512. // Add signature.
  513. DxilEntrySignature &entrySig = entryDM.GetDxilEntrySignature(entryFunc);
  514. std::unique_ptr<DxilEntrySignature> newSig =
  515. std::make_unique<DxilEntrySignature>(entrySig);
  516. DM.ResetEntrySignature(newSig.release());
  517. }
  518. if (NewEntryFunc->hasFnAttribute(llvm::Attribute::AlwaysInline))
  519. NewEntryFunc->removeFnAttr(llvm::Attribute::AlwaysInline);
  520. if (props.IsHS()) {
  521. Function *patchConstantFunc = props.ShaderProps.HS.patchConstantFunc;
  522. Function *newPatchConstantFunc =
  523. m_newFunctions[patchConstantFunc->getName()];
  524. props.ShaderProps.HS.patchConstantFunc = newPatchConstantFunc;
  525. if (newPatchConstantFunc->hasFnAttribute(llvm::Attribute::AlwaysInline))
  526. newPatchConstantFunc->removeFnAttr(llvm::Attribute::AlwaysInline);
  527. }
  528. // Set EntryProps
  529. DM.SetShaderProperties(&props);
  530. // Debug info.
  531. // Add global
  532. bool bSuccess = true;
  533. for (auto &it : m_functionDefs) {
  534. DxilFunctionLinkInfo *linkInfo = it.first;
  535. DxilLib *pLib = it.second;
  536. for (GlobalVariable *GV : linkInfo->usedGVs) {
  537. // Skip added globals.
  538. if (m_newGlobals.count(GV->getName())) {
  539. if (vmap.find(GV) == vmap.end()) {
  540. if (DxilResourceBase *res = pLib->GetResource(GV)) {
  541. // For resource of same name, if class and type match, just map to
  542. // same NewGV.
  543. GlobalVariable *NewGV = m_newGlobals[GV->getName()];
  544. if (AddResource(res, NewGV)) {
  545. vmap[GV] = NewGV;
  546. } else {
  547. bSuccess = false;
  548. }
  549. continue;
  550. }
  551. // Redefine of global.
  552. m_ctx.emitError(Twine(kRedefineGlobal) + GV->getName());
  553. bSuccess = false;
  554. }
  555. continue;
  556. }
  557. Constant *Initializer = nullptr;
  558. if (GV->hasInitializer())
  559. Initializer = GV->getInitializer();
  560. GlobalVariable *NewGV = new GlobalVariable(
  561. *pM, GV->getType()->getElementType(), GV->isConstant(),
  562. GV->getLinkage(), Initializer, GV->getName(),
  563. /*InsertBefore*/ nullptr, GV->getThreadLocalMode(),
  564. GV->getType()->getAddressSpace(), GV->isExternallyInitialized());
  565. m_newGlobals[GV->getName()] = NewGV;
  566. vmap[GV] = NewGV;
  567. if (DxilResourceBase *res = pLib->GetResource(GV)) {
  568. bSuccess &= AddResource(res, NewGV);
  569. }
  570. }
  571. }
  572. if (!bSuccess)
  573. return nullptr;
  574. // Clone functions.
  575. for (auto &it : m_functionDefs) {
  576. DxilFunctionLinkInfo *linkInfo = it.first;
  577. Function *F = linkInfo->func;
  578. Function *NewF = m_newFunctions[F->getName()];
  579. // Add dxil functions to vmap.
  580. for (Function *UsedF : linkInfo->usedFunctions) {
  581. if (!vmap.count(UsedF)) {
  582. // Extern function need match by name
  583. DXASSERT(m_newFunctions.count(UsedF->getName()),
  584. "Must have new function.");
  585. vmap[UsedF] = m_newFunctions[UsedF->getName()];
  586. }
  587. }
  588. CloneFunction(F, NewF, vmap);
  589. }
  590. // Call global constrctor.
  591. IRBuilder<> Builder(
  592. DM.GetEntryFunction()->getEntryBlock().getFirstInsertionPt());
  593. for (auto &it : m_functionDefs) {
  594. DxilFunctionLinkInfo *linkInfo = it.first;
  595. DxilLib *pLib = it.second;
  596. Function *F = linkInfo->func;
  597. if (pLib->IsInitFunc(F)) {
  598. Function *NewF = m_newFunctions[F->getName()];
  599. Builder.CreateCall(NewF);
  600. }
  601. }
  602. // Refresh intrinsic cache.
  603. DM.GetOP()->RefreshCache();
  604. // Add resource to DM.
  605. // This should be after functions cloned.
  606. AddResourceToDM(DM);
  607. RunPreparePass(*pM);
  608. return pM;
  609. }
  610. void DxilLinkJob::AddFunction(
  611. std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair) {
  612. m_functionDefs[linkPair.first] = linkPair.second;
  613. }
  614. void DxilLinkJob::AddFunction(llvm::Function *F) {
  615. m_dxilFunctions[F->getName()] = F;
  616. }
  617. void DxilLinkJob::RunPreparePass(Module &M) {
  618. legacy::PassManager PM;
  619. PM.add(createAlwaysInlinerPass(/*InsertLifeTime*/ false));
  620. PM.add(createDxilDeadFunctionEliminationPass());
  621. // mem2reg.
  622. PM.add(createPromoteMemoryToRegisterPass());
  623. // Remove unused functions.
  624. PM.add(createDeadCodeEliminationPass());
  625. PM.add(createGlobalDCEPass());
  626. PM.add(createSimplifyInstPass());
  627. PM.add(createCFGSimplificationPass());
  628. PM.add(createDxilCondenseResourcesPass());
  629. PM.add(createDxilFinalizeModulePass());
  630. PM.add(createComputeViewIdStatePass());
  631. PM.add(createDxilDeadFunctionEliminationPass());
  632. PM.add(createNoPausePassesPass());
  633. PM.add(createDxilEmitMetadataPass());
  634. PM.run(M);
  635. }
  636. //------------------------------------------------------------------------------
  637. //
  638. // DxilLinkerImpl methods.
  639. //
  640. bool DxilLinkerImpl::HasLibNameRegistered(StringRef name) {
  641. return m_LibMap.count(name);
  642. }
  643. bool DxilLinkerImpl::RegisterLib(StringRef name,
  644. std::unique_ptr<llvm::Module> pModule,
  645. std::unique_ptr<llvm::Module> pDebugModule) {
  646. if (m_LibMap.count(name))
  647. return false;
  648. std::unique_ptr<llvm::Module> pM =
  649. pDebugModule ? std::move(pDebugModule) : std::move(pModule);
  650. if (!pM)
  651. return false;
  652. pM->setModuleIdentifier(name);
  653. std::unique_ptr<DxilLib> pLib =
  654. std::make_unique<DxilLib>(std::move(pM));
  655. m_LibMap[name] = std::move(pLib);
  656. return true;
  657. }
  658. bool DxilLinkerImpl::AttachLib(StringRef name) {
  659. auto iter = m_LibMap.find(name);
  660. if (iter == m_LibMap.end()) {
  661. return false;
  662. }
  663. return AttachLib(iter->second.get());
  664. }
  665. bool DxilLinkerImpl::DetachLib(StringRef name) {
  666. auto iter = m_LibMap.find(name);
  667. if (iter == m_LibMap.end()) {
  668. return false;
  669. }
  670. return DetachLib(iter->second.get());
  671. }
  672. void DxilLinkerImpl::DetachAll() {
  673. m_functionNameMap.clear();
  674. m_attachedLibs.clear();
  675. }
  676. bool DxilLinkerImpl::AttachLib(DxilLib *lib) {
  677. if (!lib) {
  678. // Invalid arg.
  679. return false;
  680. }
  681. if (m_attachedLibs.count(lib))
  682. return false;
  683. StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &funcTable =
  684. lib->GetFunctionTable();
  685. bool bSuccess = true;
  686. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  687. StringRef name = it->getKey();
  688. if (m_functionNameMap.count(name)) {
  689. // Redefine of function.
  690. m_ctx.emitError(Twine(kRedefineFunction) + name);
  691. bSuccess = false;
  692. continue;
  693. }
  694. m_functionNameMap[name] = std::make_pair(it->second.get(), lib);
  695. }
  696. if (bSuccess) {
  697. m_attachedLibs.insert(lib);
  698. } else {
  699. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  700. StringRef name = it->getKey();
  701. auto iter = m_functionNameMap.find(name);
  702. if (iter == m_functionNameMap.end())
  703. continue;
  704. // Remove functions of lib.
  705. if (m_functionNameMap[name].second == lib)
  706. m_functionNameMap.erase(name);
  707. }
  708. }
  709. return bSuccess;
  710. }
  711. bool DxilLinkerImpl::DetachLib(DxilLib *lib) {
  712. if (!lib) {
  713. // Invalid arg.
  714. return false;
  715. }
  716. if (!m_attachedLibs.count(lib))
  717. return false;
  718. m_attachedLibs.erase(lib);
  719. // Remove functions from lib.
  720. StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &funcTable =
  721. lib->GetFunctionTable();
  722. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  723. StringRef name = it->getKey();
  724. m_functionNameMap.erase(name);
  725. }
  726. return true;
  727. }
  728. bool DxilLinkerImpl::AddFunctions(SmallVector<StringRef, 4> &workList,
  729. DenseSet<DxilLib *> &libSet,
  730. StringSet<> &addedFunctionSet,
  731. DxilLinkJob &linkJob, bool bLazyLoadDone) {
  732. while (!workList.empty()) {
  733. StringRef name = workList.pop_back_val();
  734. // Ignore added function.
  735. if (addedFunctionSet.count(name))
  736. continue;
  737. if (!m_functionNameMap.count(name)) {
  738. // Cannot find function, report error.
  739. m_ctx.emitError(Twine(kUndefFunction) + name);
  740. return false;
  741. }
  742. std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair =
  743. m_functionNameMap[name];
  744. linkJob.AddFunction(linkPair);
  745. DxilLib *pLib = linkPair.second;
  746. libSet.insert(pLib);
  747. if (!bLazyLoadDone) {
  748. Function *F = linkPair.first->func;
  749. pLib->LazyLoadFunction(F);
  750. }
  751. for (Function *F : linkPair.first->usedFunctions) {
  752. if (hlsl::OP::IsDxilOpFunc(F)) {
  753. // Add dxil operations directly.
  754. linkJob.AddFunction(F);
  755. } else {
  756. // Push function name to work list.
  757. workList.emplace_back(F->getName());
  758. }
  759. }
  760. addedFunctionSet.insert(name);
  761. }
  762. return true;
  763. }
  764. std::unique_ptr<llvm::Module> DxilLinkerImpl::Link(StringRef entry,
  765. StringRef profile) {
  766. StringSet<> addedFunctionSet;
  767. SmallVector<StringRef, 4> workList;
  768. workList.emplace_back(entry);
  769. DxilLinkJob linkJob(m_ctx);
  770. DenseSet<DxilLib *> libSet;
  771. if (!AddFunctions(workList, libSet, addedFunctionSet, linkJob,
  772. /*bLazyLoadDone*/ false))
  773. return nullptr;
  774. // Save global users.
  775. for (auto &pLib : libSet) {
  776. pLib->BuildGlobalUsage();
  777. }
  778. // Save global ctor users.
  779. for (auto &pLib : libSet) {
  780. pLib->CollectUsedInitFunctions(addedFunctionSet, workList);
  781. }
  782. // Add init functions if used.
  783. // All init function already loaded in BuildGlobalUsage, so set bLazyLoad
  784. // false here.
  785. if (!AddFunctions(workList, libSet, addedFunctionSet, linkJob,
  786. /*bLazyLoadDone*/ true))
  787. return nullptr;
  788. std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair =
  789. m_functionNameMap[entry];
  790. return linkJob.Link(entryLinkPair, profile);
  791. }
  792. namespace hlsl {
  793. DxilLinker *DxilLinker::CreateLinker(LLVMContext &Ctx) {
  794. return new DxilLinkerImpl(Ctx);
  795. }
  796. } // namespace hlsl