Skip to content

Commit

Permalink
Add support for basic blocks and CFGs
Browse files Browse the repository at this point in the history
Added class for representing basic blocks, and a helper function to
generate basic blocks from AST. For testing, disabled the loop_finder
code.
  • Loading branch information
VedantParanjape committed May 15, 2023
1 parent 73e3041 commit 51a3213
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 14 deletions.
22 changes: 22 additions & 0 deletions include/blocks/basic_blocks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef BASIC_BLOCKS_H
#define BASIC_BLOCKS_H
#include "blocks/block_visitor.h"
#include "blocks/stmt.h"
#include <vector>
#include <deque>
#include <string>

class basic_block {
public:
basic_block(std::string label): name(label) {};

std::vector<std::shared_ptr<basic_block>> predecessor;
std::vector<std::shared_ptr<basic_block>> successor;
block::expr::Ptr branch_expr;
block::stmt::Ptr parent;
std::string name;
};

std::vector<std::shared_ptr<basic_block>> generate_basic_blocks(block::stmt_block::Ptr ast);

#endif
1 change: 1 addition & 0 deletions include/blocks/loop_finder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define LOOP_FINDER_H
#include "blocks/block_visitor.h"
#include "blocks/stmt.h"
#include "blocks/basic_blocks.h"

namespace block {
class loop_finder : public block_visitor {
Expand Down
157 changes: 157 additions & 0 deletions src/blocks/basic_blocks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include "blocks/basic_blocks.h"
#include <algorithm>

using namespace block;

std::vector<std::shared_ptr<basic_block>> generate_basic_blocks(block::stmt_block::Ptr ast) {
std::deque<std::shared_ptr<basic_block>> work_list;
std::vector<std::shared_ptr<basic_block>> return_list;
int basic_block_count = 0;

// step 1: fill the work_list
for (auto st: ast->stmts) {
auto bb = std::make_shared<basic_block>(std::to_string(basic_block_count));
bb->parent = st;
work_list.push_back(bb);
basic_block_count++;
}

// step 2: add successors
for (unsigned i = 0; work_list.size() != 0 && i < work_list.size() - 1; i++) {
work_list[i]->successor.push_back(work_list[i+1]);
}

// step 3: process blocks
while (work_list.size()) {
auto bb = work_list.front();

if (isa<block::stmt_block>(bb->parent)) {
stmt_block::Ptr stmt_block_ = to<stmt_block>(bb->parent);
bb->name = "stmt" + bb->name;

if (stmt_block_->stmts.size() > 0) {
std::vector<std::shared_ptr<basic_block>> stmt_block_list;

for (auto st: stmt_block_->stmts) {
stmt_block_list.push_back(std::make_shared<basic_block>(std::to_string(basic_block_count++)));
stmt_block_list.back()->parent = st;
}

for (unsigned i = 0; stmt_block_list.size() != 0 && i < stmt_block_list.size() - 1; i++) {
stmt_block_list[i]->successor.push_back(stmt_block_list[i+1]);
}

stmt_block_list.back()->successor.push_back(bb->successor.front());
bb->successor.clear();
bb->successor.push_back(stmt_block_list.front());

return_list.push_back(bb);
work_list.pop_front();
work_list.insert(work_list.begin(), stmt_block_list.begin(), stmt_block_list.end());
}
else {
return_list.push_back(bb);
work_list.pop_front();
}
}
else if (isa<if_stmt>(bb->parent)) {
bb->name = "if" + bb->name;

if_stmt::Ptr if_stmt_ = to<if_stmt>(bb->parent);
// assign the if condition to the basic block
bb->branch_expr = if_stmt_->cond;

// create a exit block
auto exit_bb = std::make_shared<basic_block>("exit" + std::to_string(basic_block_count));
// assign it a empty stmt_block as parent
exit_bb->parent = std::make_shared<stmt_block>();
// check if this is the last block, if yes the successor will be empty
if (bb->successor.size()) {
// set the successor to the block that if_stmt pointer to earlier
exit_bb->successor.push_back(bb->successor.front());
// clear the successor block from the if_stmt
bb->successor.clear();
}
// remove the if from the work_list
work_list.pop_front();
// push the exit block to the work_list
work_list.push_front(exit_bb);

// if there is a then_stmt, create a basic block for it
if (to<stmt_block>(if_stmt_->then_stmt)->stmts.size() != 0) {
auto then_bb = std::make_shared<basic_block>(std::to_string(++basic_block_count));
// set the parent of this block as the then stmts
then_bb->parent = if_stmt_->then_stmt;
// set the successor of this block to be the exit block
then_bb->successor.push_back(exit_bb);
// set the successor of the original if_stmt block to be this then block
bb->successor.push_back(then_bb);
// push the block to the work_list, to expand it further
work_list.push_front(then_bb);
}
// if there is a else_stmt, create a basic block for it
if (to<stmt_block>(if_stmt_->else_stmt)->stmts.size() != 0) {
auto else_bb = std::make_shared<basic_block>(std::to_string(++basic_block_count));
// set the parent of this block as the else stmts
else_bb->parent = if_stmt_->else_stmt;
// set the successor of this block to be the exit block
else_bb->successor.push_back(exit_bb);
// set the successor of the orignal if_stmt block to be this else block
bb->successor.push_back(else_bb);
// push the block to the work_list, to expand it further
work_list.insert(work_list.begin() + 1, else_bb);
}

// if there is no else block, then have the exit block as successor as well.
if (bb->successor.size() <= 1) bb->successor.push_back(exit_bb);

return_list.push_back(bb);
}
else if (isa<block::expr_stmt>(bb->parent)) {
bb->name = "expr" + bb->name;
return_list.push_back(bb);
work_list.pop_front();
}
else if (isa<block::decl_stmt>(bb->parent)) {
bb->name = "decl" + bb->name;
return_list.push_back(bb);
work_list.pop_front();
}
else if (isa<block::label_stmt>(bb->parent)) {
bb->name = "label" + bb->name;
return_list.push_back(bb);
work_list.pop_front();
}
else if (isa<block::goto_stmt>(bb->parent)) {
bb->name = "goto" + bb->name;
return_list.push_back(bb);
work_list.pop_front();
}
else if (isa<block::return_stmt>(bb->parent)) {
bb->name = "return" + bb->name;
return_list.push_back(bb);
work_list.pop_front();
}

basic_block_count++;
}

// step 4: resolve goto calls to successors of labels
for (auto bb: return_list) {
if (isa<block::goto_stmt>(bb->parent)) {
auto goto_source = std::find_if(return_list.begin(), return_list.end(),
[bb](std::shared_ptr<basic_block> bb_l) {
if (isa<label_stmt>(bb_l->parent)) {
return to<label_stmt>(bb_l->parent)->label1 == to<goto_stmt>(bb->parent)->label1;
}
return false;
});
if (goto_source != return_list.end()) {
bb->successor.clear();
bb->successor.push_back(*goto_source);
}
}
}

return return_list;
}
45 changes: 31 additions & 14 deletions src/blocks/loop_finder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,39 @@ static void trim_from_parents(std::vector<stmt_block::Ptr> &parents, std::vector
}

void loop_finder::visit(stmt_block::Ptr a) {
// Check if this block has a label
while (1) {
label_stmt::Ptr found_label = nullptr;
for (auto stmt : a->stmts) {
if (isa<label_stmt>(stmt)) {
found_label = to<label_stmt>(stmt);
}
std::vector<std::shared_ptr<basic_block>> BBs = generate_basic_blocks(a);

std::cout << "++++++ basic blocks ++++++ \n";
for (auto bb: BBs) {
std::cout << bb->name << ":" << "\n";
if (bb->branch_expr) {
std::cout << " ";
bb->branch_expr->dump(std::cout, 0);
}
if (found_label == nullptr)
break;
visit_label(found_label, a);
}
// Once all labels are done, visit the instructions normally
for (auto stmt : a->stmts) {
stmt->accept(this);
std::cout << " ";
std::cout << "br ";
for (auto branches: bb->successor) {
std::cout << branches->name << ", ";
}
std::cout << "\n";
}
std::cout << "++++++ basic blocks ++++++ \n";

// while (1) {
// label_stmt::Ptr found_label = nullptr;
// for (auto stmt : a->stmts) {
// if (isa<label_stmt>(stmt)) {
// found_label = to<label_stmt>(stmt);
// }
// }
// if (found_label == nullptr)
// break;
// visit_label(found_label, a);
// }
// // Once all labels are done, visit the instructions normally
// for (auto stmt : a->stmts) {
// stmt->accept(this);
// }
}
void loop_finder::visit_label(label_stmt::Ptr a, stmt_block::Ptr parent) {

Expand Down

0 comments on commit 51a3213

Please sign in to comment.