DxilPromoteResourcePasses.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilPromoteResourcePasses.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/DXIL/DxilUtil.h"
  10. #include "dxc/HLSL/DxilGenerationPass.h"
  11. #include "dxc/HLSL/HLModule.h"
  12. #include "dxc/DXIL/DxilResourceBase.h"
  13. #include "dxc/DXIL/DxilResource.h"
  14. #include "dxc/DXIL/DxilCBuffer.h"
  15. #include "dxc/DXIL/DxilOperations.h"
  16. #include "dxc/DXIL/DxilModule.h"
  17. #include "llvm/Pass.h"
  18. #include "llvm/Analysis/AssumptionCache.h"
  19. #include "llvm/ADT/DenseSet.h"
  20. #include "llvm/IR/Dominators.h"
  21. #include "llvm/IR/Function.h"
  22. #include "llvm/IR/Instruction.h"
  23. #include "llvm/IR/Instructions.h"
  24. #include "llvm/IR/Intrinsics.h"
  25. #include "llvm/IR/LLVMContext.h"
  26. #include "llvm/IR/Module.h"
  27. #include "llvm/IR/Attributes.h"
  28. #include "llvm/IR/DebugInfo.h"
  29. #include "llvm/IR/Operator.h"
  30. #include "llvm/Transforms/Utils/PromoteMemToReg.h"
  31. #include "llvm/Transforms/Utils/SSAUpdater.h"
  32. #include <unordered_set>
  33. #include <vector>
  34. using namespace llvm;
  35. using namespace hlsl;
  36. // Legalize resource use.
  37. // Map local or static global resource to global resource.
  38. // Require inline for static global resource.
  39. namespace {
  40. static const StringRef kStaticResourceLibErrorMsg = "static global resource use is disallowed in library exports.";
  41. class DxilPromoteStaticResources : public ModulePass {
  42. public:
  43. static char ID; // Pass identification, replacement for typeid
  44. explicit DxilPromoteStaticResources()
  45. : ModulePass(ID) {}
  46. const char *getPassName() const override {
  47. return "DXIL Legalize Static Resource Use";
  48. }
  49. bool runOnModule(Module &M) override {
  50. // Promote static global variables.
  51. return PromoteStaticGlobalResources(M);
  52. }
  53. private:
  54. bool PromoteStaticGlobalResources(Module &M);
  55. };
  56. char DxilPromoteStaticResources::ID = 0;
  57. class DxilPromoteLocalResources : public FunctionPass {
  58. void getAnalysisUsage(AnalysisUsage &AU) const override;
  59. public:
  60. static char ID; // Pass identification, replacement for typeid
  61. explicit DxilPromoteLocalResources()
  62. : FunctionPass(ID) {}
  63. const char *getPassName() const override {
  64. return "DXIL Legalize Resource Use";
  65. }
  66. bool runOnFunction(Function &F) override {
  67. // Promote local resource first.
  68. return PromoteLocalResource(F);
  69. }
  70. private:
  71. bool PromoteLocalResource(Function &F);
  72. };
  73. char DxilPromoteLocalResources::ID = 0;
  74. }
  75. void DxilPromoteLocalResources::getAnalysisUsage(AnalysisUsage &AU) const {
  76. AU.addRequired<AssumptionCacheTracker>();
  77. AU.addRequired<DominatorTreeWrapperPass>();
  78. AU.setPreservesAll();
  79. }
  80. bool DxilPromoteLocalResources::PromoteLocalResource(Function &F) {
  81. bool bModified = false;
  82. std::vector<AllocaInst *> Allocas;
  83. DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
  84. AssumptionCache &AC =
  85. getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  86. BasicBlock &BB = F.getEntryBlock();
  87. unsigned allocaSize = 0;
  88. while (1) {
  89. Allocas.clear();
  90. // Find allocas that are safe to promote, by looking at all instructions in
  91. // the entry node
  92. for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
  93. if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) { // Is it an alloca?
  94. if (dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(AI->getAllocatedType()))) {
  95. if (isAllocaPromotable(AI))
  96. Allocas.push_back(AI);
  97. }
  98. }
  99. if (Allocas.empty())
  100. break;
  101. // No update.
  102. // Report error and break.
  103. if (allocaSize == Allocas.size()) {
  104. F.getContext().emitError(dxilutil::kResourceMapErrorMsg);
  105. break;
  106. }
  107. allocaSize = Allocas.size();
  108. PromoteMemToReg(Allocas, *DT, nullptr, &AC);
  109. bModified = true;
  110. }
  111. return bModified;
  112. }
  113. FunctionPass *llvm::createDxilPromoteLocalResources() {
  114. return new DxilPromoteLocalResources();
  115. }
  116. INITIALIZE_PASS_BEGIN(DxilPromoteLocalResources,
  117. "hlsl-dxil-promote-local-resources",
  118. "DXIL promote local resource use", false, true)
  119. INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
  120. INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
  121. INITIALIZE_PASS_END(DxilPromoteLocalResources,
  122. "hlsl-dxil-promote-local-resources",
  123. "DXIL promote local resource use", false, true)
  124. bool DxilPromoteStaticResources::PromoteStaticGlobalResources(
  125. Module &M) {
  126. if (M.GetOrCreateHLModule().GetShaderModel()->IsLib()) {
  127. // Read/write to global static resource is disallowed for libraries:
  128. // Resource use needs to be resolved to a single real global resource,
  129. // but it may not be possible since any external function call may re-enter
  130. // at any other library export, which could modify the global static
  131. // between write and read.
  132. // While it could work for certain cases, describing the boundary at
  133. // the HLSL level is difficult, so at this point it's better to disallow.
  134. // example of what could work:
  135. // After inlining, exported functions must have writes to static globals
  136. // before reads, and must not have any external function calls between
  137. // writes and subsequent reads, such that the static global may be
  138. // optimized away for the exported function.
  139. for (auto &GV : M.globals()) {
  140. if (GV.getLinkage() == GlobalVariable::LinkageTypes::InternalLinkage &&
  141. dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(GV.getType()))) {
  142. if (!GV.user_empty()) {
  143. if (Instruction *I = dyn_cast<Instruction>(*GV.user_begin())) {
  144. dxilutil::EmitErrorOnInstruction(I, kStaticResourceLibErrorMsg);
  145. break;
  146. }
  147. }
  148. }
  149. }
  150. return false;
  151. }
  152. bool bModified = false;
  153. std::set<GlobalVariable *> staticResources;
  154. for (auto &GV : M.globals()) {
  155. if (GV.getLinkage() == GlobalVariable::LinkageTypes::InternalLinkage &&
  156. dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(GV.getType()))) {
  157. staticResources.insert(&GV);
  158. }
  159. }
  160. SSAUpdater SSA;
  161. SmallVector<Instruction *, 4> Insts;
  162. // Make sure every resource load has mapped to global variable.
  163. while (!staticResources.empty()) {
  164. bool bUpdated = false;
  165. for (auto it = staticResources.begin(); it != staticResources.end();) {
  166. GlobalVariable *GV = *(it++);
  167. // Build list of instructions to promote.
  168. for (User *U : GV->users()) {
  169. if (isa<LoadInst>(U) || isa<StoreInst>(U)) {
  170. Insts.emplace_back(cast<Instruction>(U));
  171. } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
  172. for (User *gepU : GEP->users()) {
  173. DXASSERT_NOMSG(isa<LoadInst>(gepU) || isa<StoreInst>(gepU));
  174. if (isa<LoadInst>(gepU) || isa<StoreInst>(gepU))
  175. Insts.emplace_back(cast<Instruction>(gepU));
  176. }
  177. } else {
  178. DXASSERT(false, "Unhandled user of resource static global");
  179. }
  180. }
  181. LoadAndStorePromoter(Insts, SSA).run(Insts);
  182. GV->removeDeadConstantUsers();
  183. if (GV->user_empty()) {
  184. bUpdated = true;
  185. staticResources.erase(GV);
  186. }
  187. Insts.clear();
  188. }
  189. if (!bUpdated) {
  190. M.getContext().emitError(dxilutil::kResourceMapErrorMsg);
  191. break;
  192. }
  193. bModified = true;
  194. }
  195. return bModified;
  196. }
  197. ModulePass *llvm::createDxilPromoteStaticResources() {
  198. return new DxilPromoteStaticResources();
  199. }
  200. INITIALIZE_PASS(DxilPromoteStaticResources,
  201. "hlsl-dxil-promote-static-resources",
  202. "DXIL promote static resource use", false, false)
  203. // Mutate high-level resource type into handle.
  204. // This is used for SM 6.6+, on libraries only, where
  205. // CreateHandleForLib is eliminated, and high-level resource
  206. // types are only preserved in metadata for reflection purposes.
  207. namespace {
  208. // Overview
  209. // 1. collectCandidates - collect to MutateValSet
  210. // Start from resource global variable, function parameter/ret, alloca.
  211. // Propagate to all insts, GEP/ld/st/phi/select/called functions.
  212. // 2. mutateCandidates
  213. // Mutate all non-function value types.
  214. // Mutate functions by creating new function with new type, then
  215. // splice original function blocks into new function, and
  216. // replace old argument uses with new function's arguments.
  217. class DxilMutateResourceToHandle : public ModulePass {
  218. public:
  219. static char ID; // Pass identification, replacement for typeid
  220. explicit DxilMutateResourceToHandle() : ModulePass(ID) {}
  221. const char *getPassName() const override {
  222. return "DXIL Mutate resource to handle";
  223. }
  224. bool runOnModule(Module &M) override {
  225. if (M.HasHLModule()) {
  226. auto &HLM = M.GetHLModule();
  227. if (!HLM.GetShaderModel()->IsSM66Plus())
  228. return false;
  229. hdlTy = HLM.GetOP()->GetHandleType();
  230. pTypeSys = &HLM.GetTypeSystem();
  231. } else if (M.HasDxilModule()) {
  232. auto &DM = M.GetDxilModule();
  233. if (!DM.GetShaderModel()->IsSM66Plus())
  234. return false;
  235. hdlTy = DM.GetOP()->GetHandleType();
  236. pTypeSys = &DM.GetTypeSystem();
  237. } else {
  238. return false;
  239. }
  240. collectCandidates(M);
  241. mutateCandidates(M);
  242. // Remvoe cast to handle.
  243. return !MutateValSet.empty();
  244. }
  245. private:
  246. Type *mutateToHandleTy(Type *Ty);
  247. bool mutateTypesToHandleTy(SmallVector<Type *, 4> &Tys);
  248. void collectGlobalResource(DxilResourceBase *Res,
  249. SmallVector<Value *, 8> &WorkList);
  250. void collectAlloca(Function &F, SmallVector<Value *, 8> &WorkList);
  251. SmallVector<Value *, 8> collectHlslObjects(Module &M);
  252. void collectCandidates(Module &M);
  253. void mutateCandidates(Module &M);
  254. Type *hdlTy;
  255. DxilTypeSystem *pTypeSys;
  256. DenseSet<Value *> MutateValSet;
  257. DenseMap<Type *, Type *> MutateTypeMap;
  258. };
  259. char DxilMutateResourceToHandle::ID = 0;
  260. Type *DxilMutateResourceToHandle::mutateToHandleTy(Type *Ty) {
  261. auto it = MutateTypeMap.find(Ty);
  262. if (it != MutateTypeMap.end())
  263. return it->second;
  264. Type *ResultTy = nullptr;
  265. if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
  266. SmallVector<unsigned, 2> nestedSize;
  267. Type *EltTy = Ty;
  268. while (ArrayType *NestAT = dyn_cast<ArrayType>(EltTy)) {
  269. nestedSize.emplace_back(NestAT->getNumElements());
  270. EltTy = NestAT->getElementType();
  271. }
  272. Type *mutatedTy = mutateToHandleTy(EltTy);
  273. if (mutatedTy == EltTy) {
  274. ResultTy = Ty;
  275. } else {
  276. Type *newAT = mutatedTy;
  277. for (auto it = nestedSize.rbegin(), E = nestedSize.rend(); it != E; ++it)
  278. newAT = ArrayType::get(newAT, *it);
  279. ResultTy = newAT;
  280. }
  281. } else if (PointerType *PT = dyn_cast<PointerType>(Ty)) {
  282. Type *EltTy = PT->getElementType();
  283. Type *mutatedTy = mutateToHandleTy(EltTy);
  284. if (mutatedTy == EltTy)
  285. ResultTy = Ty;
  286. else
  287. ResultTy = mutatedTy->getPointerTo(PT->getAddressSpace());
  288. } else if (dxilutil::IsHLSLResourceType(Ty)) {
  289. ResultTy = hdlTy;
  290. } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
  291. if (!ST->isOpaque()) {
  292. SmallVector<Type *, 4> Elts(ST->element_begin(), ST->element_end());
  293. if (!mutateTypesToHandleTy(Elts)) {
  294. ResultTy = Ty;
  295. } else {
  296. ResultTy = StructType::create(Elts, ST->getName().str() + ".hdl");
  297. }
  298. } else {
  299. if (ST->getName() == "ConstantBuffer")
  300. ResultTy = hdlTy;
  301. else
  302. ResultTy = Ty;
  303. }
  304. } else if (FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
  305. Type *RetTy = FT->getReturnType();
  306. SmallVector<Type *, 4> Args(FT->param_begin(), FT->param_end());
  307. Type *mutatedRetTy = mutateToHandleTy(RetTy);
  308. if (!mutateTypesToHandleTy(Args) && RetTy == mutatedRetTy) {
  309. ResultTy = Ty;
  310. } else {
  311. ResultTy = FunctionType::get(mutatedRetTy, Args, FT->isVarArg());
  312. }
  313. } else {
  314. ResultTy = Ty;
  315. }
  316. MutateTypeMap[Ty] = ResultTy;
  317. return ResultTy;
  318. }
  319. bool DxilMutateResourceToHandle::mutateTypesToHandleTy(
  320. SmallVector<Type *, 4> &Tys) {
  321. bool bMutated = false;
  322. for (size_t i = 0; i < Tys.size(); i++) {
  323. Type *Ty = Tys[i];
  324. Type *mutatedTy = mutateToHandleTy(Ty);
  325. if (Ty != mutatedTy) {
  326. Tys[i] = mutatedTy;
  327. bMutated = true;
  328. }
  329. }
  330. return bMutated;
  331. }
  332. void DxilMutateResourceToHandle::collectGlobalResource(
  333. DxilResourceBase *Res, SmallVector<Value *, 8> &WorkList) {
  334. Value *GV = Res->GetGlobalSymbol();
  335. // Save hlsl type before mutate to handle.
  336. Res->SetHLSLType(GV->getType());
  337. mutateToHandleTy(GV->getType());
  338. WorkList.emplace_back(GV);
  339. }
  340. void DxilMutateResourceToHandle::collectAlloca(
  341. Function &F, SmallVector<Value *, 8> &WorkList) {
  342. if (F.isDeclaration())
  343. return;
  344. for (Instruction &I : F.getEntryBlock()) {
  345. AllocaInst *AI = dyn_cast<AllocaInst>(&I);
  346. if (!AI)
  347. continue;
  348. Type *Ty = AI->getType();
  349. Type *MTy = mutateToHandleTy(Ty);
  350. if (Ty == MTy)
  351. continue;
  352. WorkList.emplace_back(AI);
  353. }
  354. }
  355. }
  356. SmallVector<Value *, 8>
  357. DxilMutateResourceToHandle::collectHlslObjects(Module &M) {
  358. // Add all global/function/argument/alloca has resource type.
  359. SmallVector<Value *, 8> WorkList;
  360. // Assume this is after SROA so no struct for global/alloca.
  361. // Functions.
  362. for (Function &F : M) {
  363. collectAlloca(F, WorkList);
  364. FunctionType *FT = F.getFunctionType();
  365. FunctionType *MFT = cast<FunctionType>(mutateToHandleTy(FT));
  366. if (FT == MFT)
  367. continue;
  368. WorkList.emplace_back(&F);
  369. // Check args.
  370. for (Argument &Arg : F.args()) {
  371. Type *Ty = Arg.getType();
  372. Type *MTy = mutateToHandleTy(Ty);
  373. if (Ty == MTy)
  374. continue;
  375. WorkList.emplace_back(&Arg);
  376. }
  377. }
  378. // Static globals.
  379. for (GlobalVariable &GV : M.globals()) {
  380. if (!dxilutil::IsStaticGlobal(&GV))
  381. continue;
  382. Type *Ty = dxilutil::GetArrayEltTy(GV.getValueType());
  383. if (!dxilutil::IsHLSLObjectType(Ty))
  384. continue;
  385. WorkList.emplace_back(&GV);
  386. }
  387. // Global resources.
  388. if (M.HasHLModule()) {
  389. auto &HLM = M.GetHLModule();
  390. for (auto &Res : HLM.GetCBuffers()) {
  391. collectGlobalResource(Res.get(), WorkList);
  392. }
  393. for (auto &Res : HLM.GetSRVs()) {
  394. collectGlobalResource(Res.get(), WorkList);
  395. }
  396. for (auto &Res : HLM.GetUAVs()) {
  397. collectGlobalResource(Res.get(), WorkList);
  398. }
  399. for (auto &Res : HLM.GetSamplers()) {
  400. collectGlobalResource(Res.get(), WorkList);
  401. }
  402. } else {
  403. auto &DM = M.GetDxilModule();
  404. for (auto &Res : DM.GetCBuffers()) {
  405. collectGlobalResource(Res.get(), WorkList);
  406. }
  407. for (auto &Res : DM.GetSRVs()) {
  408. collectGlobalResource(Res.get(), WorkList);
  409. }
  410. for (auto &Res : DM.GetUAVs()) {
  411. collectGlobalResource(Res.get(), WorkList);
  412. }
  413. for (auto &Res : DM.GetSamplers()) {
  414. collectGlobalResource(Res.get(), WorkList);
  415. }
  416. }
  417. return WorkList;
  418. }
  419. void DxilMutateResourceToHandle::collectCandidates(Module &M) {
  420. SmallVector<Value *, 8> WorkList = collectHlslObjects(M);
  421. // Propagate candidates.
  422. while (!WorkList.empty()) {
  423. Value *V = WorkList.pop_back_val();
  424. MutateValSet.insert(V);
  425. for (User *U : V->users()) {
  426. // collect in a user.
  427. SmallVector<Value *, 2> newCandidates;
  428. // Should only used by ld/st/sel/phi/gep/call.
  429. if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
  430. newCandidates.emplace_back(LI);
  431. } else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
  432. Value *Ptr = SI->getPointerOperand();
  433. Value *Val = SI->getValueOperand();
  434. if (V == Ptr)
  435. newCandidates.emplace_back(Val);
  436. else
  437. newCandidates.emplace_back(Ptr);
  438. } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
  439. // If result type of GEP not related to resource type, skip.
  440. Type *Ty = GEP->getType();
  441. Type *MTy = mutateToHandleTy(Ty);
  442. if (MTy == Ty)
  443. continue;
  444. newCandidates.emplace_back(GEP);
  445. } else if (PHINode *Phi = dyn_cast<PHINode>(U)) {
  446. // Propagate all operands.
  447. newCandidates.emplace_back(Phi);
  448. for (Use &PhiOp : Phi->incoming_values()) {
  449. if (V == PhiOp)
  450. continue;
  451. newCandidates.emplace_back(PhiOp);
  452. }
  453. } else if (SelectInst *Sel = dyn_cast<SelectInst>(U)) {
  454. // Propagate other result.
  455. newCandidates.emplace_back(Sel);
  456. Value *TrueV = Sel->getTrueValue();
  457. Value *FalseV = Sel->getFalseValue();
  458. if (TrueV == V)
  459. newCandidates.emplace_back(FalseV);
  460. else
  461. newCandidates.emplace_back(TrueV);
  462. } else if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(U)) {
  463. // Make sure only used for lifetime intrinsic.
  464. for (User *BCUser : BCO->users()) {
  465. if (ConstantArray *CA = dyn_cast<ConstantArray>(BCUser)) {
  466. // For llvm.used.
  467. if (CA->hasOneUse()) {
  468. Value *CAUser = CA->user_back();
  469. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CAUser)) {
  470. if (GV->getName() == "llvm.used")
  471. continue;
  472. }
  473. } else if (CA->user_empty()) {
  474. continue;
  475. }
  476. }
  477. CallInst *CI = cast<CallInst>(BCUser);
  478. Function *F = CI->getCalledFunction();
  479. Intrinsic::ID ID = F->getIntrinsicID();
  480. if (ID != Intrinsic::lifetime_start &&
  481. ID != Intrinsic::lifetime_end) {
  482. DXASSERT(false, "unexpected resource object user");
  483. }
  484. }
  485. } else {
  486. CallInst *CI = cast<CallInst>(U);
  487. Type *Ty = CI->getType();
  488. Type *MTy = mutateToHandleTy(Ty);
  489. if (Ty != MTy)
  490. newCandidates.emplace_back(CI);
  491. SmallVector<Value *, 4> Args(CI->arg_operands().begin(),
  492. CI->arg_operands().end());
  493. for (Value *Arg : Args) {
  494. if (Arg == V)
  495. continue;
  496. Type *Ty = Arg->getType();
  497. Type *MTy = mutateToHandleTy(Ty);
  498. if (Ty == MTy)
  499. continue;
  500. newCandidates.emplace_back(Arg);
  501. }
  502. }
  503. for (Value *Val : newCandidates) {
  504. // New candidate find.
  505. if (MutateValSet.insert(Val).second) {
  506. WorkList.emplace_back(Val);
  507. }
  508. }
  509. }
  510. }
  511. }
  512. void DxilMutateResourceToHandle::mutateCandidates(Module &M) {
  513. SmallVector<Function *, 2> CandidateFns;
  514. for (Value *V : MutateValSet) {
  515. if (Function *F = dyn_cast<Function>(V)) {
  516. CandidateFns.emplace_back(F);
  517. continue;
  518. }
  519. Type *Ty = V->getType();
  520. Type *MTy = mutateToHandleTy(Ty);
  521. if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
  522. AI->setAllocatedType(MTy->getPointerElementType());
  523. } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
  524. Type *MResultEltTy = mutateToHandleTy(GEP->getResultElementType());
  525. GEP->setResultElementType(MResultEltTy);
  526. Type *MSrcEltTy = mutateToHandleTy(GEP->getSourceElementType());
  527. GEP->setSourceElementType(MSrcEltTy);
  528. } else if (GEPOperator *GEPO = dyn_cast<GEPOperator>(V)) {
  529. // GEP operator not support setSourceElementType.
  530. // Create a new GEP here.
  531. Constant *C = cast<Constant>(GEPO->getPointerOperand());
  532. IRBuilder<> B(C->getContext());
  533. // Make sure C is mutated so the GEP get correct sourceElementType.
  534. C->mutateType(mutateToHandleTy(C->getType()));
  535. // Collect user of GEPs, then replace all use with undef.
  536. SmallVector<Use *, 2> Uses;
  537. for (Use &U : GEPO->uses()) {
  538. Uses.emplace_back(&U);
  539. }
  540. SmallVector<Value *, 2> idxList(GEPO->idx_begin(), GEPO->idx_end());
  541. Type *Ty = GEPO->getType();
  542. GEPO->replaceAllUsesWith(UndefValue::get(Ty));
  543. StringRef Name = GEPO->getName();
  544. // GO and newGO will be same constant except has different
  545. // sourceElementType. ConstantMap think they're the same constant. Have to
  546. // remove GO first before create newGO.
  547. C->removeDeadConstantUsers();
  548. Value *newGO = B.CreateGEP(C, idxList, Name);
  549. // update uses.
  550. for (Use *U : Uses) {
  551. U->set(newGO);
  552. }
  553. continue;
  554. }
  555. V->mutateType(MTy);
  556. }
  557. Function *createHandleForLibOnHandle = nullptr;
  558. hlsl::OP *hlslOP = nullptr;
  559. if (M.HasDxilModule()) {
  560. auto &DM = M.GetDxilModule();
  561. hlslOP = DM.GetOP();
  562. if (hlslOP->IsDxilOpUsed(DXIL::OpCode::CreateHandleForLib)) {
  563. createHandleForLibOnHandle =
  564. hlslOP->GetOpFunc(DXIL::OpCode::CreateHandleForLib, hdlTy);
  565. }
  566. }
  567. // Mutate functions.
  568. for (Function *F : CandidateFns) {
  569. Function *MF = nullptr;
  570. if (hlslOP) {
  571. if (hlslOP->IsDxilOpFunc(F)) {
  572. DXIL::OpCodeClass OpcodeClass;
  573. if (hlslOP->GetOpCodeClass(F, OpcodeClass)) {
  574. if (OpcodeClass == DXIL::OpCodeClass::CreateHandleForLib) {
  575. MF = createHandleForLibOnHandle;
  576. }
  577. }
  578. }
  579. }
  580. if (!MF) {
  581. FunctionType *FT = F->getFunctionType();
  582. FunctionType *MFT = cast<FunctionType>(MutateTypeMap[FT]);
  583. MF = Function::Create(MFT, F->getLinkage(), "", &M);
  584. MF->takeName(F);
  585. // Copy calling conv.
  586. MF->setCallingConv(F->getCallingConv());
  587. // Copy attributes.
  588. AttributeSet AS = F->getAttributes();
  589. MF->setAttributes(AS);
  590. // Annotation.
  591. if (DxilFunctionAnnotation *FnAnnot =
  592. pTypeSys->GetFunctionAnnotation(F)) {
  593. DxilFunctionAnnotation *newFnAnnot =
  594. pTypeSys->AddFunctionAnnotation(MF);
  595. DxilParameterAnnotation &RetAnnot = newFnAnnot->GetRetTypeAnnotation();
  596. RetAnnot = FnAnnot->GetRetTypeAnnotation();
  597. for (unsigned i = 0; i < FnAnnot->GetNumParameters(); i++) {
  598. newFnAnnot->GetParameterAnnotation(i) =
  599. FnAnnot->GetParameterAnnotation(i);
  600. }
  601. }
  602. // Update function debug info.
  603. if (DISubprogram *funcDI = getDISubprogram(F))
  604. funcDI->replaceFunction(MF);
  605. }
  606. for (auto it = F->user_begin(); it != F->user_end();) {
  607. CallInst *CI = cast<CallInst>(*(it++));
  608. CI->setCalledFunction(MF);
  609. }
  610. if (F->isDeclaration()) {
  611. F->eraseFromParent();
  612. continue;
  613. }
  614. // Take body of F.
  615. // Splice the body of the old function right into the new function.
  616. MF->getBasicBlockList().splice(MF->begin(), F->getBasicBlockList());
  617. // Replace use of arg.
  618. auto argIt = F->arg_begin();
  619. for (auto MArgIt = MF->arg_begin(); MArgIt != MF->arg_end();) {
  620. Argument *Arg = (argIt++);
  621. Argument *MArg = (MArgIt++);
  622. Arg->replaceAllUsesWith(MArg);
  623. }
  624. }
  625. }
  626. ModulePass *llvm::createDxilMutateResourceToHandlePass() {
  627. return new DxilMutateResourceToHandle();
  628. }
  629. INITIALIZE_PASS(DxilMutateResourceToHandle,
  630. "hlsl-dxil-resources-to-handle",
  631. "Mutate resource to handle", false, false)