DxilEraseDeadRegion.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //===- DxilEraseDeadRegion.cpp - Heuristically Remove Dead Region ---------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. // Overview:
  10. // 1. Identify potentially dead regions by finding blocks with multiple
  11. // predecessors but no PHIs
  12. // 2. Find common dominant ancestor of all the predecessors
  13. // 3. Ensure original block post-dominates the ancestor
  14. // 4. Ensure no instructions in the region have side effects (not including
  15. // original block and ancestor)
  16. // 5. Remove all blocks in the region (excluding original block and ancestor)
  17. //
  18. #include "llvm/Pass.h"
  19. #include "llvm/Analysis/CFG.h"
  20. #include "llvm/Analysis/PostDominators.h"
  21. #include "llvm/Transforms/Scalar.h"
  22. #include "llvm/IR/Instructions.h"
  23. #include "llvm/IR/IntrinsicInst.h"
  24. #include "llvm/IR/Function.h"
  25. #include "llvm/IR/Module.h"
  26. #include "llvm/IR/BasicBlock.h"
  27. #include "dxc/DXIL/DxilOperations.h"
  28. #include <unordered_map>
  29. #include <unordered_set>
  30. using namespace llvm;
  31. using namespace hlsl;
  32. struct DxilEraseDeadRegion : public FunctionPass {
  33. static char ID;
  34. DxilEraseDeadRegion() : FunctionPass(ID) {
  35. initializeDxilEraseDeadRegionPass(*PassRegistry::getPassRegistry());
  36. }
  37. std::unordered_map<BasicBlock *, bool> m_HasSideEffect;
  38. bool HasSideEffects(BasicBlock *BB) {
  39. auto FindIt = m_HasSideEffect.find(BB);
  40. if (FindIt != m_HasSideEffect.end()) {
  41. return FindIt->second;
  42. }
  43. for (Instruction &I : *BB)
  44. if (I.mayHaveSideEffects()) {
  45. m_HasSideEffect[BB] = true;
  46. return true;
  47. }
  48. m_HasSideEffect[BB] = false;
  49. return false;
  50. }
  51. bool IsEmptySelfLoop(BasicBlock *BB) {
  52. // Make sure all inst not used outside BB.
  53. for (Instruction &I : *BB) {
  54. for (User *U : I.users()) {
  55. if (Instruction *UI = dyn_cast<Instruction>(U)) {
  56. if (UI->getParent() != BB)
  57. return false;
  58. }
  59. }
  60. if (!I.mayHaveSideEffects())
  61. continue;
  62. if (CallInst *CI = dyn_cast<CallInst>(&I)) {
  63. if (hlsl::OP::IsDxilOpFuncCallInst(CI)) {
  64. DXIL::OpCode opcode = hlsl::OP::GetDxilOpFuncCallInst(CI);
  65. // Wave Ops are marked has side effect to avoid move cross control flow.
  66. // But they're safe to remove if unused.
  67. if (hlsl::OP::IsDxilOpWave(opcode))
  68. continue;
  69. }
  70. }
  71. return false;
  72. }
  73. return true;
  74. }
  75. bool FindDeadRegion(BasicBlock *Begin, BasicBlock *End, std::set<BasicBlock *> &Region) {
  76. std::vector<BasicBlock *> WorkList;
  77. auto ProcessSuccessors = [this, &WorkList, Begin, End, &Region](BasicBlock *BB) {
  78. for (BasicBlock *Succ : successors(BB)) {
  79. if (Succ == End) continue;
  80. if (Succ == Begin) return false; // If goes back to the beginning, there's a loop, give up.
  81. if (Region.count(Succ)) continue;
  82. if (this->HasSideEffects(Succ)) return false; // Give up if the block may have side effects
  83. WorkList.push_back(Succ);
  84. Region.insert(Succ);
  85. }
  86. return true;
  87. };
  88. if (!ProcessSuccessors(Begin))
  89. return false;
  90. while (WorkList.size()) {
  91. BasicBlock *BB = WorkList.back();
  92. WorkList.pop_back();
  93. if (!ProcessSuccessors(BB))
  94. return false;
  95. }
  96. return Region.size() != 0;
  97. }
  98. bool TrySimplify(DominatorTree *DT, PostDominatorTree *PDT, BasicBlock *BB) {
  99. // Give up if BB has any Phis
  100. if (BB->begin() != BB->end() && isa<PHINode>(BB->begin()))
  101. return false;
  102. std::vector<BasicBlock *> Predecessors(pred_begin(BB), pred_end(BB));
  103. if (Predecessors.size() < 2) return false;
  104. // Give up if BB is a self loop
  105. for (BasicBlock *PredBB : Predecessors)
  106. if (PredBB == BB) {
  107. if (!IsEmptySelfLoop(BB)) {
  108. return false;
  109. } else if (Predecessors.size() != 2) {
  110. return false;
  111. } else {
  112. BasicBlock *PredBB0 = Predecessors[0];
  113. BasicBlock *PredBB1 = Predecessors[1];
  114. BasicBlock *LoopBB = PredBB;
  115. BasicBlock *LoopPrevBB = PredBB == PredBB0? PredBB1 : PredBB0;
  116. // Remove LoopBB, LoopPrevBB branch to succ of LoopBB.
  117. BranchInst *BI = cast<BranchInst>(LoopBB->getTerminator());
  118. if (BI->getNumSuccessors() != 2)
  119. return false;
  120. BasicBlock *Succ0 = BI->getSuccessor(0);
  121. BasicBlock *Succ1 = BI->getSuccessor(1);
  122. BasicBlock *NextBB = Succ0 == PredBB ? Succ1 : Succ0;
  123. // Make sure it is not a dead loop.
  124. if (NextBB == LoopPrevBB || NextBB == BB)
  125. return false;
  126. LoopPrevBB->getTerminator()->eraseFromParent();
  127. BranchInst::Create(NextBB, LoopPrevBB);
  128. return true;
  129. }
  130. }
  131. // Find the common ancestor of all the predecessors
  132. BasicBlock *Common = DT->findNearestCommonDominator(Predecessors[0], Predecessors[1]);
  133. if (!Common) return false;
  134. for (unsigned i = 2; i < Predecessors.size(); i++) {
  135. Common = DT->findNearestCommonDominator(Common, Predecessors[i]);
  136. if (!Common) return false;
  137. }
  138. // If there are any metadata on Common block's branch, give up.
  139. if (Common->getTerminator()->hasMetadataOtherThanDebugLoc())
  140. return false;
  141. if (!DT->properlyDominates(Common, BB))
  142. return false;
  143. if (!PDT->properlyDominates(BB, Common))
  144. return false;
  145. std::set<BasicBlock *> Region;
  146. if (!this->FindDeadRegion(Common, BB, Region))
  147. return false;
  148. // If BB branches INTO the region, forming a loop give up.
  149. for (BasicBlock *Succ : successors(BB))
  150. if (Region.count(Succ))
  151. return false;
  152. // Replace Common's branch with an unconditional branch to BB
  153. Common->getTerminator()->eraseFromParent();
  154. BranchInst::Create(BB, Common);
  155. // Delete the region
  156. for (BasicBlock *BB : Region) {
  157. for (Instruction &I : *BB)
  158. I.dropAllReferences();
  159. BB->dropAllReferences();
  160. }
  161. for (BasicBlock *BB : Region) {
  162. while (BB->begin() != BB->end())
  163. BB->begin()->eraseFromParent();
  164. BB->eraseFromParent();
  165. }
  166. return true;
  167. }
  168. void getAnalysisUsage(AnalysisUsage &AU) const override {
  169. AU.addRequired<DominatorTreeWrapperPass>();
  170. AU.addRequired<PostDominatorTree>();
  171. }
  172. bool runOnFunction(Function &F) override {
  173. auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
  174. auto *PDT = &getAnalysis<PostDominatorTree>();
  175. std::unordered_set<BasicBlock *> FailedSet;
  176. bool Changed = false;
  177. while (1) {
  178. bool LocalChanged = false;
  179. for (Function::iterator It = F.begin(), E = F.end(); It != E; It++) {
  180. BasicBlock &BB = *It;
  181. if (FailedSet.count(&BB))
  182. continue;
  183. if (this->TrySimplify(DT, PDT, &BB)) {
  184. LocalChanged = true;
  185. break;
  186. }
  187. else {
  188. FailedSet.insert(&BB);
  189. }
  190. }
  191. Changed |= LocalChanged;
  192. if (!LocalChanged)
  193. break;
  194. }
  195. return Changed;
  196. }
  197. };
  198. char DxilEraseDeadRegion::ID;
  199. Pass *llvm::createDxilEraseDeadRegionPass() {
  200. return new DxilEraseDeadRegion();
  201. }
  202. INITIALIZE_PASS_BEGIN(DxilEraseDeadRegion, "dxil-erase-dead-region", "Dxil Erase Dead Region", false, false)
  203. INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
  204. INITIALIZE_PASS_DEPENDENCY(PostDominatorTree)
  205. INITIALIZE_PASS_END(DxilEraseDeadRegion, "dxil-erase-dead-region", "Dxil Erase Dead Region", false, false)