2
0

ReducibilityAnalysis.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // ReducibilityAnalysis.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 "llvm/Analysis/ReducibilityAnalysis.h"
  10. #include "dxc/Support/Global.h"
  11. #include "llvm/IR/LLVMContext.h"
  12. #include "llvm/IR/Module.h"
  13. #include "llvm/IR/Function.h"
  14. #include "llvm/Pass.h"
  15. #include "llvm/IR/LegacyPassManager.h"
  16. #include "llvm/Support/Debug.h"
  17. #include "llvm/Support/raw_ostream.h"
  18. #include "llvm/IR/CFG.h"
  19. #include <vector>
  20. #include <unordered_map>
  21. #include <unordered_set>
  22. #include <algorithm>
  23. using namespace llvm;
  24. using llvm::legacy::PassManager;
  25. using llvm::legacy::FunctionPassManager;
  26. using std::vector;
  27. using std::unordered_map;
  28. using std::unordered_set;
  29. #define DEBUG_TYPE "reducibility"
  30. //===----------------------------------------------------------------------===//
  31. // Reducibility Analysis Pass
  32. //
  33. // The pass implements T1-T2 graph reducibility test.
  34. // The algorithm can be found in "Engineering a Compiler" text by
  35. // Keith Cooper and Linda Torczon.
  36. //
  37. //===----------------------------------------------------------------------===//
  38. namespace ReducibilityAnalysisNS {
  39. class ReducibilityAnalysis : public FunctionPass {
  40. public:
  41. static char ID;
  42. ReducibilityAnalysis()
  43. : FunctionPass(ID), m_Action(IrreducibilityAction::ThrowException),
  44. m_bReducible(true) {}
  45. explicit ReducibilityAnalysis(IrreducibilityAction Action)
  46. : FunctionPass(ID), m_Action(Action), m_bReducible(true) {}
  47. virtual bool runOnFunction(Function &F);
  48. virtual void getAnalysisUsage(AnalysisUsage &AU) const {
  49. AU.setPreservesAll();
  50. }
  51. bool IsReducible() const { return m_bReducible; }
  52. private:
  53. IrreducibilityAction m_Action;
  54. bool m_bReducible;
  55. };
  56. char ReducibilityAnalysis::ID = 0;
  57. struct Node {
  58. typedef unordered_set<unsigned> IdxSet;
  59. IdxSet m_Succ;
  60. IdxSet m_Pred;
  61. };
  62. class NodeWorklist {
  63. public:
  64. NodeWorklist(size_t MaxSize) : m_Size(0) { m_Data.resize(MaxSize); }
  65. size_t Size() const { return m_Size; }
  66. unsigned Get(size_t idx) const { return m_Data[idx]; }
  67. void PushBack(unsigned Val) { m_Data[m_Size++] = Val; }
  68. void Clear() { m_Size = 0; }
  69. private:
  70. size_t m_Size;
  71. vector<unsigned> m_Data;
  72. };
  73. static bool IsEntryNode(size_t NodeIdx) {
  74. return NodeIdx == 0;
  75. }
  76. bool ReducibilityAnalysis::runOnFunction(Function &F) {
  77. m_bReducible = true;
  78. if (F.empty()) return false;
  79. IFTBOOL(F.size() < UINT32_MAX, DXC_E_DATA_TOO_LARGE);
  80. vector<Node> Nodes(F.size());
  81. unordered_map<BasicBlock*, unsigned> BasicBlockToNodeIdxMap;
  82. //
  83. // Initialize.
  84. //
  85. unsigned iNode = 0;
  86. for (BasicBlock &BB : F) {
  87. BasicBlockToNodeIdxMap[&BB] = iNode++;
  88. }
  89. for (BasicBlock &BB : F) {
  90. BasicBlock *pBB = &BB;
  91. unsigned N = BasicBlockToNodeIdxMap[pBB];
  92. for (succ_iterator itSucc = succ_begin(pBB), endSucc = succ_end(pBB); itSucc != endSucc; ++itSucc) {
  93. BasicBlock *pSuccBB = *itSucc;
  94. unsigned SuccNode = BasicBlockToNodeIdxMap[pSuccBB];
  95. Nodes[N].m_Succ.insert(SuccNode);
  96. }
  97. for (pred_iterator itPred = pred_begin(pBB), endPred = pred_end(pBB); itPred != endPred; ++itPred) {
  98. BasicBlock *pPredBB = *itPred;
  99. unsigned PredNode = BasicBlockToNodeIdxMap[pPredBB];
  100. Nodes[N].m_Pred.insert(PredNode);
  101. }
  102. }
  103. //
  104. // Reduce.
  105. //
  106. NodeWorklist Q1(Nodes.size()), Q2(Nodes.size());
  107. NodeWorklist *pReady = &Q1, *pWaiting = &Q2;
  108. for (unsigned i = 0; i < Nodes.size(); i++) {
  109. pReady->PushBack(i);
  110. }
  111. for (;;) {
  112. bool bChanged = false;
  113. pWaiting->Clear();
  114. for (unsigned iNode = 0; iNode < pReady->Size(); iNode++) {
  115. unsigned N = pReady->Get(iNode);
  116. Node *pNode = &Nodes[N];
  117. // T1: self-edge.
  118. auto itSucc = pNode->m_Succ.find(N);
  119. if (itSucc != pNode->m_Succ.end()) {
  120. pWaiting->PushBack(N);
  121. pNode->m_Succ.erase(itSucc);
  122. auto s1 = pNode->m_Pred.erase(N); DXASSERT_LOCALVAR(s1, s1 == 1, "otherwise check Pred/Succ sets");
  123. bChanged = true;
  124. continue;
  125. }
  126. // T2: single predecessor.
  127. if (pNode->m_Pred.size() == 1) {
  128. unsigned PredNode = *pNode->m_Pred.begin();
  129. Node *pPredNode = &Nodes[PredNode];
  130. auto s1 = pPredNode->m_Succ.erase(N); DXASSERT_LOCALVAR(s1, s1 == 1, "otherwise check Pred/Succ sets");
  131. // Do not update N's sets, as N is discarded and never looked at again.
  132. for (auto itSucc = pNode->m_Succ.begin(), endSucc = pNode->m_Succ.end(); itSucc != endSucc; ++itSucc) {
  133. unsigned SuccNode = *itSucc;
  134. Node *pSuccNode = &Nodes[SuccNode];
  135. auto s2 = pSuccNode->m_Pred.erase(N); DXASSERT_LOCALVAR(s2, s2, "otherwise check Pred/Succ sets");
  136. pPredNode->m_Succ.insert(SuccNode);
  137. pSuccNode->m_Pred.insert(PredNode);
  138. }
  139. bChanged = true;
  140. continue;
  141. }
  142. // Unreachable.
  143. if (pNode->m_Pred.size() == 0 && !IsEntryNode(N)) {
  144. for (auto itSucc = pNode->m_Succ.begin(), endSucc = pNode->m_Succ.end(); itSucc != endSucc; ++itSucc) {
  145. unsigned SuccNode = *itSucc;
  146. Node *pSuccNode = &Nodes[SuccNode];
  147. auto s1 = pSuccNode->m_Pred.erase(N); DXASSERT_LOCALVAR(s1, s1, "otherwise check Pred/Succ sets");
  148. }
  149. bChanged = true;
  150. continue;
  151. }
  152. // Could not reduce.
  153. pWaiting->PushBack(N);
  154. }
  155. if (pWaiting->Size() == 1) {
  156. break;
  157. }
  158. if (!bChanged) {
  159. m_bReducible = false;
  160. break;
  161. }
  162. std::swap(pReady, pWaiting);
  163. }
  164. if (!IsReducible()) {
  165. switch (m_Action) {
  166. case IrreducibilityAction::ThrowException:
  167. DEBUG(dbgs() << "Function '" << F.getName() << "' is irreducible. Aborting compilation.\n");
  168. IFT(DXC_E_IRREDUCIBLE_CFG);
  169. break;
  170. case IrreducibilityAction::PrintLog:
  171. DEBUG(dbgs() << "Function '" << F.getName() << "' is irreducible\n");
  172. break;
  173. case IrreducibilityAction::Ignore:
  174. break;
  175. default:
  176. DXASSERT(false, "otherwise incorrect action passed to the constructor");
  177. }
  178. }
  179. return false;
  180. }
  181. }
  182. using namespace ReducibilityAnalysisNS;
  183. // Publicly exposed interface to pass...
  184. char &llvm::ReducibilityAnalysisID = ReducibilityAnalysis::ID;
  185. INITIALIZE_PASS_BEGIN(ReducibilityAnalysis, "red", "Reducibility Analysis", true, true)
  186. INITIALIZE_PASS_END(ReducibilityAnalysis, "red", "Reducibility Analysis", true, true)
  187. namespace llvm {
  188. FunctionPass *createReducibilityAnalysisPass(IrreducibilityAction Action) {
  189. return new ReducibilityAnalysis(Action);
  190. }
  191. bool IsReducible(const Module &M, IrreducibilityAction Action) {
  192. PassManager PM;
  193. ReducibilityAnalysis *pRA = new ReducibilityAnalysis(Action);
  194. PM.add(pRA);
  195. PM.run(const_cast<Module&>(M));
  196. return pRA->IsReducible();
  197. }
  198. bool IsReducible(const Function &f, IrreducibilityAction Action) {
  199. Function &F = const_cast<Function&>(f);
  200. DXASSERT(!F.isDeclaration(), "otherwise the caller is asking to check an external function");
  201. FunctionPassManager FPM(F.getParent());
  202. ReducibilityAnalysis *pRA = new ReducibilityAnalysis(Action);
  203. FPM.add(pRA);
  204. FPM.doInitialization();
  205. FPM.run(F);
  206. return pRA->IsReducible();
  207. }
  208. }