Skip to content

Commit 7b3bc0a

Browse files
Implement loop_info analysis pass
This commit adds the analysis pass to find natural loops and subloops. It uses the algorithm from LLVM LoopInfo anaylsis pass for the same, heavily uses the dominance tree to find the backedges and loop headers.
1 parent 3e3518e commit 7b3bc0a

File tree

5 files changed

+179
-15
lines changed

5 files changed

+179
-15
lines changed

include/blocks/dominance.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,26 @@ class dominator_analysis {
1818
// std::vector<std::shared_ptr<dominator_tree_>> child_nodes;
1919
// } dominator_tree;
2020
dominator_analysis(basic_block::cfg_block &cfg);
21+
basic_block::cfg_block &cfg_;
2122
std::vector<int> &get_postorder_bb_map();
2223
std::vector<int> &get_postorder();
2324
std::vector<int> &get_idom();
2425
std::map<int, std::vector<int>> &get_idom_map();
26+
std::vector<int> &get_postorder_idom_map();
2527
int get_idom(int bb_id);
2628
std::vector<int> get_idom_map(int bb_id);
29+
int get_postorder_idom_map(int idom_id);
2730
bool dominates(int bb1_id, int bb2_id);
2831
bool is_reachable_from_entry(int bb_id);
2932
void analyze();
3033

3134
private:
3235
std::vector<int> idom;
3336
std::map<int, std::vector<int>> idom_map;
37+
std::vector<int> postorder_idom;
3438
std::vector<int> postorder;
3539
std::vector<int> postorder_bb_map;
36-
basic_block::cfg_block &cfg_;
40+
void postorder_idom_helper(std::vector<bool> &visited, int id);
3741
void postorder_dfs_helper(std::vector<bool> &visited_bbs, int id);
3842
void postorder_dfs();
3943
int intersect(int bb1_id, int bb2_id);

include/blocks/loops.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
using namespace block;
99
class loop {
1010
public:
11-
loop() = default;
11+
loop(std::shared_ptr<basic_block> header): header_block(header) {}
1212

13-
private:
13+
// private:
1414
struct loop_bounds_ {
1515
stmt::Ptr ind_var;
1616
// MISS: intial value of ind var
@@ -22,17 +22,26 @@ class loop {
2222
stmt::Ptr entry_stmt;
2323
} loop_bounds;
2424

25-
basic_block::cfg_block exit_bbs;
25+
basic_block::cfg_block blocks;
26+
std::shared_ptr<loop> parent_loop;
27+
std::shared_ptr<basic_block> header_block;
28+
std::shared_ptr<basic_block> backedge_block;
29+
std::vector<std::shared_ptr<loop>> subloops;
2630
};
2731

2832
class loop_info {
2933
public:
30-
loop_info(basic_block::cfg_block ast, dominator_analysis dt): parent_ast(ast), dta(dt) {
34+
loop_info(basic_block::cfg_block ast, dominator_analysis &dt): parent_ast(ast), dta(dt) {
3135
analyze();
3236
}
37+
std::shared_ptr<loop> allocate_loop(std::shared_ptr<basic_block> header);
38+
std::vector<std::shared_ptr<loop>> loops;
39+
std::vector<std::shared_ptr<loop>> top_level_loops;
40+
3341
private:
3442
basic_block::cfg_block parent_ast;
3543
dominator_analysis dta;
44+
std::map<int, std::shared_ptr<loop>> bb_loop_map;
3645
// discover loops during traversal of the abstract syntax tree
3746
void analyze();
3847
};

src/blocks/dominance.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ dominator_analysis::dominator_analysis(basic_block::cfg_block &cfg) : cfg_(cfg)
1414
analyze();
1515
}
1616

17+
void dominator_analysis::postorder_idom_helper(std::vector<bool> &visited, int id) {
18+
for (int idom_id: idom_map[id]) {
19+
std::cerr << idom_id << "\n";
20+
if (idom_id != -1 && !visited[idom_id]) {
21+
visited[idom_id] = true;
22+
postorder_idom_helper(visited, idom_id);
23+
postorder_idom.push_back(idom_id);
24+
}
25+
}
26+
}
27+
1728
void dominator_analysis::postorder_dfs_helper(std::vector<bool> &visited_bbs, int id) {
1829
for (auto child: cfg_[id]->successor) {
1930
if (!visited_bbs[child->id]) {
@@ -48,6 +59,10 @@ std::map<int, std::vector<int>> &dominator_analysis::get_idom_map() {
4859
return idom_map;
4960
}
5061

62+
std::vector<int> &dominator_analysis::get_postorder_idom_map() {
63+
return postorder_idom;
64+
}
65+
5166
int dominator_analysis::get_idom(int bb_id) {
5267
if (bb_id < 0 || bb_id >= (int)idom.size()) {
5368
return -1;
@@ -64,6 +79,14 @@ std::vector<int> dominator_analysis::get_idom_map(int bb_id) {
6479
return idom_map[bb_id];
6580
}
6681

82+
int dominator_analysis::get_postorder_idom_map(int idom_id) {
83+
if (idom_id < 0 || idom_id >= (int)postorder_idom.size()) {
84+
return -1;
85+
}
86+
87+
return postorder_idom[idom_id];
88+
}
89+
6790
bool dominator_analysis::dominates(int bb1_id, int bb2_id) {
6891
if (bb1_id == 0) {
6992
return true;
@@ -138,11 +161,11 @@ void dominator_analysis::analyze() {
138161
idom_map[i].push_back(-1);
139162
}
140163

141-
// for (auto key: idom_map) {
142-
// std::cout << key.first << ": ";
143-
// for (int id: key.second) {
144-
// std::cout << id << " ";
145-
// }
146-
// std::cout << "\n";
147-
// }
164+
// build a postorder visit list of idom_tree
165+
std::vector<bool> visited_idom_nodes(idom_map.size());
166+
visited_idom_nodes.assign(visited_idom_nodes.size(), false);
167+
visited_idom_nodes[0] = true;
168+
169+
postorder_idom_helper(visited_idom_nodes, 0);
170+
postorder_idom.push_back(0);
148171
}

src/blocks/loops.cpp

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,114 @@
11
#include "blocks/loops.h"
22
#include <algorithm>
33

4+
std::shared_ptr<loop> loop_info::allocate_loop(std::shared_ptr<basic_block> header) {
5+
if (!header)
6+
return nullptr;
7+
8+
loops.push_back(std::make_shared<loop>(header));
9+
bb_loop_map[header->id] = loops.back();
10+
return loops.back();
11+
}
12+
413
void loop_info::analyze() {
514
std::vector<int> idom = dta.get_idom();
6-
for (unsigned int i = 0; i < idom.size(); i++) {
7-
std::cout << i << " : " << idom[i] << "\n";
15+
16+
for (int idom_id: dta.get_postorder_idom_map()) {
17+
std::vector<int> backedges;
18+
int header = idom_id;
19+
20+
for (auto backedge: dta.cfg_[header]->predecessor) {
21+
if (dta.dominates(header, backedge->id) && dta.is_reachable_from_entry(backedge->id)) {
22+
backedges.push_back(backedge->id);
23+
}
24+
}
25+
26+
if (!backedges.empty()) {
27+
std::shared_ptr<loop> new_loop = allocate_loop(dta.cfg_[header]);
28+
if (!new_loop)
29+
continue;
30+
31+
int num_blocks = 0;
32+
int num_subloops = 0;
33+
34+
auto backedge_iter = backedges.begin();
35+
// do a reverse CFG traversal to map basic blocks in this loop.
36+
basic_block::cfg_block worklist(backedges.size());
37+
std::generate(worklist.begin(), worklist.end(), [&backedge_iter, this](){
38+
return dta.cfg_[*(backedge_iter++)];
39+
});
40+
41+
while (!worklist.empty()) {
42+
unsigned int predecessor_bb_id = worklist.back()->id;
43+
worklist.pop_back();
44+
45+
auto subloop_iter = bb_loop_map.find(predecessor_bb_id);
46+
if (subloop_iter == bb_loop_map.end()) {
47+
if (!dta.is_reachable_from_entry(predecessor_bb_id))
48+
continue;
49+
50+
bb_loop_map[predecessor_bb_id] = new_loop;
51+
++num_blocks;
52+
// loop has no blocks between header and backedge
53+
if (predecessor_bb_id == new_loop->header_block->id)
54+
continue;
55+
56+
worklist.insert(worklist.end(), dta.cfg_[predecessor_bb_id]->predecessor.begin(), dta.cfg_[predecessor_bb_id]->predecessor.end());
57+
}
58+
else {
59+
// this block has already been discovered, mapped to some other loop
60+
// find the outermost loop
61+
std::shared_ptr<loop> subloop = subloop_iter->second;
62+
while (subloop->parent_loop) {
63+
subloop = subloop->parent_loop;
64+
}
65+
66+
if (subloop == new_loop)
67+
continue;
68+
69+
// discovered a subloop of this loop
70+
subloop->parent_loop = new_loop;
71+
++num_subloops;
72+
num_blocks = num_blocks + subloop->blocks.size();
73+
predecessor_bb_id = subloop->header_block->id;
74+
75+
for (auto pred: dta.cfg_[predecessor_bb_id]->predecessor) {
76+
auto loop_iter = bb_loop_map.find(pred->id);
77+
// do not check if loop_iter != bb_loop_map.end(), as a results
78+
// basic blocks that are not directly part of the natural loops
79+
// are skipped, like loop latches.
80+
if (loop_iter->second != subloop)
81+
worklist.push_back(pred);
82+
}
83+
}
84+
}
85+
new_loop->subloops.reserve(num_subloops);
86+
new_loop->blocks.reserve(num_blocks);
87+
}
888
}
9-
}
89+
90+
// populate all subloops and loops with blocks
91+
for (auto bb_id: dta.get_postorder()) {
92+
auto subloop_iter = bb_loop_map.find(bb_id);
93+
std::shared_ptr<loop> subloop = nullptr;
94+
if (subloop_iter != bb_loop_map.end() && (subloop = subloop_iter->second) && dta.cfg_[bb_id] == subloop_iter->second->header_block) {
95+
// check if it is the outermost loop
96+
if (subloop->parent_loop != nullptr) {
97+
subloop->parent_loop->subloops.push_back(subloop);
98+
}
99+
else {
100+
top_level_loops.push_back(subloop);
101+
}
102+
103+
std::reverse(subloop->blocks.begin(), subloop->blocks.end());
104+
std::reverse(subloop->subloops.begin(), subloop->subloops.end());
105+
106+
subloop = subloop->parent_loop;
107+
}
108+
109+
while (subloop) {
110+
subloop->blocks.push_back(dta.cfg_[bb_id]);
111+
subloop = subloop->parent_loop;
112+
}
113+
}
114+
}

src/builder/builder_context.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,32 @@ block::stmt::Ptr builder_context::extract_ast_from_function_impl(void) {
356356
}
357357
std::cerr << "== idom map ==\n";
358358

359+
std::cerr << "== postorder idom ==\n";
360+
for (auto idom: dom.get_postorder_idom_map()) {
361+
std::cerr << idom << "\n";
362+
}
363+
std::cerr << "== postorder idom ==\n";
364+
359365
std::cerr << "++++++ dominance ++++++ \n";
360366

367+
std::cerr << "++++++ loop info ++++++ \n";
361368
loop_info LI(BBs, dom);
369+
int loop_num = 0;
370+
for (auto loop: LI.loops) {
371+
std::cerr << "++++++ loop " << loop_num++ << " ++++++ \n";
372+
373+
std::cerr << "loop headers: " << loop->header_block->id << "\n";
374+
std::cerr << "blocks: ";
375+
for (auto bb: loop->blocks) std::cerr << bb->id << " ";
376+
std::cerr << "\n";
377+
// std::cerr << "backedge: " << loop->backedge_block->id << "\n";
378+
std::cerr << "parent loop: (loop header: " << (loop->parent_loop ? (int)loop->parent_loop->header_block->id : -1) << ")\n";
379+
std::cerr << "subloops: ";
380+
for (auto subl: loop->subloops) std::cerr << "(loop header: " << subl->header_block->id << ") ";
381+
std::cerr << "\n";
382+
}
383+
std::cerr << "++++++ loop info ++++++ \n";
384+
362385
if (feature_unstructured)
363386
return ast;
364387

0 commit comments

Comments
 (0)