Coverage Report

Created: 2023-10-30 17:15

/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