DxilLinker.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  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/DXIL/DxilCBuffer.h"
  11. #include "dxc/DXIL/DxilFunctionProps.h"
  12. #include "dxc/DXIL/DxilEntryProps.h"
  13. #include "dxc/DXIL/DxilModule.h"
  14. #include "dxc/DXIL/DxilOperations.h"
  15. #include "dxc/DXIL/DxilResource.h"
  16. #include "dxc/DXIL/DxilSampler.h"
  17. #include "dxc/DXIL/DxilUtil.h"
  18. #include "dxc/Support/Global.h"
  19. #include "llvm/ADT/StringSet.h"
  20. #include "llvm/ADT/DenseSet.h"
  21. #include "llvm/IR/Constants.h"
  22. #include "llvm/IR/IRBuilder.h"
  23. #include "llvm/IR/Instructions.h"
  24. #include "llvm/IR/Module.h"
  25. #include "llvm/Transforms/Utils/Cloning.h"
  26. #include "llvm/ADT/StringMap.h"
  27. #include "llvm/ADT/SetVector.h"
  28. #include "llvm/ADT/STLExtras.h"
  29. #include "llvm/Support/raw_ostream.h"
  30. #include <memory>
  31. #include <vector>
  32. #include "dxc/DxilContainer/DxilContainer.h"
  33. #include "llvm/IR/DiagnosticPrinter.h"
  34. #include "llvm/IR/LLVMContext.h"
  35. #include "llvm/IR/DebugInfo.h"
  36. #include "dxc/HLSL/DxilGenerationPass.h"
  37. #include "llvm/IR/LegacyPassManager.h"
  38. #include "llvm/Transforms/IPO.h"
  39. #include "llvm/Transforms/Scalar.h"
  40. #include "dxc/HLSL/DxilExportMap.h"
  41. #include "dxc/HLSL/ComputeViewIdState.h"
  42. using namespace llvm;
  43. using namespace hlsl;
  44. namespace {
  45. void CollectUsedFunctions(Constant *C,
  46. std::unordered_set<Function *> &funcSet) {
  47. for (User *U : C->users()) {
  48. if (Instruction *I = dyn_cast<Instruction>(U)) {
  49. funcSet.insert(I->getParent()->getParent());
  50. } else {
  51. Constant *CU = cast<Constant>(U);
  52. CollectUsedFunctions(CU, funcSet);
  53. }
  54. }
  55. }
  56. template <class T>
  57. void AddResourceMap(
  58. const std::vector<std::unique_ptr<T>> &resTab, DXIL::ResourceClass resClass,
  59. std::unordered_map<const llvm::Constant *, DxilResourceBase *> &resMap,
  60. DxilModule &DM) {
  61. for (auto &Res : resTab) {
  62. resMap[Res->GetGlobalSymbol()] = Res.get();
  63. }
  64. }
  65. void CloneFunction(Function *F, Function *NewF, ValueToValueMapTy &vmap,
  66. hlsl::DxilTypeSystem *TypeSys = nullptr,
  67. hlsl::DxilTypeSystem *SrcTypeSys = nullptr) {
  68. SmallVector<ReturnInst *, 2> Returns;
  69. // Map params.
  70. auto paramIt = NewF->arg_begin();
  71. for (Argument &param : F->args()) {
  72. vmap[&param] = (paramIt++);
  73. }
  74. llvm::CloneFunctionInto(NewF, F, vmap, /*ModuleLevelChanges*/ true, Returns);
  75. if (TypeSys) {
  76. if (SrcTypeSys == nullptr)
  77. SrcTypeSys = TypeSys;
  78. TypeSys->CopyFunctionAnnotation(NewF, F, *SrcTypeSys);
  79. }
  80. // Remove params from vmap.
  81. for (Argument &param : F->args()) {
  82. vmap.erase(&param);
  83. }
  84. }
  85. } // namespace
  86. namespace {
  87. struct DxilFunctionLinkInfo {
  88. DxilFunctionLinkInfo(llvm::Function *F);
  89. llvm::Function *func;
  90. std::unordered_set<llvm::Function *> usedFunctions;
  91. std::unordered_set<llvm::GlobalVariable *> usedGVs;
  92. std::unordered_set<DxilResourceBase *> usedResources;
  93. };
  94. // Library to link.
  95. class DxilLib {
  96. public:
  97. DxilLib(std::unique_ptr<llvm::Module> pModule);
  98. virtual ~DxilLib() {}
  99. bool HasFunction(std::string &name);
  100. llvm::StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &GetFunctionTable() {
  101. return m_functionNameMap;
  102. }
  103. bool IsInitFunc(llvm::Function *F);
  104. bool IsResourceGlobal(const llvm::Constant *GV);
  105. DxilResourceBase *GetResource(const llvm::Constant *GV);
  106. DxilModule &GetDxilModule() { return m_DM; }
  107. void LazyLoadFunction(Function *F);
  108. void BuildGlobalUsage();
  109. void CollectUsedInitFunctions(StringSet<> &addedFunctionSet,
  110. SmallVector<StringRef, 4> &workList);
  111. private:
  112. std::unique_ptr<llvm::Module> m_pModule;
  113. DxilModule &m_DM;
  114. // Map from name to Link info for extern functions.
  115. llvm::StringMap<std::unique_ptr<DxilFunctionLinkInfo>> m_functionNameMap;
  116. // Map from resource link global to resource.
  117. std::unordered_map<const llvm::Constant *, DxilResourceBase *> m_resourceMap;
  118. // Set of initialize functions for global variable.
  119. std::unordered_set<llvm::Function *> m_initFuncSet;
  120. };
  121. struct DxilLinkJob;
  122. class DxilLinkerImpl : public hlsl::DxilLinker {
  123. public:
  124. DxilLinkerImpl(LLVMContext &Ctx, unsigned valMajor, unsigned valMinor) : DxilLinker(Ctx, valMajor, valMinor) {}
  125. virtual ~DxilLinkerImpl() {}
  126. bool HasLibNameRegistered(StringRef name) override;
  127. bool RegisterLib(StringRef name, std::unique_ptr<llvm::Module> pModule,
  128. std::unique_ptr<llvm::Module> pDebugModule) override;
  129. bool AttachLib(StringRef name) override;
  130. bool DetachLib(StringRef name) override;
  131. void DetachAll() override;
  132. std::unique_ptr<llvm::Module>
  133. Link(StringRef entry, StringRef profile, dxilutil::ExportMap &exportMap) override;
  134. private:
  135. bool AttachLib(DxilLib *lib);
  136. bool DetachLib(DxilLib *lib);
  137. bool AddFunctions(SmallVector<StringRef, 4> &workList,
  138. DenseSet<DxilLib *> &libSet, StringSet<> &addedFunctionSet,
  139. DxilLinkJob &linkJob, bool bLazyLoadDone,
  140. bool bAllowFuncionDecls);
  141. // Attached libs to link.
  142. std::unordered_set<DxilLib *> m_attachedLibs;
  143. // Owner of all DxilLib.
  144. StringMap<std::unique_ptr<DxilLib>> m_LibMap;
  145. llvm::StringMap<std::pair<DxilFunctionLinkInfo *, DxilLib *>>
  146. m_functionNameMap;
  147. };
  148. } // namespace
  149. //------------------------------------------------------------------------------
  150. //
  151. // DxilFunctionLinkInfo methods.
  152. //
  153. DxilFunctionLinkInfo::DxilFunctionLinkInfo(Function *F) : func(F) {
  154. DXASSERT_NOMSG(F);
  155. }
  156. //------------------------------------------------------------------------------
  157. //
  158. // DxilLib methods.
  159. //
  160. DxilLib::DxilLib(std::unique_ptr<llvm::Module> pModule)
  161. : m_pModule(std::move(pModule)), m_DM(m_pModule->GetOrCreateDxilModule()) {
  162. Module &M = *m_pModule;
  163. const std::string &MID = M.getModuleIdentifier();
  164. // Collect function defines.
  165. for (Function &F : M.functions()) {
  166. if (F.isDeclaration())
  167. continue;
  168. if (F.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage) {
  169. // Add prefix to internal function.
  170. F.setName(MID + F.getName());
  171. }
  172. m_functionNameMap[F.getName()] =
  173. llvm::make_unique<DxilFunctionLinkInfo>(&F);
  174. }
  175. // Update internal global name.
  176. for (GlobalVariable &GV : M.globals()) {
  177. if (GV.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage) {
  178. // Add prefix to internal global.
  179. GV.setName(MID + GV.getName());
  180. }
  181. }
  182. }
  183. void DxilLib::LazyLoadFunction(Function *F) {
  184. DXASSERT(m_functionNameMap.count(F->getName()), "else invalid Function");
  185. DxilFunctionLinkInfo *linkInfo = m_functionNameMap[F->getName()].get();
  186. std::error_code EC = F->materialize();
  187. DXASSERT_LOCALVAR(EC, !EC, "else fail to materialize");
  188. // Build used functions for F.
  189. for (auto &BB : F->getBasicBlockList()) {
  190. for (auto &I : BB.getInstList()) {
  191. if (CallInst *CI = dyn_cast<CallInst>(&I)) {
  192. linkInfo->usedFunctions.insert(CI->getCalledFunction());
  193. }
  194. }
  195. }
  196. if (m_DM.HasDxilFunctionProps(F)) {
  197. DxilFunctionProps &props = m_DM.GetDxilFunctionProps(F);
  198. if (props.IsHS()) {
  199. // Add patch constant function to usedFunctions of entry.
  200. Function *patchConstantFunc = props.ShaderProps.HS.patchConstantFunc;
  201. linkInfo->usedFunctions.insert(patchConstantFunc);
  202. }
  203. }
  204. // Used globals will be build before link.
  205. }
  206. void DxilLib::BuildGlobalUsage() {
  207. Module &M = *m_pModule;
  208. // Collect init functions for static globals.
  209. if (GlobalVariable *Ctors = M.getGlobalVariable("llvm.global_ctors")) {
  210. if (ConstantArray *CA = dyn_cast<ConstantArray>(Ctors->getInitializer())) {
  211. for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e;
  212. ++i) {
  213. if (isa<ConstantAggregateZero>(*i))
  214. continue;
  215. ConstantStruct *CS = cast<ConstantStruct>(*i);
  216. if (isa<ConstantPointerNull>(CS->getOperand(1)))
  217. continue;
  218. // Must have a function or null ptr.
  219. if (!isa<Function>(CS->getOperand(1)))
  220. continue;
  221. Function *Ctor = cast<Function>(CS->getOperand(1));
  222. assert(Ctor->getReturnType()->isVoidTy() && Ctor->arg_size() == 0 &&
  223. "function type must be void (void)");
  224. // Add Ctor.
  225. m_initFuncSet.insert(Ctor);
  226. LazyLoadFunction(Ctor);
  227. }
  228. }
  229. }
  230. // Build used globals.
  231. for (GlobalVariable &GV : M.globals()) {
  232. std::unordered_set<Function *> funcSet;
  233. CollectUsedFunctions(&GV, funcSet);
  234. for (Function *F : funcSet) {
  235. DXASSERT(m_functionNameMap.count(F->getName()), "must exist in table");
  236. DxilFunctionLinkInfo *linkInfo = m_functionNameMap[F->getName()].get();
  237. linkInfo->usedGVs.insert(&GV);
  238. }
  239. }
  240. // Build resource map.
  241. AddResourceMap(m_DM.GetUAVs(), DXIL::ResourceClass::UAV, m_resourceMap, m_DM);
  242. AddResourceMap(m_DM.GetSRVs(), DXIL::ResourceClass::SRV, m_resourceMap, m_DM);
  243. AddResourceMap(m_DM.GetCBuffers(), DXIL::ResourceClass::CBuffer,
  244. m_resourceMap, m_DM);
  245. AddResourceMap(m_DM.GetSamplers(), DXIL::ResourceClass::Sampler,
  246. m_resourceMap, m_DM);
  247. }
  248. void DxilLib::CollectUsedInitFunctions(StringSet<> &addedFunctionSet,
  249. SmallVector<StringRef, 4> &workList) {
  250. // Add init functions to used functions.
  251. for (Function *Ctor : m_initFuncSet) {
  252. DXASSERT(m_functionNameMap.count(Ctor->getName()),
  253. "must exist in internal table");
  254. DxilFunctionLinkInfo *linkInfo = m_functionNameMap[Ctor->getName()].get();
  255. // If function other than Ctor used GV of Ctor.
  256. // Add Ctor to usedFunctions for it.
  257. for (GlobalVariable *GV : linkInfo->usedGVs) {
  258. std::unordered_set<Function *> funcSet;
  259. CollectUsedFunctions(GV, funcSet);
  260. bool bAdded = false;
  261. for (Function *F : funcSet) {
  262. if (F == Ctor)
  263. continue;
  264. // If F is added for link, add init func to workList.
  265. if (addedFunctionSet.count(F->getName())) {
  266. workList.emplace_back(Ctor->getName());
  267. bAdded = true;
  268. break;
  269. }
  270. }
  271. if (bAdded)
  272. break;
  273. }
  274. }
  275. }
  276. bool DxilLib::HasFunction(std::string &name) {
  277. return m_functionNameMap.count(name);
  278. }
  279. bool DxilLib::IsInitFunc(llvm::Function *F) { return m_initFuncSet.count(F); }
  280. bool DxilLib::IsResourceGlobal(const llvm::Constant *GV) {
  281. return m_resourceMap.count(GV);
  282. }
  283. DxilResourceBase *DxilLib::GetResource(const llvm::Constant *GV) {
  284. if (IsResourceGlobal(GV))
  285. return m_resourceMap[GV];
  286. else
  287. return nullptr;
  288. }
  289. namespace {
  290. // Create module from link defines.
  291. struct DxilLinkJob {
  292. DxilLinkJob(LLVMContext &Ctx, dxilutil::ExportMap &exportMap,
  293. unsigned valMajor, unsigned valMinor)
  294. : m_ctx(Ctx), m_exportMap(exportMap), m_valMajor(valMajor),
  295. m_valMinor(valMinor) {}
  296. std::unique_ptr<llvm::Module>
  297. Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
  298. const ShaderModel *pSM);
  299. std::unique_ptr<llvm::Module> LinkToLib(const ShaderModel *pSM);
  300. void StripDeadDebugInfo(llvm::Module &M);
  301. void RunPreparePass(llvm::Module &M);
  302. void AddFunction(std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair);
  303. void AddFunction(llvm::Function *F);
  304. private:
  305. void LinkNamedMDNodes(Module *pM, ValueToValueMapTy &vmap);
  306. void AddFunctionDecls(Module *pM);
  307. bool AddGlobals(DxilModule &DM, ValueToValueMapTy &vmap);
  308. void CloneFunctions(ValueToValueMapTy &vmap);
  309. void AddFunctions(DxilModule &DM, ValueToValueMapTy &vmap,
  310. std::unordered_set<Function *> &initFuncSet);
  311. bool AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV);
  312. void AddResourceToDM(DxilModule &DM);
  313. std::unordered_map<DxilFunctionLinkInfo *, DxilLib *> m_functionDefs;
  314. llvm::StringMap<llvm::Function *> m_functionDecls;
  315. // New created functions.
  316. llvm::StringMap<llvm::Function *> m_newFunctions;
  317. // New created globals.
  318. llvm::StringMap<llvm::GlobalVariable *> m_newGlobals;
  319. // Map for resource.
  320. llvm::StringMap<std::pair<DxilResourceBase *, llvm::GlobalVariable *>>
  321. m_resourceMap;
  322. LLVMContext &m_ctx;
  323. dxilutil::ExportMap &m_exportMap;
  324. unsigned m_valMajor, m_valMinor;
  325. };
  326. } // namespace
  327. namespace {
  328. const char kUndefFunction[] = "Cannot find definition of function ";
  329. const char kRedefineFunction[] = "Definition already exists for function ";
  330. const char kRedefineGlobal[] = "Definition already exists for global variable ";
  331. const char kInvalidProfile[] = " is invalid profile to link";
  332. const char kExportOnlyForLib[] = "export map is only for library";
  333. const char kShaderKindMismatch[] =
  334. "Profile mismatch between entry function and target profile:";
  335. const char kNoEntryProps[] =
  336. "Cannot find function property for entry function ";
  337. const char kRedefineResource[] =
  338. "Resource already exists as ";
  339. const char kInvalidValidatorVersion[] = "Validator version does not support target profile ";
  340. const char kExportNameCollision[] = "Export name collides with another export: ";
  341. const char kExportFunctionMissing[] = "Could not find target for export: ";
  342. const char kNoFunctionsToExport[] = "Library has no functions to export";
  343. } // namespace
  344. //------------------------------------------------------------------------------
  345. //
  346. // DxilLinkJob methods.
  347. //
  348. namespace {
  349. // Helper function to check type match.
  350. bool IsMatchedType(Type *Ty0, Type *Ty);
  351. StringRef RemoveNameSuffix(StringRef Name) {
  352. size_t DotPos = Name.rfind('.');
  353. if (DotPos != StringRef::npos && Name.back() != '.' &&
  354. isdigit(static_cast<unsigned char>(Name[DotPos + 1])))
  355. Name = Name.substr(0, DotPos);
  356. return Name;
  357. }
  358. bool IsMatchedStructType(StructType *ST0, StructType *ST) {
  359. StringRef Name0 = RemoveNameSuffix(ST0->getName());
  360. StringRef Name = RemoveNameSuffix(ST->getName());
  361. if (Name0 != Name)
  362. return false;
  363. if (ST0->getNumElements() != ST->getNumElements())
  364. return false;
  365. if (ST0->isLayoutIdentical(ST))
  366. return true;
  367. for (unsigned i = 0; i < ST->getNumElements(); i++) {
  368. Type *Ty = ST->getElementType(i);
  369. Type *Ty0 = ST0->getElementType(i);
  370. if (!IsMatchedType(Ty, Ty0))
  371. return false;
  372. }
  373. return true;
  374. }
  375. bool IsMatchedArrayType(ArrayType *AT0, ArrayType *AT) {
  376. if (AT0->getNumElements() != AT->getNumElements())
  377. return false;
  378. return IsMatchedType(AT0->getElementType(), AT->getElementType());
  379. }
  380. bool IsMatchedType(Type *Ty0, Type *Ty) {
  381. if (Ty0->isStructTy() && Ty->isStructTy()) {
  382. StructType *ST0 = cast<StructType>(Ty0);
  383. StructType *ST = cast<StructType>(Ty);
  384. return IsMatchedStructType(ST0, ST);
  385. }
  386. if (Ty0->isArrayTy() && Ty->isArrayTy()) {
  387. ArrayType *AT0 = cast<ArrayType>(Ty0);
  388. ArrayType *AT = cast<ArrayType>(Ty);
  389. return IsMatchedArrayType(AT0, AT);
  390. }
  391. if (Ty0->isPointerTy() && Ty->isPointerTy()) {
  392. if (Ty0->getPointerAddressSpace() != Ty->getPointerAddressSpace())
  393. return false;
  394. return IsMatchedType(Ty0->getPointerElementType(),
  395. Ty->getPointerElementType());
  396. }
  397. return Ty0 == Ty;
  398. }
  399. } // namespace
  400. bool DxilLinkJob::AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV) {
  401. if (m_resourceMap.count(res->GetGlobalName())) {
  402. DxilResourceBase *res0 = m_resourceMap[res->GetGlobalName()].first;
  403. Type *Ty0 = res0->GetGlobalSymbol()->getType()->getPointerElementType();
  404. Type *Ty = res->GetGlobalSymbol()->getType()->getPointerElementType();
  405. // Make sure res0 match res.
  406. bool bMatch = IsMatchedType(Ty0, Ty);
  407. if (!bMatch) {
  408. // Report error.
  409. m_ctx.emitError(Twine(kRedefineResource) + res->GetResClassName() + " for " +
  410. res->GetGlobalName());
  411. return false;
  412. }
  413. } else {
  414. m_resourceMap[res->GetGlobalName()] = std::make_pair(res, GV);
  415. }
  416. return true;
  417. }
  418. void DxilLinkJob::AddResourceToDM(DxilModule &DM) {
  419. for (auto &it : m_resourceMap) {
  420. DxilResourceBase *res = it.second.first;
  421. GlobalVariable *GV = it.second.second;
  422. unsigned ID = 0;
  423. DxilResourceBase *basePtr = nullptr;
  424. switch (res->GetClass()) {
  425. case DXIL::ResourceClass::UAV: {
  426. std::unique_ptr<DxilResource> pUAV = llvm::make_unique<DxilResource>();
  427. DxilResource *ptr = pUAV.get();
  428. // Copy the content.
  429. *ptr = *(static_cast<DxilResource *>(res));
  430. ID = DM.AddUAV(std::move(pUAV));
  431. basePtr = &DM.GetUAV(ID);
  432. } break;
  433. case DXIL::ResourceClass::SRV: {
  434. std::unique_ptr<DxilResource> pSRV = llvm::make_unique<DxilResource>();
  435. DxilResource *ptr = pSRV.get();
  436. // Copy the content.
  437. *ptr = *(static_cast<DxilResource *>(res));
  438. ID = DM.AddSRV(std::move(pSRV));
  439. basePtr = &DM.GetSRV(ID);
  440. } break;
  441. case DXIL::ResourceClass::CBuffer: {
  442. std::unique_ptr<DxilCBuffer> pCBuf = llvm::make_unique<DxilCBuffer>();
  443. DxilCBuffer *ptr = pCBuf.get();
  444. // Copy the content.
  445. *ptr = *(static_cast<DxilCBuffer *>(res));
  446. ID = DM.AddCBuffer(std::move(pCBuf));
  447. basePtr = &DM.GetCBuffer(ID);
  448. } break;
  449. case DXIL::ResourceClass::Sampler: {
  450. std::unique_ptr<DxilSampler> pSampler = llvm::make_unique<DxilSampler>();
  451. DxilSampler *ptr = pSampler.get();
  452. // Copy the content.
  453. *ptr = *(static_cast<DxilSampler *>(res));
  454. ID = DM.AddSampler(std::move(pSampler));
  455. basePtr = &DM.GetSampler(ID);
  456. }
  457. default:
  458. DXASSERT(res->GetClass() == DXIL::ResourceClass::Sampler,
  459. "else invalid resource");
  460. break;
  461. }
  462. // Update ID.
  463. basePtr->SetID(ID);
  464. basePtr->SetGlobalSymbol(GV);
  465. DM.GetLLVMUsed().push_back(GV);
  466. }
  467. // Prevent global vars used for resources from being deleted through optimizations
  468. // while we still have hidden uses (pointers in resource vectors).
  469. DM.EmitLLVMUsed();
  470. }
  471. void DxilLinkJob::LinkNamedMDNodes(Module *pM, ValueToValueMapTy &vmap) {
  472. SetVector<Module *> moduleSet;
  473. for (auto &it : m_functionDefs) {
  474. DxilLib *pLib = it.second;
  475. moduleSet.insert(pLib->GetDxilModule().GetModule());
  476. }
  477. // Link normal NamedMDNode.
  478. // TODO: skip duplicate operands.
  479. for (Module *pSrcM : moduleSet) {
  480. const NamedMDNode *pSrcModFlags = pSrcM->getModuleFlagsMetadata();
  481. for (const NamedMDNode &NMD : pSrcM->named_metadata()) {
  482. // Don't link module flags here. Do them separately.
  483. if (&NMD == pSrcModFlags)
  484. continue;
  485. // Skip dxil metadata which will be regenerated.
  486. if (DxilMDHelper::IsKnownNamedMetaData(NMD))
  487. continue;
  488. NamedMDNode *DestNMD = pM->getOrInsertNamedMetadata(NMD.getName());
  489. // Add Src elements into Dest node.
  490. for (const MDNode *op : NMD.operands())
  491. DestNMD->addOperand(MapMetadata(op, vmap, RF_None, /*TypeMap*/ nullptr,
  492. /*ValMaterializer*/ nullptr));
  493. }
  494. }
  495. // Link mod flags.
  496. SetVector<MDNode *> flagSet;
  497. for (Module *pSrcM : moduleSet) {
  498. NamedMDNode *pSrcModFlags = pSrcM->getModuleFlagsMetadata();
  499. if (pSrcModFlags) {
  500. for (MDNode *flag : pSrcModFlags->operands()) {
  501. flagSet.insert(flag);
  502. }
  503. }
  504. }
  505. // TODO: check conflict in flags.
  506. if (!flagSet.empty()) {
  507. NamedMDNode *ModFlags = pM->getOrInsertModuleFlagsMetadata();
  508. for (MDNode *flag : flagSet) {
  509. ModFlags->addOperand(flag);
  510. }
  511. }
  512. }
  513. void DxilLinkJob::AddFunctionDecls(Module *pM) {
  514. for (auto &it : m_functionDecls) {
  515. Function *F = it.second;
  516. Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
  517. F->getName(), pM);
  518. NewF->setAttributes(F->getAttributes());
  519. m_newFunctions[NewF->getName()] = NewF;
  520. }
  521. }
  522. bool DxilLinkJob::AddGlobals(DxilModule &DM, ValueToValueMapTy &vmap) {
  523. DxilTypeSystem &typeSys = DM.GetTypeSystem();
  524. Module *pM = DM.GetModule();
  525. bool bSuccess = true;
  526. for (auto &it : m_functionDefs) {
  527. DxilFunctionLinkInfo *linkInfo = it.first;
  528. DxilLib *pLib = it.second;
  529. DxilModule &tmpDM = pLib->GetDxilModule();
  530. DxilTypeSystem &tmpTypeSys = tmpDM.GetTypeSystem();
  531. for (GlobalVariable *GV : linkInfo->usedGVs) {
  532. // Skip added globals.
  533. if (m_newGlobals.count(GV->getName())) {
  534. if (vmap.find(GV) == vmap.end()) {
  535. if (DxilResourceBase *res = pLib->GetResource(GV)) {
  536. // For resource of same name, if class and type match, just map to
  537. // same NewGV.
  538. GlobalVariable *NewGV = m_newGlobals[GV->getName()];
  539. if (AddResource(res, NewGV)) {
  540. vmap[GV] = NewGV;
  541. } else {
  542. bSuccess = false;
  543. }
  544. continue;
  545. }
  546. // Redefine of global.
  547. m_ctx.emitError(Twine(kRedefineGlobal) + GV->getName());
  548. bSuccess = false;
  549. }
  550. continue;
  551. }
  552. Constant *Initializer = nullptr;
  553. if (GV->hasInitializer())
  554. Initializer = GV->getInitializer();
  555. Type *Ty = GV->getType()->getElementType();
  556. GlobalVariable *NewGV = new GlobalVariable(
  557. *pM, Ty, GV->isConstant(), GV->getLinkage(), Initializer,
  558. GV->getName(),
  559. /*InsertBefore*/ nullptr, GV->getThreadLocalMode(),
  560. GV->getType()->getAddressSpace(), GV->isExternallyInitialized());
  561. m_newGlobals[GV->getName()] = NewGV;
  562. vmap[GV] = NewGV;
  563. typeSys.CopyTypeAnnotation(Ty, tmpTypeSys);
  564. if (DxilResourceBase *res = pLib->GetResource(GV)) {
  565. bSuccess &= AddResource(res, NewGV);
  566. }
  567. }
  568. }
  569. return bSuccess;
  570. }
  571. void DxilLinkJob::CloneFunctions(ValueToValueMapTy &vmap) {
  572. for (auto &it : m_functionDefs) {
  573. DxilFunctionLinkInfo *linkInfo = it.first;
  574. Function *F = linkInfo->func;
  575. Function *NewF = m_newFunctions[F->getName()];
  576. // Add dxil functions to vmap.
  577. for (Function *UsedF : linkInfo->usedFunctions) {
  578. if (!vmap.count(UsedF)) {
  579. // Extern function need match by name
  580. DXASSERT(m_newFunctions.count(UsedF->getName()),
  581. "Must have new function.");
  582. vmap[UsedF] = m_newFunctions[UsedF->getName()];
  583. }
  584. }
  585. CloneFunction(F, NewF, vmap);
  586. }
  587. }
  588. void DxilLinkJob::AddFunctions(DxilModule &DM, ValueToValueMapTy &vmap,
  589. std::unordered_set<Function *> &initFuncSet) {
  590. DxilTypeSystem &typeSys = DM.GetTypeSystem();
  591. Module *pM = DM.GetModule();
  592. for (auto &it : m_functionDefs) {
  593. DxilFunctionLinkInfo *linkInfo = it.first;
  594. DxilLib *pLib = it.second;
  595. DxilModule &tmpDM = pLib->GetDxilModule();
  596. DxilTypeSystem &tmpTypeSys = tmpDM.GetTypeSystem();
  597. Function *F = linkInfo->func;
  598. Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
  599. F->getName(), pM);
  600. NewF->setAttributes(F->getAttributes());
  601. if (!NewF->hasFnAttribute(llvm::Attribute::NoInline))
  602. NewF->addFnAttr(llvm::Attribute::AlwaysInline);
  603. if (DxilFunctionAnnotation *funcAnnotation =
  604. tmpTypeSys.GetFunctionAnnotation(F)) {
  605. // Clone funcAnnotation to typeSys.
  606. typeSys.CopyFunctionAnnotation(NewF, F, tmpTypeSys);
  607. }
  608. // Add to function map.
  609. m_newFunctions[NewF->getName()] = NewF;
  610. if (pLib->IsInitFunc(F))
  611. initFuncSet.insert(NewF);
  612. vmap[F] = NewF;
  613. }
  614. }
  615. std::unique_ptr<Module>
  616. DxilLinkJob::Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
  617. const ShaderModel *pSM) {
  618. Function *entryFunc = entryLinkPair.first->func;
  619. DxilModule &entryDM = entryLinkPair.second->GetDxilModule();
  620. if (!entryDM.HasDxilFunctionProps(entryFunc)) {
  621. // Cannot get function props.
  622. m_ctx.emitError(Twine(kNoEntryProps) + entryFunc->getName());
  623. return nullptr;
  624. }
  625. DxilFunctionProps props = entryDM.GetDxilFunctionProps(entryFunc);
  626. if (pSM->GetKind() != props.shaderKind) {
  627. // Shader kind mismatch.
  628. m_ctx.emitError(Twine(kShaderKindMismatch) +
  629. ShaderModel::GetKindName(pSM->GetKind()) + " and " +
  630. ShaderModel::GetKindName(props.shaderKind));
  631. return nullptr;
  632. }
  633. // Create new module.
  634. std::unique_ptr<Module> pM =
  635. llvm::make_unique<Module>(entryFunc->getName(), entryDM.GetCtx());
  636. // Set target.
  637. pM->setTargetTriple(entryDM.GetModule()->getTargetTriple());
  638. // Add dxil operation functions before create DxilModule.
  639. AddFunctionDecls(pM.get());
  640. // Create DxilModule.
  641. const bool bSkipInit = true;
  642. DxilModule &DM = pM->GetOrCreateDxilModule(bSkipInit);
  643. DM.SetShaderModel(pSM, entryDM.GetUseMinPrecision());
  644. // Set Validator version.
  645. DM.SetValidatorVersion(m_valMajor, m_valMinor);
  646. ValueToValueMapTy vmap;
  647. std::unordered_set<Function *> initFuncSet;
  648. // Add function
  649. AddFunctions(DM, vmap, initFuncSet);
  650. // Set Entry
  651. Function *NewEntryFunc = m_newFunctions[entryFunc->getName()];
  652. DM.SetEntryFunction(NewEntryFunc);
  653. DM.SetEntryFunctionName(entryFunc->getName());
  654. DxilEntryPropsMap EntryPropMap;
  655. std::unique_ptr<DxilEntryProps> pProps =
  656. llvm::make_unique<DxilEntryProps>(entryDM.GetDxilEntryProps(entryFunc));
  657. EntryPropMap[NewEntryFunc] = std::move(pProps);
  658. DM.ResetEntryPropsMap(std::move(EntryPropMap));
  659. if (NewEntryFunc->hasFnAttribute(llvm::Attribute::AlwaysInline))
  660. NewEntryFunc->removeFnAttr(llvm::Attribute::AlwaysInline);
  661. if (props.IsHS()) {
  662. Function *patchConstantFunc = props.ShaderProps.HS.patchConstantFunc;
  663. Function *newPatchConstantFunc =
  664. m_newFunctions[patchConstantFunc->getName()];
  665. props.ShaderProps.HS.patchConstantFunc = newPatchConstantFunc;
  666. if (newPatchConstantFunc->hasFnAttribute(llvm::Attribute::AlwaysInline))
  667. newPatchConstantFunc->removeFnAttr(llvm::Attribute::AlwaysInline);
  668. }
  669. // Set EntryProps
  670. DM.SetShaderProperties(&props);
  671. // Add global
  672. bool bSuccess = AddGlobals(DM, vmap);
  673. if (!bSuccess)
  674. return nullptr;
  675. // Clone functions.
  676. CloneFunctions(vmap);
  677. // Call global constrctor.
  678. IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(DM.GetEntryFunction()));
  679. for (auto &it : m_functionDefs) {
  680. DxilFunctionLinkInfo *linkInfo = it.first;
  681. DxilLib *pLib = it.second;
  682. Function *F = linkInfo->func;
  683. if (pLib->IsInitFunc(F)) {
  684. Function *NewF = m_newFunctions[F->getName()];
  685. Builder.CreateCall(NewF);
  686. }
  687. }
  688. // Refresh intrinsic cache.
  689. DM.GetOP()->RefreshCache();
  690. // Add resource to DM.
  691. // This should be after functions cloned.
  692. AddResourceToDM(DM);
  693. // Link metadata like debug info.
  694. LinkNamedMDNodes(pM.get(), vmap);
  695. RunPreparePass(*pM);
  696. return pM;
  697. }
  698. std::unique_ptr<Module>
  699. DxilLinkJob::LinkToLib(const ShaderModel *pSM) {
  700. if (m_functionDefs.empty()) {
  701. m_ctx.emitError(Twine(kNoFunctionsToExport));
  702. return nullptr;
  703. }
  704. DxilLib *pLib = m_functionDefs.begin()->second;
  705. DxilModule &tmpDM = pLib->GetDxilModule();
  706. // Create new module.
  707. std::unique_ptr<Module> pM =
  708. llvm::make_unique<Module>("merged_lib", tmpDM.GetCtx());
  709. // Set target.
  710. pM->setTargetTriple(tmpDM.GetModule()->getTargetTriple());
  711. // Add dxil operation functions and external decls before create DxilModule.
  712. AddFunctionDecls(pM.get());
  713. // Create DxilModule.
  714. const bool bSkipInit = true;
  715. DxilModule &DM = pM->GetOrCreateDxilModule(bSkipInit);
  716. DM.SetShaderModel(pSM, tmpDM.GetUseMinPrecision());
  717. // Set Validator version.
  718. DM.SetValidatorVersion(m_valMajor, m_valMinor);
  719. ValueToValueMapTy vmap;
  720. std::unordered_set<Function *> initFuncSet;
  721. // Add function
  722. AddFunctions(DM, vmap, initFuncSet);
  723. // Set DxilFunctionProps.
  724. DxilEntryPropsMap EntryPropMap;
  725. for (auto &it : m_functionDefs) {
  726. DxilFunctionLinkInfo *linkInfo = it.first;
  727. DxilLib *pLib = it.second;
  728. DxilModule &tmpDM = pLib->GetDxilModule();
  729. Function *F = linkInfo->func;
  730. if (tmpDM.HasDxilEntryProps(F)) {
  731. Function *NewF = m_newFunctions[F->getName()];
  732. DxilEntryProps &props = tmpDM.GetDxilEntryProps(F);
  733. std::unique_ptr<DxilEntryProps> pProps =
  734. llvm::make_unique<DxilEntryProps>(props);
  735. EntryPropMap[NewF] = std::move(pProps);
  736. }
  737. }
  738. DM.ResetEntryPropsMap(std::move(EntryPropMap));
  739. // Add global
  740. bool bSuccess = AddGlobals(DM, vmap);
  741. if (!bSuccess)
  742. return nullptr;
  743. // Clone functions.
  744. CloneFunctions(vmap);
  745. // Refresh intrinsic cache.
  746. DM.GetOP()->RefreshCache();
  747. // Add resource to DM.
  748. // This should be after functions cloned.
  749. AddResourceToDM(DM);
  750. // Link metadata like debug info.
  751. LinkNamedMDNodes(pM.get(), vmap);
  752. RunPreparePass(*pM);
  753. if (!m_exportMap.empty()) {
  754. m_exportMap.BeginProcessing();
  755. DM.ClearDxilMetadata(*pM);
  756. for (auto it = pM->begin(); it != pM->end();) {
  757. Function *F = it++;
  758. if (F->isDeclaration())
  759. continue;
  760. if (!m_exportMap.ProcessFunction(F, true)) {
  761. // Remove Function not in exportMap.
  762. DM.RemoveFunction(F);
  763. F->eraseFromParent();
  764. }
  765. }
  766. if(!m_exportMap.EndProcessing()) {
  767. for (auto &name : m_exportMap.GetNameCollisions()) {
  768. std::string escaped;
  769. llvm::raw_string_ostream os(escaped);
  770. dxilutil::PrintEscapedString(name, os);
  771. m_ctx.emitError(Twine(kExportNameCollision) + os.str());
  772. }
  773. for (auto &name : m_exportMap.GetUnusedExports()) {
  774. std::string escaped;
  775. llvm::raw_string_ostream os(escaped);
  776. dxilutil::PrintEscapedString(name, os);
  777. m_ctx.emitError(Twine(kExportFunctionMissing) + os.str());
  778. }
  779. return nullptr;
  780. }
  781. // Rename the original, if necessary, then clone the rest
  782. for (auto &it : m_exportMap.GetFunctionRenames()) {
  783. Function *F = it.first;
  784. auto &renames = it.second;
  785. if (renames.empty())
  786. continue;
  787. auto itName = renames.begin();
  788. // Rename the original, if necessary, then clone the rest
  789. if (renames.find(F->getName()) == renames.end())
  790. F->setName(*(itName++));
  791. while (itName != renames.end()) {
  792. if (F->getName() != *itName) {
  793. Function *NewF = Function::Create(F->getFunctionType(),
  794. GlobalValue::LinkageTypes::ExternalLinkage,
  795. *itName, DM.GetModule());
  796. ValueToValueMapTy vmap;
  797. CloneFunction(F, NewF, vmap, &DM.GetTypeSystem());
  798. // add DxilFunctionProps if entry
  799. if (DM.HasDxilFunctionProps(F)) {
  800. DM.CloneDxilEntryProps(F, NewF);
  801. }
  802. }
  803. itName++;
  804. }
  805. }
  806. DM.EmitDxilMetadata();
  807. }
  808. return pM;
  809. }
  810. void DxilLinkJob::AddFunction(
  811. std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair) {
  812. m_functionDefs[linkPair.first] = linkPair.second;
  813. }
  814. void DxilLinkJob::AddFunction(llvm::Function *F) {
  815. m_functionDecls[F->getName()] = F;
  816. }
  817. // Clone of StripDeadDebugInfo::runOnModule.
  818. // Also remove function which not not in current Module.
  819. void DxilLinkJob::StripDeadDebugInfo(Module &M) {
  820. LLVMContext &C = M.getContext();
  821. // Find all debug info in F. This is actually overkill in terms of what we
  822. // want to do, but we want to try and be as resilient as possible in the face
  823. // of potential debug info changes by using the formal interfaces given to us
  824. // as much as possible.
  825. DebugInfoFinder F;
  826. F.processModule(M);
  827. // For each compile unit, find the live set of global variables/functions and
  828. // replace the current list of potentially dead global variables/functions
  829. // with the live list.
  830. SmallVector<Metadata *, 64> LiveGlobalVariables;
  831. SmallVector<Metadata *, 64> LiveSubprograms;
  832. DenseSet<const MDNode *> VisitedSet;
  833. for (DICompileUnit *DIC : F.compile_units()) {
  834. // Create our live subprogram list.
  835. bool SubprogramChange = false;
  836. for (DISubprogram *DISP : DIC->getSubprograms()) {
  837. // Make sure we visit each subprogram only once.
  838. if (!VisitedSet.insert(DISP).second)
  839. continue;
  840. // If the function referenced by DISP is not null, the function is live.
  841. if (Function *Func = DISP->getFunction()) {
  842. if (Func->getParent() == &M)
  843. LiveSubprograms.push_back(DISP);
  844. else
  845. SubprogramChange = true;
  846. } else {
  847. SubprogramChange = true;
  848. }
  849. }
  850. // Create our live global variable list.
  851. bool GlobalVariableChange = false;
  852. for (DIGlobalVariable *DIG : DIC->getGlobalVariables()) {
  853. // Make sure we only visit each global variable only once.
  854. if (!VisitedSet.insert(DIG).second)
  855. continue;
  856. // If the global variable referenced by DIG is not null, the global
  857. // variable is live.
  858. if (Constant *CV = DIG->getVariable()) {
  859. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CV)) {
  860. if (GV->getParent() == &M) {
  861. LiveGlobalVariables.push_back(DIG);
  862. } else {
  863. GlobalVariableChange = true;
  864. }
  865. } else {
  866. LiveGlobalVariables.push_back(DIG);
  867. }
  868. } else {
  869. GlobalVariableChange = true;
  870. }
  871. }
  872. // If we found dead subprograms or global variables, replace the current
  873. // subprogram list/global variable list with our new live subprogram/global
  874. // variable list.
  875. if (SubprogramChange) {
  876. DIC->replaceSubprograms(MDTuple::get(C, LiveSubprograms));
  877. }
  878. if (GlobalVariableChange) {
  879. DIC->replaceGlobalVariables(MDTuple::get(C, LiveGlobalVariables));
  880. }
  881. // Reset lists for the next iteration.
  882. LiveSubprograms.clear();
  883. LiveGlobalVariables.clear();
  884. }
  885. }
  886. void DxilLinkJob::RunPreparePass(Module &M) {
  887. StripDeadDebugInfo(M);
  888. legacy::PassManager PM;
  889. PM.add(createAlwaysInlinerPass(/*InsertLifeTime*/ false));
  890. // Remove unused functions.
  891. PM.add(createDxilDeadFunctionEliminationPass());
  892. // SROA
  893. PM.add(createSROAPass(/*RequiresDomTree*/false, /*SkipHLSLMat*/false));
  894. // Remove MultiDimArray from function call arg.
  895. PM.add(createMultiDimArrayToOneDimArrayPass());
  896. // Lower matrix bitcast.
  897. PM.add(createMatrixBitcastLowerPass());
  898. // mem2reg.
  899. PM.add(createPromoteMemoryToRegisterPass());
  900. // Clean up vectors, and run mem2reg again
  901. PM.add(createScalarizerPass());
  902. PM.add(createPromoteMemoryToRegisterPass());
  903. PM.add(createSimplifyInstPass());
  904. PM.add(createCFGSimplificationPass());
  905. PM.add(createDeadCodeEliminationPass());
  906. PM.add(createGlobalDCEPass());
  907. PM.add(createDxilLowerCreateHandleForLibPass());
  908. PM.add(createDxilTranslateRawBuffer());
  909. PM.add(createDxilFinalizeModulePass());
  910. PM.add(createComputeViewIdStatePass());
  911. PM.add(createDxilDeadFunctionEliminationPass());
  912. PM.add(createNoPausePassesPass());
  913. PM.add(createDxilEmitMetadataPass());
  914. PM.run(M);
  915. }
  916. //------------------------------------------------------------------------------
  917. //
  918. // DxilLinkerImpl methods.
  919. //
  920. bool DxilLinkerImpl::HasLibNameRegistered(StringRef name) {
  921. return m_LibMap.count(name);
  922. }
  923. bool DxilLinkerImpl::RegisterLib(StringRef name,
  924. std::unique_ptr<llvm::Module> pModule,
  925. std::unique_ptr<llvm::Module> pDebugModule) {
  926. if (m_LibMap.count(name))
  927. return false;
  928. std::unique_ptr<llvm::Module> pM =
  929. pDebugModule ? std::move(pDebugModule) : std::move(pModule);
  930. if (!pM)
  931. return false;
  932. pM->setModuleIdentifier(name);
  933. std::unique_ptr<DxilLib> pLib =
  934. llvm::make_unique<DxilLib>(std::move(pM));
  935. m_LibMap[name] = std::move(pLib);
  936. return true;
  937. }
  938. bool DxilLinkerImpl::AttachLib(StringRef name) {
  939. auto iter = m_LibMap.find(name);
  940. if (iter == m_LibMap.end()) {
  941. return false;
  942. }
  943. return AttachLib(iter->second.get());
  944. }
  945. bool DxilLinkerImpl::DetachLib(StringRef name) {
  946. auto iter = m_LibMap.find(name);
  947. if (iter == m_LibMap.end()) {
  948. return false;
  949. }
  950. return DetachLib(iter->second.get());
  951. }
  952. void DxilLinkerImpl::DetachAll() {
  953. m_functionNameMap.clear();
  954. m_attachedLibs.clear();
  955. }
  956. bool DxilLinkerImpl::AttachLib(DxilLib *lib) {
  957. if (!lib) {
  958. // Invalid arg.
  959. return false;
  960. }
  961. if (m_attachedLibs.count(lib))
  962. return false;
  963. StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &funcTable =
  964. lib->GetFunctionTable();
  965. bool bSuccess = true;
  966. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  967. StringRef name = it->getKey();
  968. if (m_functionNameMap.count(name)) {
  969. // Redefine of function.
  970. m_ctx.emitError(Twine(kRedefineFunction) + name);
  971. bSuccess = false;
  972. continue;
  973. }
  974. m_functionNameMap[name] = std::make_pair(it->second.get(), lib);
  975. }
  976. if (bSuccess) {
  977. m_attachedLibs.insert(lib);
  978. } else {
  979. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  980. StringRef name = it->getKey();
  981. auto iter = m_functionNameMap.find(name);
  982. if (iter == m_functionNameMap.end())
  983. continue;
  984. // Remove functions of lib.
  985. if (m_functionNameMap[name].second == lib)
  986. m_functionNameMap.erase(name);
  987. }
  988. }
  989. return bSuccess;
  990. }
  991. bool DxilLinkerImpl::DetachLib(DxilLib *lib) {
  992. if (!lib) {
  993. // Invalid arg.
  994. return false;
  995. }
  996. if (!m_attachedLibs.count(lib))
  997. return false;
  998. m_attachedLibs.erase(lib);
  999. // Remove functions from lib.
  1000. StringMap<std::unique_ptr<DxilFunctionLinkInfo>> &funcTable =
  1001. lib->GetFunctionTable();
  1002. for (auto it = funcTable.begin(), e = funcTable.end(); it != e; it++) {
  1003. StringRef name = it->getKey();
  1004. m_functionNameMap.erase(name);
  1005. }
  1006. return true;
  1007. }
  1008. bool DxilLinkerImpl::AddFunctions(SmallVector<StringRef, 4> &workList,
  1009. DenseSet<DxilLib *> &libSet,
  1010. StringSet<> &addedFunctionSet,
  1011. DxilLinkJob &linkJob, bool bLazyLoadDone,
  1012. bool bAllowFuncionDecls) {
  1013. while (!workList.empty()) {
  1014. StringRef name = workList.pop_back_val();
  1015. // Ignore added function.
  1016. if (addedFunctionSet.count(name))
  1017. continue;
  1018. if (!m_functionNameMap.count(name)) {
  1019. // Cannot find function, report error.
  1020. m_ctx.emitError(Twine(kUndefFunction) + name);
  1021. return false;
  1022. }
  1023. std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair =
  1024. m_functionNameMap[name];
  1025. linkJob.AddFunction(linkPair);
  1026. DxilLib *pLib = linkPair.second;
  1027. libSet.insert(pLib);
  1028. if (!bLazyLoadDone) {
  1029. Function *F = linkPair.first->func;
  1030. pLib->LazyLoadFunction(F);
  1031. }
  1032. for (Function *F : linkPair.first->usedFunctions) {
  1033. if (hlsl::OP::IsDxilOpFunc(F) || F->isIntrinsic()) {
  1034. // Add dxil operations directly.
  1035. linkJob.AddFunction(F);
  1036. } else if (addedFunctionSet.count(F->getName()) == 0) {
  1037. if (bAllowFuncionDecls && F->isDeclaration() && !m_functionNameMap.count(F->getName())) {
  1038. // When linking to lib, use of undefined function is allowed; add directly.
  1039. linkJob.AddFunction(F);
  1040. } else {
  1041. // Push function name to work list.
  1042. workList.emplace_back(F->getName());
  1043. }
  1044. }
  1045. }
  1046. addedFunctionSet.insert(name);
  1047. }
  1048. return true;
  1049. }
  1050. std::unique_ptr<llvm::Module>
  1051. DxilLinkerImpl::Link(StringRef entry, StringRef profile, dxilutil::ExportMap &exportMap) {
  1052. const ShaderModel *pSM = ShaderModel::GetByName(profile.data());
  1053. DXIL::ShaderKind kind = pSM->GetKind();
  1054. if (kind == DXIL::ShaderKind::Invalid ||
  1055. (kind >= DXIL::ShaderKind::RayGeneration &&
  1056. kind <= DXIL::ShaderKind::Callable)) {
  1057. m_ctx.emitError(profile + Twine(kInvalidProfile));
  1058. // Invalid profile.
  1059. return nullptr;
  1060. }
  1061. if (!exportMap.empty() && kind != DXIL::ShaderKind::Library) {
  1062. m_ctx.emitError(Twine(kExportOnlyForLib));
  1063. return nullptr;
  1064. }
  1065. // Verifying validator version supports the requested profile
  1066. unsigned minValMajor, minValMinor;
  1067. pSM->GetMinValidatorVersion(minValMajor, minValMinor);
  1068. if (minValMajor > m_valMajor ||
  1069. (minValMajor == m_valMajor && minValMinor > m_valMinor)) {
  1070. m_ctx.emitError(Twine(kInvalidValidatorVersion) + profile);
  1071. return nullptr;
  1072. }
  1073. DxilLinkJob linkJob(m_ctx, exportMap, m_valMajor, m_valMinor);
  1074. DenseSet<DxilLib *> libSet;
  1075. StringSet<> addedFunctionSet;
  1076. bool bIsLib = pSM->IsLib();
  1077. if (!bIsLib) {
  1078. SmallVector<StringRef, 4> workList;
  1079. workList.emplace_back(entry);
  1080. if (!AddFunctions(workList, libSet, addedFunctionSet, linkJob,
  1081. /*bLazyLoadDone*/ false,
  1082. /*bAllowFuncionDecls*/ false))
  1083. return nullptr;
  1084. } else {
  1085. if (exportMap.empty()) {
  1086. // Add every function for lib profile.
  1087. for (auto &it : m_functionNameMap) {
  1088. StringRef name = it.getKey();
  1089. std::pair<DxilFunctionLinkInfo *, DxilLib *> &linkPair = it.second;
  1090. DxilFunctionLinkInfo *linkInfo = linkPair.first;
  1091. DxilLib *pLib = linkPair.second;
  1092. Function *F = linkInfo->func;
  1093. pLib->LazyLoadFunction(F);
  1094. linkJob.AddFunction(linkPair);
  1095. libSet.insert(pLib);
  1096. addedFunctionSet.insert(name);
  1097. }
  1098. // Add every dxil function and llvm intrinsic.
  1099. for (auto *pLib : libSet) {
  1100. auto &DM = pLib->GetDxilModule();
  1101. DM.GetOP();
  1102. auto *pM = DM.GetModule();
  1103. for (Function &F : pM->functions()) {
  1104. if (hlsl::OP::IsDxilOpFunc(&F) || F.isIntrinsic() ||
  1105. (F.isDeclaration() && m_functionNameMap.count(F.getName()) == 0)) {
  1106. // Add intrinsics and function decls still not defined in any lib
  1107. linkJob.AddFunction(&F);
  1108. }
  1109. }
  1110. }
  1111. } else {
  1112. SmallVector<StringRef, 4> workList;
  1113. // Only add exported functions.
  1114. for (auto &it : m_functionNameMap) {
  1115. StringRef name = it.getKey();
  1116. // Only add names exist in exportMap.
  1117. if (exportMap.IsExported(name))
  1118. workList.emplace_back(name);
  1119. }
  1120. if (!AddFunctions(workList, libSet, addedFunctionSet, linkJob,
  1121. /*bLazyLoadDone*/ false,
  1122. /*bAllowFuncionDecls*/ true))
  1123. return nullptr;
  1124. }
  1125. }
  1126. // Save global users.
  1127. for (auto &pLib : libSet) {
  1128. pLib->BuildGlobalUsage();
  1129. }
  1130. SmallVector<StringRef, 4> workList;
  1131. // Save global ctor users.
  1132. for (auto &pLib : libSet) {
  1133. pLib->CollectUsedInitFunctions(addedFunctionSet, workList);
  1134. }
  1135. // Add init functions if used.
  1136. // All init function already loaded in BuildGlobalUsage,
  1137. // so set bLazyLoadDone to true here.
  1138. // Decls should have been added to addedFunctionSet if lib,
  1139. // so set bAllowFuncionDecls is false here.
  1140. if (!AddFunctions(workList, libSet, addedFunctionSet, linkJob,
  1141. /*bLazyLoadDone*/ true,
  1142. /*bAllowFuncionDecls*/ false))
  1143. return nullptr;
  1144. if (!bIsLib) {
  1145. std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair =
  1146. m_functionNameMap[entry];
  1147. return linkJob.Link(entryLinkPair, pSM);
  1148. } else {
  1149. return linkJob.LinkToLib(pSM);
  1150. }
  1151. }
  1152. namespace hlsl {
  1153. DxilLinker *DxilLinker::CreateLinker(LLVMContext &Ctx, unsigned valMajor, unsigned valMinor) {
  1154. return new DxilLinkerImpl(Ctx, valMajor, valMinor);
  1155. }
  1156. } // namespace hlsl