1
+ #include " blocks/basic_blocks.h"
2
+ #include < algorithm>
3
+
4
+ using namespace block ;
5
+ std::map<block::stmt::Ptr , std::shared_ptr<basic_block>> basic_block::ast_to_basic_block_map = {};
6
+
7
+ basic_block::cfg_block generate_basic_blocks (block::stmt_block::Ptr ast) {
8
+ std::deque<std::shared_ptr<basic_block>> work_list;
9
+ basic_block::cfg_block return_list;
10
+ int basic_block_count = 0 ;
11
+
12
+ // step 1: fill the work_list
13
+ unsigned int ast_index_counter = 0 ;
14
+ for (auto st: ast->stmts ) {
15
+ auto bb = std::make_shared<basic_block>(std::to_string (basic_block_count));
16
+ bb->parent = st;
17
+ bb->ast_index = ast_index_counter++;
18
+ bb->ast_depth = 0 ;
19
+ work_list.push_back (bb);
20
+ basic_block_count++;
21
+ }
22
+
23
+ // step 2: add successors
24
+ for (unsigned i = 0 ; work_list.size () != 0 && i < work_list.size () - 1 ; i++) {
25
+ work_list[i]->successor .push_back (work_list[i+1 ]);
26
+ }
27
+
28
+ // step 3: process blocks: every xx_stmt type statement is made out into a basic block
29
+ while (work_list.size ()) {
30
+ auto bb = work_list.front ();
31
+
32
+ if (isa<block::stmt_block>(bb->parent )) {
33
+ ast_index_counter = 0 ;
34
+ stmt_block::Ptr stmt_block_ = to<stmt_block>(bb->parent );
35
+ bb->name = " stmt" + bb->name ;
36
+
37
+ if (stmt_block_->stmts .size () > 0 ) {
38
+ basic_block::cfg_block stmt_block_list;
39
+
40
+ // convert all statements of this stmt_block into a basic block
41
+ for (auto st: stmt_block_->stmts ) {
42
+ stmt_block_list.push_back (std::make_shared<basic_block>(std::to_string (basic_block_count++)));
43
+ stmt_block_list.back ()->parent = st;
44
+ stmt_block_list.back ()->ast_index = ast_index_counter++;
45
+ stmt_block_list.back ()->ast_depth = bb->ast_depth + 1 ;
46
+ }
47
+
48
+ // set the basic block successors
49
+ for (unsigned i = 0 ; stmt_block_list.size () != 0 && i < stmt_block_list.size () - 1 ; i++) {
50
+ stmt_block_list[i]->successor .push_back (stmt_block_list[i+1 ]);
51
+ }
52
+
53
+ // since we insert these stmts between bb1 ---> bb2 ==> bb1 ---> (bb-a1...bb-an) ---> bb2
54
+ // point the successor of the stmt_block_list to the basic block that bb1's successor
55
+ // pointed to. After this, clear the bb1's successor and push the front of stmt_block_list
56
+ // to bb1's successor list.
57
+ stmt_block_list.back ()->successor .push_back (bb->successor .front ());
58
+ bb->successor .clear ();
59
+ bb->successor .push_back (stmt_block_list.front ());
60
+
61
+ // push a rather empty-ish basic block, which will branch to the next basic block, or the next statement.
62
+ return_list.push_back (bb);
63
+ work_list.pop_front ();
64
+ // now insert the pending blocks to be processed at the front of the work_list
65
+ work_list.insert (work_list.begin (), stmt_block_list.begin (), stmt_block_list.end ());
66
+ }
67
+ else {
68
+ return_list.push_back (bb);
69
+ work_list.pop_front ();
70
+ }
71
+ }
72
+ else if (isa<if_stmt>(bb->parent )) {
73
+ bb->name = " if" + bb->name ;
74
+
75
+ if_stmt::Ptr if_stmt_ = to<if_stmt>(bb->parent );
76
+ // assign the if condition to the basic block
77
+ bb->branch_expr = if_stmt_->cond ;
78
+
79
+ // create a exit block
80
+ auto exit_bb = std::make_shared<basic_block>(" exit" + std::to_string (basic_block_count));
81
+ // assign it a empty stmt_block as parent
82
+ exit_bb->parent = std::make_shared<stmt_block>();
83
+ // mark the basic block as exit block
84
+ exit_bb->is_exit_block = true ;
85
+ // set the ast depth of the basic block
86
+ exit_bb->ast_depth = bb->ast_depth ;
87
+ // check if this is the last block, if yes the successor will be empty
88
+ if (bb->successor .size ()) {
89
+ // set the successor to the block that if_stmt successor pointer to earlier
90
+ exit_bb->successor .push_back (bb->successor .front ());
91
+ // clear the successor block from the if_stmt
92
+ bb->successor .clear ();
93
+ }
94
+ // remove the if from the work_list
95
+ work_list.pop_front ();
96
+ // push the exit block to the work_list
97
+ work_list.push_front (exit_bb);
98
+ std::cerr << " inside if handler: " << bb->name << " \n " ;
99
+ // if there is a then_stmt, create a basic block for it
100
+ if (to<stmt_block>(if_stmt_->then_stmt )->stmts .size () != 0 ) {
101
+ auto then_bb = std::make_shared<basic_block>(std::to_string (++basic_block_count));
102
+ // set the parent of this block as the then stmts
103
+ then_bb->parent = if_stmt_->then_stmt ;
104
+ // set the ast depth of the basic block
105
+ then_bb->ast_depth = bb->ast_depth ;
106
+ // set the successor of this block to be the exit block
107
+ then_bb->successor .push_back (exit_bb);
108
+ // set the successor of the original if_stmt block to be this then block
109
+ bb->successor .push_back (then_bb);
110
+ // set the then branch ptr
111
+ bb->then_branch = then_bb;
112
+ // push the block to the work_list, to expand it further
113
+ work_list.push_front (then_bb);
114
+ std::cerr << " inside then" << " \n " ;
115
+ }
116
+ // if there is a else_stmt, create a basic block for it
117
+ if (to<stmt_block>(if_stmt_->else_stmt )->stmts .size () != 0 ) {
118
+ auto else_bb = std::make_shared<basic_block>(std::to_string (++basic_block_count));
119
+ // set the parent of this block as the else stmts
120
+ else_bb->parent = if_stmt_->else_stmt ;
121
+ // set the ast depth of the basic block
122
+ else_bb->ast_depth = bb->ast_depth ;
123
+ // set the successor of this block to be the exit block
124
+ else_bb->successor .push_back (exit_bb);
125
+ // set the successor of the orignal if_stmt block to be this else block
126
+ bb->successor .push_back (else_bb);
127
+ // set the else branch ptr
128
+ bb->else_branch = else_bb;
129
+ // push the block to the work_list, to expand it further
130
+ work_list.insert (work_list.begin () + 1 , else_bb);
131
+ std::cerr << " inside else" << " \n " ;
132
+ }
133
+
134
+ // if there is no then/else block, then have the exit block as successor as well.
135
+ if (bb->successor .size () <= 1 ) bb->successor .push_back (exit_bb);
136
+
137
+ // set the missing block as the exit block
138
+ if (!bb->then_branch ) bb->then_branch = exit_bb;
139
+ else if (!bb->else_branch ) bb->else_branch = exit_bb;
140
+
141
+ // set the exit block of this if stmt
142
+ bb->exit_block = exit_bb;
143
+
144
+ return_list.push_back (bb);
145
+ }
146
+ else if (isa<block::expr_stmt>(bb->parent )) {
147
+ bb->name = " expr" + bb->name ;
148
+ return_list.push_back (bb);
149
+ work_list.pop_front ();
150
+ }
151
+ else if (isa<block::decl_stmt>(bb->parent )) {
152
+ bb->name = " decl" + bb->name ;
153
+ return_list.push_back (bb);
154
+ work_list.pop_front ();
155
+ }
156
+ else if (isa<block::label_stmt>(bb->parent )) {
157
+ bb->name = " label" + bb->name ;
158
+ return_list.push_back (bb);
159
+ work_list.pop_front ();
160
+ }
161
+ else if (isa<block::goto_stmt>(bb->parent )) {
162
+ bb->name = " goto" + bb->name ;
163
+ return_list.push_back (bb);
164
+ work_list.pop_front ();
165
+ }
166
+ else if (isa<block::return_stmt>(bb->parent )) {
167
+ bb->name = " return" + bb->name ;
168
+ return_list.push_back (bb);
169
+ work_list.pop_front ();
170
+ }
171
+
172
+ basic_block_count++;
173
+ }
174
+
175
+ // step 4: resolve goto calls to successors of labels
176
+ for (auto bb: return_list) {
177
+ if (isa<block::goto_stmt>(bb->parent )) {
178
+ auto goto_source = std::find_if (return_list.begin (), return_list.end (),
179
+ [bb](std::shared_ptr<basic_block> bb_l) {
180
+ if (isa<label_stmt>(bb_l->parent )) {
181
+ return to<label_stmt>(bb_l->parent )->label1 == to<goto_stmt>(bb->parent )->label1 ;
182
+ }
183
+ return false ;
184
+ });
185
+ if (goto_source != return_list.end ()) {
186
+ bb->successor .clear ();
187
+ bb->successor .push_back (*goto_source);
188
+ }
189
+ }
190
+ }
191
+
192
+ // step 5: populate the predecessors
193
+ for (auto bb: return_list) {
194
+ for (auto succ: bb->successor ) {
195
+ succ->predecessor .push_back (bb);
196
+ }
197
+ }
198
+
199
+ // step 6: assign each basic_block an id
200
+ for (unsigned int i = 0 ; i < return_list.size (); i++) {
201
+ return_list[i]->id = i;
202
+ }
203
+
204
+ // step 7: populate the ast -> bb map
205
+ for (auto bb: return_list) {
206
+ bb->ast_to_basic_block_map [bb->parent ] = bb;
207
+ }
208
+
209
+ return return_list;
210
+ }
0 commit comments