NormalizeDxil.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // NormalizeDxil.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. // Normalize DXIL transformation. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "DxilConvPasses/NormalizeDxil.h"
  12. #include "dxc/Support/Global.h"
  13. #include "llvm/IR/BasicBlock.h"
  14. #include "llvm/IR/Constant.h"
  15. #include "llvm/IR/Constants.h"
  16. #include "llvm/IR/Function.h"
  17. #include "llvm/IR/Instruction.h"
  18. #include "llvm/IR/Instructions.h"
  19. #include "llvm/IR/Dominators.h"
  20. #include "dxc/DXIL/DXILOperations.h"
  21. #include "dxc/DXIL/DxilInstructions.h"
  22. #include <vector>
  23. using namespace llvm;
  24. //----------------------- Normalize Implementation ------------------------//
  25. // Look for resource handles that were moved to the stack by reg2mem and
  26. // move them back to registers.
  27. //
  28. // We make this change so the dxil will have an actual resource handle as
  29. // the argument to a load/store resource instruction instead of being
  30. // indirected through the stack.
  31. class NormalizeResourceHandle {
  32. public:
  33. bool Run(Function &F, DominatorTree &DT);
  34. private:
  35. struct ResourceHandleCandidate {
  36. Instruction *Alloca;
  37. Instruction *CreateHandle;
  38. };
  39. Instruction *IsResourceHandleAllocaCandidate(BasicBlock *entryBlock, AllocaInst *allocaInst, DominatorTree &DT);
  40. void FindCandidates(BasicBlock &entry, std::vector<ResourceHandleCandidate> &candidates, DominatorTree &DT);
  41. void ReplaceResourceHandleUsage(const std::vector<ResourceHandleCandidate> &candidates, std::vector<Instruction*> &trash);
  42. void Cleanup(std::vector<Instruction *> &trash);
  43. };
  44. // Check to see if this is a valid resource handle location for replacement:
  45. // 1. Only used in load/store.
  46. // 2. Only stored to once.
  47. // 3. Store value is create handle inst.
  48. // 4. Create handle dominates all uses of alloca.
  49. //
  50. // The check is strict to limit the replacement candidates to those allocas that
  51. // were inserted by mem2reg and make the replacement trivial.
  52. Instruction *NormalizeResourceHandle::IsResourceHandleAllocaCandidate(BasicBlock *entryBlock, AllocaInst *allocaInst, DominatorTree &DT) {
  53. Instruction *createHandleInst = nullptr;
  54. Instruction *const NOT_A_CANDIDATE = nullptr;
  55. for (User *use : allocaInst->users()) {
  56. if (StoreInst *store = dyn_cast<StoreInst>(use)) {
  57. if (store->getPointerOperand() != allocaInst) // In case it is used in gep expression.
  58. return NOT_A_CANDIDATE;
  59. Instruction *storedValue = dyn_cast<Instruction>(store->getValueOperand());
  60. if (!storedValue)
  61. return NOT_A_CANDIDATE;
  62. hlsl::DxilInst_CreateHandle createHandle(storedValue);
  63. if (!createHandle)
  64. return NOT_A_CANDIDATE;
  65. if (createHandleInst && createHandleInst != storedValue)
  66. return NOT_A_CANDIDATE;
  67. createHandleInst = storedValue;
  68. }
  69. else if (!(isa<LoadInst>(use))) {
  70. return NOT_A_CANDIDATE;
  71. }
  72. }
  73. for (Use &use : allocaInst->uses()) {
  74. if (!DT.dominates(createHandleInst, use))
  75. return NOT_A_CANDIDATE;
  76. }
  77. return createHandleInst;
  78. }
  79. void NormalizeResourceHandle::FindCandidates(BasicBlock &BBEntry, std::vector<ResourceHandleCandidate> &candidates, DominatorTree &DT) {
  80. DXASSERT_NOMSG(BBEntry.getTerminator());
  81. BasicBlock::iterator I = BBEntry.begin();
  82. while (isa<AllocaInst>(I)) {
  83. if (Instruction *createHandle = IsResourceHandleAllocaCandidate(&BBEntry, cast<AllocaInst>(I), DT))
  84. {
  85. candidates.push_back({ I, createHandle });
  86. }
  87. ++I;
  88. }
  89. }
  90. void NormalizeResourceHandle::ReplaceResourceHandleUsage(const std::vector<ResourceHandleCandidate> &candidates, std::vector<Instruction *> &trash) {
  91. for (const ResourceHandleCandidate &candidate : candidates) {
  92. for (User *use : candidate.Alloca->users()) {
  93. if (LoadInst *load = dyn_cast<LoadInst>(use)) {
  94. load->replaceAllUsesWith(candidate.CreateHandle);
  95. trash.push_back(load);
  96. }
  97. else if (StoreInst *store = dyn_cast<StoreInst>(use)) {
  98. trash.push_back(store);
  99. }
  100. else {
  101. DXASSERT(false, "should only have load and store insts");
  102. }
  103. }
  104. trash.push_back(candidate.Alloca);
  105. }
  106. }
  107. void NormalizeResourceHandle::Cleanup(std::vector<Instruction*> &trash) {
  108. for (Instruction *inst : trash) {
  109. inst->eraseFromParent();
  110. }
  111. trash.clear();
  112. }
  113. bool NormalizeResourceHandle::Run(Function &function, DominatorTree &DT) {
  114. std::vector<ResourceHandleCandidate> candidates;
  115. std::vector<Instruction *> trash;
  116. FindCandidates(function.getEntryBlock(), candidates, DT);
  117. ReplaceResourceHandleUsage(candidates, trash);
  118. Cleanup(trash);
  119. return candidates.size() > 0;
  120. }
  121. bool NormalizeDxil::Run() {
  122. return NormalizeResourceHandle().Run(m_function, m_dominatorTree);
  123. }
  124. //----------------------- Pass Implementation ------------------------//
  125. char NormalizeDxilPass::ID = 0;
  126. INITIALIZE_PASS_BEGIN(NormalizeDxilPass, "normalizedxil", "Normalize dxil pass", false, false)
  127. INITIALIZE_PASS_END(NormalizeDxilPass, "normalizedxil", "Normalize dxil pass", false, false)
  128. FunctionPass *llvm::createNormalizeDxilPass() {
  129. return new NormalizeDxilPass();
  130. }
  131. bool NormalizeDxilPass::runOnFunction(Function &F) {
  132. DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
  133. NormalizeDxil normalizer(F, DT);
  134. return normalizer.Run();
  135. }
  136. void NormalizeDxilPass::getAnalysisUsage(AnalysisUsage &AU) const {
  137. AU.setPreservesCFG();
  138. AU.addRequired<DominatorTreeWrapperPass>();
  139. }