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+ }
0 commit comments