/builds/2mk6rsew/0/parcoach/parcoach/src/include/parcoach/CFGVisitors.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include "parcoach/CollectiveList.h" |
4 | | |
5 | | #include "llvm/ADT/DenseMap.h" |
6 | | #include "llvm/ADT/SCCIterator.h" |
7 | | #include "llvm/ADT/SetVector.h" |
8 | | #include "llvm/Analysis/LoopInfo.h" |
9 | | #include "llvm/IR/Function.h" |
10 | | #include "llvm/IR/ValueMap.h" |
11 | | |
12 | | #include <vector> |
13 | | |
14 | | namespace parcoach { |
15 | | |
16 | | using BBToBBMap = llvm::DenseMap<llvm::BasicBlock *, llvm::BasicBlock *>; |
17 | | using BBToVectorBBMap = |
18 | | llvm::DenseMap<llvm::BasicBlock *, |
19 | | llvm::SmallSetVector<llvm::BasicBlock *, 8>>; |
20 | | enum class NodeState { |
21 | | UNVISITED = 0, |
22 | | PUSHED, |
23 | | VISITED, |
24 | | }; |
25 | | |
26 | | struct LoopAggretationInfo { |
27 | | BBToVectorBBMap LoopHeaderToSuccessors; |
28 | | BBToBBMap LoopHeaderToIncomingBlock; |
29 | | BBToBBMap LoopSuccessorToLoopHeader; |
30 | | llvm::LoopInfo const *LI{}; |
31 | | void clear(); |
32 | | }; |
33 | | |
34 | | using VisitedMapTy = llvm::ValueMap<llvm::BasicBlock *, NodeState>; |
35 | | |
36 | | // This is a top-down BFS that visit loops from the innermost to the outermost. |
37 | | // It also computes the successors for each loop "as a whole", as well |
38 | | // as predecessors (ie: matching loop headers) for these successors. |
39 | | template <typename Derived> class LoopVisitor { |
40 | 1.86k | Derived &getDerived() { return *static_cast<Derived *>(this); } |
41 | 1.82k | void ComputeReversedMap() { |
42 | 1.82k | for (auto &[Header, Successors] : LAI_.LoopHeaderToSuccessors) { |
43 | 449 | for (llvm::BasicBlock *Succ : Successors) { |
44 | 449 | assert(LAI_.LoopSuccessorToLoopHeader.count(Succ) == 0 && |
45 | 449 | "Unexpected number of successors"); |
46 | 449 | LAI_.LoopSuccessorToLoopHeader[Succ] = Header; |
47 | 449 | } |
48 | 447 | } |
49 | 1.82k | } |
50 | | |
51 | 456 | void Visit(llvm::Loop &L, llvm::LoopInfo &LI) { |
52 | 456 | for (llvm::Loop *SubLoop : L) { |
53 | 9 | Visit(*SubLoop, LI); |
54 | 9 | } |
55 | 456 | std::deque<llvm::BasicBlock *> Queue; |
56 | 456 | VisitedMapTy Visited; |
57 | | // Make sure we register our loop. |
58 | 456 | auto *Start = L.getHeader(); |
59 | 456 | LAI_.LoopHeaderToSuccessors[Start] = {}; |
60 | 456 | Queue.emplace_back(Start); |
61 | 456 | Visited[Start] = NodeState::PUSHED; |
62 | 456 | llvm::BasicBlock *Incoming, *BackEdge; |
63 | | |
64 | 456 | if (!L.getIncomingAndBackEdge(Incoming, BackEdge)) { |
65 | | // This is a dead loop, just ignore it. |
66 | 0 | return; |
67 | 0 | } |
68 | | |
69 | 456 | LAI_.LoopHeaderToIncomingBlock[Start] = Incoming; |
70 | 1.86k | while (!Queue.empty()) { |
71 | 1.40k | llvm::BasicBlock *BB = Queue.front(); |
72 | 1.40k | Queue.pop_front(); |
73 | | |
74 | 1.40k | auto IsDone = [&](llvm::BasicBlock *Succ) { |
75 | 959 | return Visited[Succ] == NodeState::VISITED; |
76 | 959 | }; |
77 | | |
78 | | // If the BB is not a loop header, check all predecessors are done! |
79 | 1.40k | if (!LAI_.LoopHeaderToIncomingBlock.count(BB) && |
80 | 1.40k | !llvm::all_of(llvm::predecessors(BB), IsDone)) { |
81 | 3 | Queue.push_back(BB); |
82 | 3 | continue; |
83 | 3 | } |
84 | | |
85 | 1.40k | Visited[BB] = NodeState::VISITED; |
86 | 1.40k | getDerived().visitBB(L, BB); |
87 | 1.87k | auto EnqueueBB = [&](llvm::BasicBlock *BB) { |
88 | 1.87k | if (Visited[BB] == NodeState::UNVISITED) { |
89 | 1.40k | if (L.contains(BB)) { |
90 | 950 | Visited[BB] = NodeState::PUSHED; |
91 | 950 | Queue.emplace_back(BB); |
92 | 950 | } else { |
93 | 458 | LAI_.LoopHeaderToSuccessors[Start].insert(BB); |
94 | 458 | } |
95 | 1.40k | } |
96 | 1.87k | }; |
97 | | |
98 | | // Try to see if the current BB is a header for a loop other than ours. |
99 | 1.40k | llvm::Loop const *LoopForBB = LI[BB]; |
100 | 1.40k | if (BB != Start && LoopForBB && BB == LoopForBB->getHeader()) { |
101 | 9 | llvm::for_each(LAI_.LoopHeaderToSuccessors[LoopForBB->getHeader()], |
102 | 9 | EnqueueBB); |
103 | | // We just "ate" an inner loop, remove its successors. |
104 | 9 | LAI_.LoopHeaderToSuccessors.erase(LoopForBB->getHeader()); |
105 | 1.39k | } else { |
106 | 1.39k | llvm::for_each(successors(BB), EnqueueBB); |
107 | 1.39k | } |
108 | 1.40k | } |
109 | 456 | getDerived().endOfLoop(L); |
110 | 456 | } |
111 | | |
112 | | protected: |
113 | | LoopAggretationInfo LAI_; |
114 | | |
115 | | public: |
116 | 1.82k | void Visit(llvm::Function &F, llvm::FunctionAnalysisManager &FAM) { |
117 | 1.82k | LAI_.clear(); |
118 | 1.82k | llvm::LoopInfo &LI = FAM.getResult<llvm::LoopAnalysis>(F); |
119 | 1.82k | LAI_.LI = &LI; |
120 | 1.82k | for (llvm::Loop *L : LI) { |
121 | 447 | Visit(*L, LI); |
122 | 447 | } |
123 | 1.82k | ComputeReversedMap(); |
124 | 1.82k | } |
125 | | }; |
126 | | |
127 | | template <typename Derived> class CFGVisitor { |
128 | 14.1k | Derived &getDerived() { return *static_cast<Derived *>(this); } |
129 | | |
130 | | protected: |
131 | | llvm::ModuleAnalysisManager &AM; |
132 | | |
133 | | public: |
134 | 1.76k | CFGVisitor(llvm::ModuleAnalysisManager &MAM) : AM(MAM) {} |
135 | | |
136 | 1.82k | void Visit(llvm::Function &F, LoopAggretationInfo const &Res) { |
137 | 1.82k | VisitedMapTy Visited; |
138 | | |
139 | 1.82k | auto const &PredsMap = Res.LoopSuccessorToLoopHeader; |
140 | 1.82k | auto const &SuccsMap = Res.LoopHeaderToSuccessors; |
141 | 1.82k | auto const &IncomingMap = Res.LoopHeaderToIncomingBlock; |
142 | 1.82k | assert(Res.LI && "LoopInfo should be populated"); |
143 | 1.82k | auto const &LI = *Res.LI; |
144 | | |
145 | 1.82k | std::deque<llvm::BasicBlock *> Queue; |
146 | | |
147 | 15.0k | auto HasNoSucc = [](llvm::BasicBlock &BB) { |
148 | 15.0k | return llvm::succ_size(&BB) == 0; |
149 | 15.0k | }; |
150 | 1.83k | for (auto &Exit : make_filter_range(F, HasNoSucc)) { |
151 | 1.83k | Visited[&Exit] = NodeState::PUSHED; |
152 | 1.83k | Queue.push_back(&Exit); |
153 | 1.83k | } |
154 | 1.82k | assert(!Queue.empty() && "No exit nodes?!"); |
155 | | |
156 | 16.0k | while (!Queue.empty()) { |
157 | 14.2k | llvm::BasicBlock *BB = Queue.front(); |
158 | 14.2k | Queue.pop_front(); |
159 | 17.4k | auto IsDone = [&](llvm::BasicBlock *Succ) { |
160 | 17.4k | return Visited[Succ] == NodeState::VISITED; |
161 | 17.4k | }; |
162 | | // Check if this BB belongs to a loop |
163 | 14.2k | bool IsLoopHeader = SuccsMap.count(BB); |
164 | | // If visiting a loop header, the succesors are the loop's successors! |
165 | 14.2k | bool AllDone = IsLoopHeader |
166 | 14.2k | ? llvm::all_of(SuccsMap.find(BB)->second, IsDone) |
167 | 14.2k | : llvm::all_of(llvm::successors(BB), IsDone); |
168 | | // All successors are not visited, postpone the handling. |
169 | 14.2k | if (!AllDone) { |
170 | 64 | Queue.push_back(BB); |
171 | 64 | continue; |
172 | 64 | } |
173 | | |
174 | 14.1k | Visited[BB] = NodeState::VISITED; |
175 | 14.1k | if (IsLoopHeader) { |
176 | 447 | getDerived().visitBB(BB, &Res); |
177 | 13.6k | } else { |
178 | 13.6k | getDerived().visitBB(BB); |
179 | 13.6k | } |
180 | 17.3k | auto EnqueueBB = [&](llvm::BasicBlock *Current) { |
181 | 17.3k | if (Visited[Current] == NodeState::UNVISITED) { |
182 | 12.3k | Visited[Current] = NodeState::PUSHED; |
183 | 12.3k | Queue.push_back(Current); |
184 | 12.3k | } |
185 | 17.3k | }; |
186 | 14.1k | if (IsLoopHeader) { |
187 | | // If BB is a loop header, it should have a single incoming edge, |
188 | | // add it. |
189 | 447 | EnqueueBB(IncomingMap.find(BB)->second); |
190 | 13.6k | } else if (PredsMap.count(BB)) { |
191 | 449 | llvm::BasicBlock *Header = PredsMap.find(BB)->second; |
192 | | // This BB was a successor of a loop: we want its predecessors to be the |
193 | | // header loop itself. |
194 | 449 | EnqueueBB(Header); |
195 | | // As well as any other predecessors that may be something else than a |
196 | | // loop. |
197 | 449 | assert(LI[Header] && "BB Must be in a loop if it's in PredsMap"); |
198 | 449 | llvm::Loop const &L = *LI[Header]; |
199 | 449 | auto EnqueuePred = [&](llvm::BasicBlock *Pred) { |
200 | 449 | if (!L.contains(Pred)) { |
201 | 0 | EnqueueBB(Pred); |
202 | 0 | } |
203 | 449 | }; |
204 | 449 | llvm::for_each(llvm::predecessors(BB), EnqueuePred); |
205 | 13.2k | } else { |
206 | | // Else just add all preds. |
207 | 13.2k | llvm::for_each(llvm::predecessors(BB), EnqueueBB); |
208 | 13.2k | } |
209 | 14.1k | } |
210 | 1.82k | } |
211 | | }; |
212 | | |
213 | | } // namespace parcoach |