Skip to content

Commit 51a3213

Browse files
Add support for basic blocks and CFGs
Added class for representing basic blocks, and a helper function to generate basic blocks from AST. For testing, disabled the loop_finder code.
1 parent 73e3041 commit 51a3213

File tree

4 files changed

+211
-14
lines changed

4 files changed

+211
-14
lines changed

include/blocks/basic_blocks.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifndef BASIC_BLOCKS_H
2+
#define BASIC_BLOCKS_H
3+
#include "blocks/block_visitor.h"
4+
#include "blocks/stmt.h"
5+
#include <vector>
6+
#include <deque>
7+
#include <string>
8+
9+
class basic_block {
10+
public:
11+
basic_block(std::string label): name(label) {};
12+
13+
std::vector<std::shared_ptr<basic_block>> predecessor;
14+
std::vector<std::shared_ptr<basic_block>> successor;
15+
block::expr::Ptr branch_expr;
16+
block::stmt::Ptr parent;
17+
std::string name;
18+
};
19+
20+
std::vector<std::shared_ptr<basic_block>> generate_basic_blocks(block::stmt_block::Ptr ast);
21+
22+
#endif

include/blocks/loop_finder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define LOOP_FINDER_H
33
#include "blocks/block_visitor.h"
44
#include "blocks/stmt.h"
5+
#include "blocks/basic_blocks.h"
56

67
namespace block {
78
class loop_finder : public block_visitor {

src/blocks/basic_blocks.cpp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#include "blocks/basic_blocks.h"
2+
#include <algorithm>
3+
4+
using namespace block;
5+
6+
std::vector<std::shared_ptr<basic_block>> generate_basic_blocks(block::stmt_block::Ptr ast) {
7+
std::deque<std::shared_ptr<basic_block>> work_list;
8+
std::vector<std::shared_ptr<basic_block>> return_list;
9+
int basic_block_count = 0;
10+
11+
// step 1: fill the work_list
12+
for (auto st: ast->stmts) {
13+
auto bb = std::make_shared<basic_block>(std::to_string(basic_block_count));
14+
bb->parent = st;
15+
work_list.push_back(bb);
16+
basic_block_count++;
17+
}
18+
19+
// step 2: add successors
20+
for (unsigned i = 0; work_list.size() != 0 && i < work_list.size() - 1; i++) {
21+
work_list[i]->successor.push_back(work_list[i+1]);
22+
}
23+
24+
// step 3: process blocks
25+
while (work_list.size()) {
26+
auto bb = work_list.front();
27+
28+
if (isa<block::stmt_block>(bb->parent)) {
29+
stmt_block::Ptr stmt_block_ = to<stmt_block>(bb->parent);
30+
bb->name = "stmt" + bb->name;
31+
32+
if (stmt_block_->stmts.size() > 0) {
33+
std::vector<std::shared_ptr<basic_block>> stmt_block_list;
34+
35+
for (auto st: stmt_block_->stmts) {
36+
stmt_block_list.push_back(std::make_shared<basic_block>(std::to_string(basic_block_count++)));
37+
stmt_block_list.back()->parent = st;
38+
}
39+
40+
for (unsigned i = 0; stmt_block_list.size() != 0 && i < stmt_block_list.size() - 1; i++) {
41+
stmt_block_list[i]->successor.push_back(stmt_block_list[i+1]);
42+
}
43+
44+
stmt_block_list.back()->successor.push_back(bb->successor.front());
45+
bb->successor.clear();
46+
bb->successor.push_back(stmt_block_list.front());
47+
48+
return_list.push_back(bb);
49+
work_list.pop_front();
50+
work_list.insert(work_list.begin(), stmt_block_list.begin(), stmt_block_list.end());
51+
}
52+
else {
53+
return_list.push_back(bb);
54+
work_list.pop_front();
55+
}
56+
}
57+
else if (isa<if_stmt>(bb->parent)) {
58+
bb->name = "if" + bb->name;
59+
60+
if_stmt::Ptr if_stmt_ = to<if_stmt>(bb->parent);
61+
// assign the if condition to the basic block
62+
bb->branch_expr = if_stmt_->cond;
63+
64+
// create a exit block
65+
auto exit_bb = std::make_shared<basic_block>("exit" + std::to_string(basic_block_count));
66+
// assign it a empty stmt_block as parent
67+
exit_bb->parent = std::make_shared<stmt_block>();
68+
// check if this is the last block, if yes the successor will be empty
69+
if (bb->successor.size()) {
70+
// set the successor to the block that if_stmt pointer to earlier
71+
exit_bb->successor.push_back(bb->successor.front());
72+
// clear the successor block from the if_stmt
73+
bb->successor.clear();
74+
}
75+
// remove the if from the work_list
76+
work_list.pop_front();
77+
// push the exit block to the work_list
78+
work_list.push_front(exit_bb);
79+
80+
// if there is a then_stmt, create a basic block for it
81+
if (to<stmt_block>(if_stmt_->then_stmt)->stmts.size() != 0) {
82+
auto then_bb = std::make_shared<basic_block>(std::to_string(++basic_block_count));
83+
// set the parent of this block as the then stmts
84+
then_bb->parent = if_stmt_->then_stmt;
85+
// set the successor of this block to be the exit block
86+
then_bb->successor.push_back(exit_bb);
87+
// set the successor of the original if_stmt block to be this then block
88+
bb->successor.push_back(then_bb);
89+
// push the block to the work_list, to expand it further
90+
work_list.push_front(then_bb);
91+
}
92+
// if there is a else_stmt, create a basic block for it
93+
if (to<stmt_block>(if_stmt_->else_stmt)->stmts.size() != 0) {
94+
auto else_bb = std::make_shared<basic_block>(std::to_string(++basic_block_count));
95+
// set the parent of this block as the else stmts
96+
else_bb->parent = if_stmt_->else_stmt;
97+
// set the successor of this block to be the exit block
98+
else_bb->successor.push_back(exit_bb);
99+
// set the successor of the orignal if_stmt block to be this else block
100+
bb->successor.push_back(else_bb);
101+
// push the block to the work_list, to expand it further
102+
work_list.insert(work_list.begin() + 1, else_bb);
103+
}
104+
105+
// if there is no else block, then have the exit block as successor as well.
106+
if (bb->successor.size() <= 1) bb->successor.push_back(exit_bb);
107+
108+
return_list.push_back(bb);
109+
}
110+
else if (isa<block::expr_stmt>(bb->parent)) {
111+
bb->name = "expr" + bb->name;
112+
return_list.push_back(bb);
113+
work_list.pop_front();
114+
}
115+
else if (isa<block::decl_stmt>(bb->parent)) {
116+
bb->name = "decl" + bb->name;
117+
return_list.push_back(bb);
118+
work_list.pop_front();
119+
}
120+
else if (isa<block::label_stmt>(bb->parent)) {
121+
bb->name = "label" + bb->name;
122+
return_list.push_back(bb);
123+
work_list.pop_front();
124+
}
125+
else if (isa<block::goto_stmt>(bb->parent)) {
126+
bb->name = "goto" + bb->name;
127+
return_list.push_back(bb);
128+
work_list.pop_front();
129+
}
130+
else if (isa<block::return_stmt>(bb->parent)) {
131+
bb->name = "return" + bb->name;
132+
return_list.push_back(bb);
133+
work_list.pop_front();
134+
}
135+
136+
basic_block_count++;
137+
}
138+
139+
// step 4: resolve goto calls to successors of labels
140+
for (auto bb: return_list) {
141+
if (isa<block::goto_stmt>(bb->parent)) {
142+
auto goto_source = std::find_if(return_list.begin(), return_list.end(),
143+
[bb](std::shared_ptr<basic_block> bb_l) {
144+
if (isa<label_stmt>(bb_l->parent)) {
145+
return to<label_stmt>(bb_l->parent)->label1 == to<goto_stmt>(bb->parent)->label1;
146+
}
147+
return false;
148+
});
149+
if (goto_source != return_list.end()) {
150+
bb->successor.clear();
151+
bb->successor.push_back(*goto_source);
152+
}
153+
}
154+
}
155+
156+
return return_list;
157+
}

src/blocks/loop_finder.cpp

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,22 +129,39 @@ static void trim_from_parents(std::vector<stmt_block::Ptr> &parents, std::vector
129129
}
130130

131131
void loop_finder::visit(stmt_block::Ptr a) {
132-
// Check if this block has a label
133-
while (1) {
134-
label_stmt::Ptr found_label = nullptr;
135-
for (auto stmt : a->stmts) {
136-
if (isa<label_stmt>(stmt)) {
137-
found_label = to<label_stmt>(stmt);
138-
}
132+
std::vector<std::shared_ptr<basic_block>> BBs = generate_basic_blocks(a);
133+
134+
std::cout << "++++++ basic blocks ++++++ \n";
135+
for (auto bb: BBs) {
136+
std::cout << bb->name << ":" << "\n";
137+
if (bb->branch_expr) {
138+
std::cout << " ";
139+
bb->branch_expr->dump(std::cout, 0);
139140
}
140-
if (found_label == nullptr)
141-
break;
142-
visit_label(found_label, a);
143-
}
144-
// Once all labels are done, visit the instructions normally
145-
for (auto stmt : a->stmts) {
146-
stmt->accept(this);
141+
std::cout << " ";
142+
std::cout << "br ";
143+
for (auto branches: bb->successor) {
144+
std::cout << branches->name << ", ";
145+
}
146+
std::cout << "\n";
147147
}
148+
std::cout << "++++++ basic blocks ++++++ \n";
149+
150+
// while (1) {
151+
// label_stmt::Ptr found_label = nullptr;
152+
// for (auto stmt : a->stmts) {
153+
// if (isa<label_stmt>(stmt)) {
154+
// found_label = to<label_stmt>(stmt);
155+
// }
156+
// }
157+
// if (found_label == nullptr)
158+
// break;
159+
// visit_label(found_label, a);
160+
// }
161+
// // Once all labels are done, visit the instructions normally
162+
// for (auto stmt : a->stmts) {
163+
// stmt->accept(this);
164+
// }
148165
}
149166
void loop_finder::visit_label(label_stmt::Ptr a, stmt_block::Ptr parent) {
150167

0 commit comments

Comments
 (0)