diff --git a/include/blocks/basic_blocks.h b/include/blocks/basic_blocks.h new file mode 100644 index 0000000..ee4f6a9 --- /dev/null +++ b/include/blocks/basic_blocks.h @@ -0,0 +1,31 @@ +#ifndef BASIC_BLOCKS_H +#define BASIC_BLOCKS_H +#include "blocks/stmt.h" +#include +#include +#include +#include + +class basic_block { + public: + typedef std::vector> cfg_block; + basic_block(std::string label): name(label) {}; + + cfg_block predecessor; + cfg_block successor; + block::expr::Ptr branch_expr; + std::shared_ptr then_branch; + std::shared_ptr else_branch; + std::shared_ptr exit_block; + bool is_exit_block = false; + block::stmt::Ptr parent; + unsigned int ast_index; + unsigned int ast_depth; + unsigned int id; + std::string name; + static std::map> ast_to_basic_block_map; +}; + +basic_block::cfg_block generate_basic_blocks(block::stmt_block::Ptr ast); + +#endif \ No newline at end of file diff --git a/include/blocks/dominance.h b/include/blocks/dominance.h new file mode 100644 index 0000000..85cd44e --- /dev/null +++ b/include/blocks/dominance.h @@ -0,0 +1,57 @@ +#ifndef DOMINANCE_H +#define DOMINANCE_H +#include "blocks/block_visitor.h" +#include "blocks/basic_blocks.h" +#include "blocks/stmt.h" +#include +#include +#include +#include +#include +#include + +class dominator_analysis { + public: + // struct dominator_tree_ { + // dominator_tree_(int id): bb_id(id); + // int bb_id; + // std::vector> child_nodes; + // } dominator_tree; + dominator_analysis(basic_block::cfg_block cfg, bool is_postdom = false); + basic_block::cfg_block cfg_; + bool is_postdom_; + int max_depth; + unsigned int max_depth_bb_id; + std::vector &get_postorder_bb_map(); + std::vector &get_postorder(); + std::vector &get_preorder_bb_map(); + std::vector &get_preorder(); + std::vector &get_idom(); + std::map> &get_idom_map(); + std::vector &get_postorder_idom_map(); + int get_idom(int bb_id); + std::vector get_idom_map(int bb_id); + int get_postorder_idom_map(int idom_id); + bool dominates(int bb1_id, int bb2_id); + bool is_reachable_from_entry(int bb_id); + void analyze(); + + private: + std::vector idom; + std::map> idom_map; + std::vector postorder_idom; + std::vector postorder; + std::vector postorder_bb_map; + std::vector preorder; + std::vector preorder_bb_map; + void reverse_cfg(); + void postorder_idom_helper(std::vector &visited, int id); + void postorder_dfs_helper(std::vector &visited_bbs, int id, int depth); + void postorder_dfs(bool reverse_cfg); + void preorder_dfs_helper(std::vector &visited_bbs, int id); + void preorder_dfs(bool reverse_cfg); + int intersect(int bb1_id, int bb2_id); +}; + + +#endif \ No newline at end of file diff --git a/include/blocks/loops.h b/include/blocks/loops.h new file mode 100644 index 0000000..2149f5f --- /dev/null +++ b/include/blocks/loops.h @@ -0,0 +1,63 @@ +#ifndef LOOP_H +#define LOOP_H +#include "blocks/block_visitor.h" +#include "blocks/basic_blocks.h" +#include "blocks/dominance.h" +#include "blocks/stmt.h" +#include + +using namespace block; +class loop_info; +class loop { +public: + loop(std::shared_ptr header): header_block(header) {} + stmt::Ptr convert_to_ast_impl(loop_info &li, dominator_analysis &dta_, std::vector, stmt_block::Ptr>> &return_blocks); + + struct loop_bounds_ { + stmt::Ptr ind_var; + // MISS: intial value of ind var + stmt::Ptr steps_ind_var; + // MISS: value of the step + // MISS: final value of the step + stmt::Ptr cond_ind_var; + // MISS: direction of step + stmt::Ptr entry_stmt; + } loop_bounds; + + unsigned int loop_id; + basic_block::cfg_block blocks; + std::unordered_set blocks_id_map; + std::shared_ptr parent_loop; + std::shared_ptr header_block; + std::shared_ptr condition_block; + std::shared_ptr unique_exit_block; + basic_block::cfg_block loop_latch_blocks; + basic_block::cfg_block loop_exit_blocks; + std::vector> subloops; + while_stmt::Ptr structured_ast_loop; +}; + +class loop_info { +public: + loop_info(basic_block::cfg_block ast, dominator_analysis &dt, dominator_analysis &post_dt): parent_ast(ast), dta(dt), post_dta(post_dt) { + analyze(); + } + std::shared_ptr allocate_loop(std::shared_ptr header); + block::stmt_block::Ptr convert_to_ast(block::stmt_block::Ptr ast); + std::map> postorder_loops_map; + std::map> preorder_loops_map; + std::vector> loops; + std::vector> top_level_loops; + +private: + basic_block::cfg_block parent_ast; + dominator_analysis dta; + dominator_analysis post_dta; + std::map> bb_loop_map; + void postorder_dfs_helper(std::vector &postorder_loops_map, std::vector &visited_loops, int id); + void preorder_dfs_helper(std::vector &preorder_loops_map, std::vector &visited_loops, int id); + // discover loops during traversal of the abstract syntax tree + void analyze(); +}; + +#endif \ No newline at end of file diff --git a/include/builder/builder_context.h b/include/builder/builder_context.h index 840fbca..effaf62 100644 --- a/include/builder/builder_context.h +++ b/include/builder/builder_context.h @@ -1,5 +1,8 @@ #ifndef BUILDER_CONTEXT #define BUILDER_CONTEXT +#include "blocks/basic_blocks.h" +#include "blocks/dominance.h" +#include "blocks/loops.h" #include "blocks/expr.h" #include "blocks/stmt.h" #include "builder/forward_declarations.h" diff --git a/src/blocks/basic_blocks.cpp b/src/blocks/basic_blocks.cpp new file mode 100644 index 0000000..139e720 --- /dev/null +++ b/src/blocks/basic_blocks.cpp @@ -0,0 +1,211 @@ +#include "blocks/basic_blocks.h" +#include + +using namespace block; + +std::map> basic_block::ast_to_basic_block_map = {}; + +basic_block::cfg_block generate_basic_blocks(block::stmt_block::Ptr ast) { + std::deque> work_list; + basic_block::cfg_block return_list; + int basic_block_count = 0; + + // step 1: fill the work_list + unsigned int ast_index_counter = 0; + for (auto st: ast->stmts) { + auto bb = std::make_shared(std::to_string(basic_block_count)); + bb->parent = st; + bb->ast_index = ast_index_counter++; + bb->ast_depth = 0; + 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: every xx_stmt type statement is made out into a basic block + while (work_list.size()) { + auto bb = work_list.front(); + + if (isa(bb->parent)) { + ast_index_counter = 0; + stmt_block::Ptr stmt_block_ = to(bb->parent); + bb->name = "stmt" + bb->name; + + if (stmt_block_->stmts.size() > 0) { + basic_block::cfg_block stmt_block_list; + + // convert all statements of this stmt_block into a basic block + for (auto st: stmt_block_->stmts) { + stmt_block_list.push_back(std::make_shared(std::to_string(basic_block_count++))); + stmt_block_list.back()->parent = st; + stmt_block_list.back()->ast_index = ast_index_counter++; + stmt_block_list.back()->ast_depth = bb->ast_depth + 1; + } + + // set the basic block successors + 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]); + } + + // since we insert these stmts between bb1 ---> bb2 ==> bb1 ---> (bb-a1...bb-an) ---> bb2 + // point the successor of the stmt_block_list to the basic block that bb1's successor + // pointed to. After this, clear the bb1's successor and push the front of stmt_block_list + // to bb1's successor list. + stmt_block_list.back()->successor.push_back(bb->successor.front()); + bb->successor.clear(); + bb->successor.push_back(stmt_block_list.front()); + + // push a rather empty-ish basic block, which will branch to the next basic block, or the next statement. + return_list.push_back(bb); + work_list.pop_front(); + // now insert the pending blocks to be processed at the front of the work_list + 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(bb->parent)) { + bb->name = "if" + bb->name; + + if_stmt::Ptr if_stmt_ = to(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("exit" + std::to_string(basic_block_count)); + // assign it a empty stmt_block as parent + exit_bb->parent = std::make_shared(); + // mark the basic block as exit block + exit_bb->is_exit_block = true; + // set the ast depth of the basic block + exit_bb->ast_depth = bb->ast_depth; + // 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 successor 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); + std::cerr << "inside if handler: " << bb->name << "\n"; + // if there is a then_stmt, create a basic block for it + if (to(if_stmt_->then_stmt)->stmts.size() != 0) { + auto then_bb = std::make_shared(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 ast depth of the basic block + then_bb->ast_depth = bb->ast_depth; + // 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); + // set the then branch ptr + bb->then_branch = then_bb; + // push the block to the work_list, to expand it further + work_list.push_front(then_bb); + std::cerr << "inside then" << "\n"; + } + // if there is a else_stmt, create a basic block for it + if (to(if_stmt_->else_stmt)->stmts.size() != 0) { + auto else_bb = std::make_shared(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 ast depth of the basic block + else_bb->ast_depth = bb->ast_depth; + // 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); + // set the else branch ptr + bb->else_branch = else_bb; + // push the block to the work_list, to expand it further + work_list.insert(work_list.begin() + 1, else_bb); + std::cerr << "inside else" << "\n"; + } + + // if there is no then/else block, then have the exit block as successor as well. + if (bb->successor.size() <= 1) bb->successor.push_back(exit_bb); + + // set the missing block as the exit block + if (!bb->then_branch) bb->then_branch = exit_bb; + else if (!bb->else_branch) bb->else_branch = exit_bb; + + // set the exit block of this if stmt + bb->exit_block = exit_bb; + + return_list.push_back(bb); + } + else if (isa(bb->parent)) { + bb->name = "expr" + bb->name; + return_list.push_back(bb); + work_list.pop_front(); + } + else if (isa(bb->parent)) { + bb->name = "decl" + bb->name; + return_list.push_back(bb); + work_list.pop_front(); + } + else if (isa(bb->parent)) { + bb->name = "label" + bb->name; + return_list.push_back(bb); + work_list.pop_front(); + } + else if (isa(bb->parent)) { + bb->name = "goto" + bb->name; + return_list.push_back(bb); + work_list.pop_front(); + } + else if (isa(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(bb->parent)) { + auto goto_source = std::find_if(return_list.begin(), return_list.end(), + [bb](std::shared_ptr bb_l) { + if (isa(bb_l->parent)) { + return to(bb_l->parent)->label1 == to(bb->parent)->label1; + } + return false; + }); + if (goto_source != return_list.end()) { + bb->successor.clear(); + bb->successor.push_back(*goto_source); + } + } + } + + // step 5: populate the predecessors + for (auto bb: return_list) { + for (auto succ: bb->successor) { + succ->predecessor.push_back(bb); + } + } + + // step 6: assign each basic_block an id + for (unsigned int i = 0; i < return_list.size(); i++) { + return_list[i]->id = i; + } + + // step 7: populate the ast -> bb map + for (auto bb: return_list) { + bb->ast_to_basic_block_map[bb->parent] = bb; + } + + return return_list; +} \ No newline at end of file diff --git a/src/blocks/dominance.cpp b/src/blocks/dominance.cpp new file mode 100644 index 0000000..d24630e --- /dev/null +++ b/src/blocks/dominance.cpp @@ -0,0 +1,283 @@ +#include "blocks/dominance.h" + +using namespace block; + +void dominator_analysis::reverse_cfg() { + // TODO: Add a check for size, it should be greater than 2. + if (cfg_.size() == 0) + assert(0); + + std::shared_ptr virtual_exit_bb = std::make_shared("virtualexit0"); + for (auto bb: cfg_) { + if (bb->successor.size() == 0) { + bb->successor.push_back(virtual_exit_bb); + virtual_exit_bb->predecessor.push_back(bb); + } + } + + // if CFG is an inifite loop, we don't have a exit block + // so we need to find the farthest block from the entry + // of the loop and consider that as one of the exit blocks + if (!virtual_exit_bb->predecessor.size()) { + std::cerr << "infinite loop\n"; + postorder_dfs(false); + + auto bb_virtual_backedge = cfg_[max_depth_bb_id]; + bb_virtual_backedge->successor.push_back(virtual_exit_bb); + virtual_exit_bb->predecessor.push_back(bb_virtual_backedge); + } + + virtual_exit_bb->id = cfg_.size(); + cfg_.push_back(virtual_exit_bb); + + for (auto bb: cfg_) { + basic_block::cfg_block temp_pred = bb->predecessor; + bb->predecessor.clear(); + bb->predecessor.insert(bb->predecessor.begin(), bb->successor.begin(), bb->successor.end()); + std::reverse(bb->predecessor.begin(), bb->predecessor.end()); + bb->successor.clear(); + bb->successor.insert(bb->successor.begin(), temp_pred.begin(), temp_pred.end()); + std::reverse(bb->successor.begin(), bb->successor.end()); + } +} + +dominator_analysis::dominator_analysis(basic_block::cfg_block cfg, bool is_postdom) : cfg_(cfg), is_postdom_(is_postdom) { + if (is_postdom) { + reverse_cfg(); + } + + // TODO: Add a check for size, it should be greater than 2. + idom.clear(); + idom.reserve(cfg_.size()); + idom.assign(cfg_.size(), -1); + postorder.clear(); + postorder.reserve(cfg_.size()); + postorder_bb_map.clear(); + postorder_bb_map.reserve(cfg_.size()); + postorder_bb_map.assign(cfg_.size(), -1); + preorder.clear(); + preorder.reserve(cfg_.size()); + preorder_bb_map.clear(); + preorder_bb_map.reserve(cfg_.size()); + preorder_bb_map.assign(cfg_.size(), -1); + + // and call the anaylse function + analyze(); +} + +void dominator_analysis::postorder_idom_helper(std::vector &visited, int id) { + for (int idom_id: idom_map[id]) { + if (idom_id != -1 && !visited[idom_id]) { + visited[idom_id] = true; + postorder_idom_helper(visited, idom_id); + postorder_idom.push_back(idom_id); + } + } +} + +void dominator_analysis::postorder_dfs_helper(std::vector &visited_bbs, int id, int depth) { + if (depth > max_depth) { + max_depth = depth; + max_depth_bb_id = id; + } + + for (auto child: cfg_[id]->successor) { + if (!visited_bbs[child->id]) { + visited_bbs[child->id] = true; + postorder_dfs_helper(visited_bbs, child->id, depth + 1); + postorder.push_back(child->id); + } + } +} + +void dominator_analysis::postorder_dfs(bool reverse_cfg) { + int current_depth = 0; + max_depth = current_depth; + + std::vector visited_bbs(cfg_.size()); + visited_bbs.assign(visited_bbs.size(), false); + if (reverse_cfg) + visited_bbs[cfg_.size() - 1] = true; + else + visited_bbs[0] = true; + + if (reverse_cfg) { + max_depth_bb_id = cfg_.size() - 1; + postorder_dfs_helper(visited_bbs, cfg_.size() - 1, current_depth + 1); + postorder.push_back(cfg_.size() - 1); + } + else { + max_depth_bb_id = 0; + postorder_dfs_helper(visited_bbs, 0, current_depth + 1); + postorder.push_back(0); + } +} + +void dominator_analysis::preorder_dfs_helper(std::vector &visited_bbs, int id) { + for (auto child: cfg_[id]->successor) { + if (!visited_bbs[child->id]) { + visited_bbs[child->id] = true; + preorder.push_back(child->id); + preorder_dfs_helper(visited_bbs, child->id); + } + } +} + +void dominator_analysis::preorder_dfs(bool reverse_cfg) { + std::vector visited_bbs(cfg_.size()); + visited_bbs.assign(visited_bbs.size(), false); + if (reverse_cfg) + visited_bbs[cfg_.size() - 1] = true; + else + visited_bbs[0] = true; + + if (reverse_cfg) { + preorder.push_back(cfg_.size() - 1); + preorder_dfs_helper(visited_bbs, cfg_.size() - 1); + } + else { + preorder.push_back(0); + preorder_dfs_helper(visited_bbs, 0); + } +} + +std::vector &dominator_analysis::get_postorder_bb_map() { + return postorder_bb_map; +} + +std::vector &dominator_analysis::get_postorder() { + return postorder; +} + +std::vector &dominator_analysis::get_preorder_bb_map() { + return preorder_bb_map; +} + +std::vector &dominator_analysis::get_preorder() { + return preorder; +} + +std::vector &dominator_analysis::get_idom() { + return idom; +} + +std::map> &dominator_analysis::get_idom_map() { + return idom_map; +} + +std::vector &dominator_analysis::get_postorder_idom_map() { + return postorder_idom; +} + +int dominator_analysis::get_idom(int bb_id) { + if (bb_id < 0 || bb_id >= (int)idom.size()) { + return -1; + } + + return idom[bb_id]; +} + +std::vector dominator_analysis::get_idom_map(int bb_id) { + if (bb_id < 0 || bb_id >= (int)idom_map.size()) { + return {}; + } + + return idom_map[bb_id]; +} + +int dominator_analysis::get_postorder_idom_map(int idom_id) { + if (idom_id < 0 || idom_id >= (int)postorder_idom.size()) { + return -1; + } + + return postorder_idom[idom_id]; +} + +bool dominator_analysis::dominates(int bb1_id, int bb2_id) { + if (bb1_id == 0) { + return true; + } + + int pointer = idom[bb2_id]; + while (pointer != 0) { + if (pointer == bb1_id) { + return true; + } + pointer = idom[pointer]; + } + + return false; +} + +bool dominator_analysis::is_reachable_from_entry(int bb_id) { + return dominates(0, bb_id); +} + +int dominator_analysis::intersect(int bb1_id, int bb2_id) { + while (bb1_id != bb2_id) { + if (postorder_bb_map[bb1_id] < postorder_bb_map[bb2_id]) { + bb1_id = idom[bb1_id]; + } + else { + bb2_id = idom[bb2_id]; + } + } + + return bb1_id; +} + +void dominator_analysis::analyze() { + preorder_dfs(is_postdom_); + postorder_dfs(is_postdom_); + for (unsigned int i = 0; i < preorder.size(); i++) { + preorder_bb_map[preorder[i]] = i; + } + for (unsigned int i = 0; i < postorder.size(); i++) { + postorder_bb_map[postorder[i]] = i; + } + if (is_postdom_) + idom[cfg_.size() - 1] = cfg_.size() - 1; + else + idom[0] = 0; + + bool change = false; + + do { + change = 0; + for (int i = postorder.size() - 2; i >= 0; i--) { + int postorder_bb_num = postorder[i]; + std::shared_ptr bb = cfg_[postorder_bb_num]; + int bb_id_idom = bb->predecessor[0]->id; + + for (unsigned int j = 1; j < bb->predecessor.size(); j++) { + int bb_id_idom_next = bb->predecessor[j]->id; + if (idom[bb_id_idom_next] != -1) { + bb_id_idom = intersect(bb_id_idom, bb_id_idom_next); + } + } + + if (idom[postorder_bb_num] != bb_id_idom) { + idom[postorder_bb_num] = bb_id_idom; + change = 1; + } + } + } while(change); + + // build a map of dominators for easy traversal. + for (unsigned int i = 0; i < idom.size(); i++) { + idom_map[idom[i]].push_back(i); + } + + for (unsigned int i = 0; i < idom.size(); i++) { + if (idom_map[i].empty()) + idom_map[i].push_back(-1); + } + + // build a postorder visit list of idom_tree + std::vector visited_idom_nodes(idom_map.size()); + visited_idom_nodes.assign(visited_idom_nodes.size(), false); + visited_idom_nodes[0] = true; + + postorder_idom_helper(visited_idom_nodes, 0); + postorder_idom.push_back(0); +} \ No newline at end of file diff --git a/src/blocks/loops.cpp b/src/blocks/loops.cpp new file mode 100644 index 0000000..d7762f9 --- /dev/null +++ b/src/blocks/loops.cpp @@ -0,0 +1,807 @@ +#include "blocks/loops.h" +#include +#include +#include +#include + +static std::vector>, stmt::Ptr>> worklist; + +std::shared_ptr loop_info::allocate_loop(std::shared_ptr header) { + if (!header) + return nullptr; + + loops.push_back(std::make_shared(header)); + bb_loop_map[header->id] = loops.back(); + return loops.back(); +} + +void loop_info::postorder_dfs_helper(std::vector &postorder_loops_map, std::vector &visited_loops, int id) { + for (auto subloop: loops[id]->subloops) { + if (!visited_loops[subloop->loop_id]) { + visited_loops[subloop->loop_id] = true; + postorder_dfs_helper(postorder_loops_map, visited_loops, subloop->loop_id); + postorder_loops_map.push_back(subloop->loop_id); + } + } +} + +void loop_info::preorder_dfs_helper(std::vector &preorder_loops_map, std::vector &visited_loops, int id) { + for (auto subloop: loops[id]->subloops) { + if (!visited_loops[subloop->loop_id]) { + visited_loops[subloop->loop_id] = true; + preorder_loops_map.push_back(subloop->loop_id); + preorder_dfs_helper(preorder_loops_map, visited_loops, subloop->loop_id); + } + } +} + +void loop_info::analyze() { + std::vector idom = dta.get_idom(); + + for (int idom_id: dta.get_postorder_idom_map()) { + std::vector backedges; + int header = idom_id; + + for (auto backedge: dta.cfg_[header]->predecessor) { + if (dta.dominates(header, backedge->id) && dta.is_reachable_from_entry(backedge->id)) { + backedges.push_back(backedge->id); + } + } + + if (!backedges.empty()) { + std::shared_ptr new_loop = allocate_loop(dta.cfg_[header]); + if (!new_loop) + continue; + + int num_blocks = 0; + int num_subloops = 0; + + auto backedge_iter = backedges.begin(); + // do a reverse CFG traversal to map basic blocks in this loop. + basic_block::cfg_block worklist(backedges.size()); + std::generate(worklist.begin(), worklist.end(), [&backedge_iter, this](){ + return dta.cfg_[*(backedge_iter++)]; + }); + + while (!worklist.empty()) { + unsigned int predecessor_bb_id = worklist.back()->id; + worklist.pop_back(); + + auto subloop_iter = bb_loop_map.find(predecessor_bb_id); + if (subloop_iter == bb_loop_map.end()) { + if (!dta.is_reachable_from_entry(predecessor_bb_id)) + continue; + + bb_loop_map[predecessor_bb_id] = new_loop; + ++num_blocks; + // loop has no blocks between header and backedge + if (predecessor_bb_id == new_loop->header_block->id) + continue; + + worklist.insert(worklist.end(), dta.cfg_[predecessor_bb_id]->predecessor.begin(), dta.cfg_[predecessor_bb_id]->predecessor.end()); + } + else { + // this block has already been discovered, mapped to some other loop + // find the outermost loop + std::shared_ptr subloop = subloop_iter->second; + while (subloop->parent_loop) { + subloop = subloop->parent_loop; + } + + if (subloop == new_loop) + continue; + + // discovered a subloop of this loop + subloop->parent_loop = new_loop; + ++num_subloops; + num_blocks = num_blocks + subloop->blocks.size(); + predecessor_bb_id = subloop->header_block->id; + + for (auto pred: dta.cfg_[predecessor_bb_id]->predecessor) { + auto loop_iter = bb_loop_map.find(pred->id); + // do not check if loop_iter != bb_loop_map.end(), as a results + // basic blocks that are not directly part of the natural loops + // are skipped, like loop latches. + if (loop_iter->second != subloop) + worklist.push_back(pred); + } + } + } + new_loop->subloops.reserve(num_subloops); + new_loop->blocks.reserve(num_blocks); + new_loop->blocks_id_map.reserve(num_blocks); + } + } + + // populate all subloops and loops with blocks + for (auto bb_id: dta.get_postorder()) { + auto subloop_iter = bb_loop_map.find(bb_id); + std::shared_ptr subloop = nullptr; + if (subloop_iter != bb_loop_map.end() && (subloop = subloop_iter->second) && dta.cfg_[bb_id] == subloop_iter->second->header_block) { + // check if it is the outermost loop + if (subloop->parent_loop != nullptr) { + subloop->parent_loop->subloops.push_back(subloop); + } + else { + top_level_loops.push_back(subloop); + } + + std::reverse(subloop->blocks.begin(), subloop->blocks.end()); + std::reverse(subloop->subloops.begin(), subloop->subloops.end()); + + subloop = subloop->parent_loop; + } + + while (subloop) { + subloop->blocks.push_back(dta.cfg_[bb_id]); + subloop->blocks_id_map.insert(dta.cfg_[bb_id]->id); + subloop = subloop->parent_loop; + } + } + + // Populate the loop latches + for (auto loop: loops) { + if (!loop->header_block) + continue; + + std::shared_ptr header = loop->header_block; + for (auto children: header->predecessor) { + if (loop->blocks_id_map.count(children->id)) { + loop->loop_latch_blocks.push_back(children); + } + } + } + + // Populate the loop exits + for (auto loop: loops) { + if (!loop->header_block) + continue; + + for (auto bb: loop->blocks) { + for (auto children: bb->successor) { + if (!loop->blocks_id_map.count(children->id) && children->id != loop->header_block->id) { + loop->loop_exit_blocks.push_back(bb); + break; + } + } + } + } + + // Update unique loop exit using post dominators + for (auto loop: loops) { + if (loop->loop_exit_blocks.size() == 0) + continue; + + int unique_postdom = post_dta.get_idom(loop->loop_exit_blocks[0]->id); + if (unique_postdom == -1) + continue; + + bool unique_postdom_flag = true; + for (auto exit_bb: loop->loop_exit_blocks) { + if (post_dta.get_idom(exit_bb->id) != unique_postdom) { + unique_postdom_flag = false; + } + } + + if (unique_postdom_flag) + loop->unique_exit_block = dta.cfg_[unique_postdom]; + } + + // Populate loop condition block + for(auto loop: loops) { + if (!loop->header_block) + continue; + + // this might be an unconditional loop or + // infinite loop. + if (loop->loop_exit_blocks.empty()) + continue; + + std::shared_ptr header = loop->header_block; + assert(header->successor.size() == 1 && "loop header cannot have more than one successor"); + if (isa(header->successor[0]->parent)) + loop->condition_block = header->successor[0]; + } + + // Assign id to the loops + for (unsigned int i = 0; i < loops.size(); i++) { + loops[i]->loop_id = i; + } + + // build a postorder loop tree + std::vector visited_loops(loops.size()); + visited_loops.assign(visited_loops.size(), false); + for (auto loop: top_level_loops) { + std::vector postorder_loop_tree; + visited_loops[loop->loop_id] = true; + + postorder_dfs_helper(postorder_loop_tree, visited_loops, loop->loop_id); + postorder_loop_tree.push_back(loop->loop_id); + postorder_loops_map[loop->loop_id] = postorder_loop_tree; + } + + // build a preorder loop tree + visited_loops.clear(); + visited_loops.assign(visited_loops.size(), false); + for (auto loop: top_level_loops) { + std::vector preorder_loop_tree; + visited_loops[loop->loop_id] = true; + + preorder_loop_tree.push_back(loop->loop_id); + preorder_dfs_helper(preorder_loop_tree, visited_loops, loop->loop_id); + preorder_loops_map[loop->loop_id] = preorder_loop_tree; + } +} + +std::set visited_blocks; +std::map ast_parent_map_loop; +// std::map, while_stmt::Ptr> return_blocks_parent_loop; +int jump_condition_counter = 0; +stmt::Ptr loop::convert_to_ast_impl(loop_info &li, dominator_analysis &dta_, std::vector, stmt_block::Ptr>> &return_blocks) { + while_stmt::Ptr while_block = std::make_shared(); + while_block->body = std::make_shared(); + structured_ast_loop = while_block; + + if (!condition_block) { + while_block->cond = std::make_shared(); + to(while_block->cond)->value = 1; + } + std::deque, stmt_block::Ptr>> worklist; + std::unordered_set> visited; + worklist.push_back({header_block->successor[0], to(while_block->body)}); + visited.insert(header_block->successor[0]); + + std::cerr << "loop: " << loop_id << " " << header_block->id << "\n"; + while (worklist.size()) { + auto bb_ast_pair = worklist.front(); + auto bb = bb_ast_pair.first; + auto ast = bb_ast_pair.second; + worklist.pop_front(); + + if (isa(bb->parent)) { + for (auto subloop: subloops) { + if (subloop->header_block->parent == bb->parent) { + std::cerr << "found subloop\n"; + std::vector, stmt_block::Ptr>> loop_out_blocks; + ast->stmts.push_back(subloop->convert_to_ast_impl(li, dta_, loop_out_blocks)); + + for (auto block: loop_out_blocks) { + // return_blocks_parent_loop.insert({block.first, to(ast->stmts.back())}); + worklist.push_back({block.first, block.second ? block.second : ast}); + } + std::cerr << "finish subloop\n"; + + break; + } + } + } + else if (isa(bb->parent)) { + if (!blocks_id_map.count(bb->id)) + continue; + + if_stmt::Ptr if_stmt_copy = std::make_shared(); + if_stmt_copy->then_stmt = to(std::make_shared()); + if_stmt_copy->else_stmt = to(std::make_shared()); + if_stmt_copy->annotation = to(bb->parent)->annotation; + + if (condition_block == bb) { + while_block->cond = to(bb->parent)->cond; + + if (to(to(bb->parent)->then_stmt)->stmts.size() == 0) { + std::cerr << "negated if cond\n"; + not_expr::Ptr negated_cond = std::make_shared(); + negated_cond->static_offset = while_block->cond->static_offset; + negated_cond->expr1 = while_block->cond; + while_block->cond = negated_cond; + + if (bb->else_branch) { + ast_parent_map_loop[to(while_block->body)] = ast; + worklist.push_back({bb->else_branch, to(while_block->body)}); + visited.insert(bb->else_branch); + } + + if (!blocks_id_map.count(bb->successor[1]->id) && blocks_id_map.count(bb->successor[0]->id)) { + std::cerr << "inserting out of loop block (1): " << bb->successor[0]->id << bb->successor[1]->is_exit_block << "\n"; + ast_parent_map_loop[to(while_block->body)] = ast; + worklist.push_back({bb->successor[1], nullptr}); + visited.insert(bb->successor[1]); + } + else if (blocks_id_map.count(bb->successor[1]->id) && !blocks_id_map.count(bb->successor[0]->id)){ + std::cerr << "inserting out of loop block (0): " << bb->successor[0]->id << bb->successor[0]->is_exit_block << "\n"; + worklist.push_back({bb->successor[0], nullptr}); + visited.insert(bb->successor[0]); + } + } + else { + if (bb->then_branch && blocks_id_map.count(bb->then_branch->id)) { + std::cerr << "loop cond then branch: " << bb->then_branch->id << "\n"; + ast_parent_map_loop[to(while_block->body)] = ast; + worklist.push_back({bb->then_branch, to(while_block->body)}); + visited.insert(bb->then_branch); + + // if (!blocks_id_map.count(bb->successor[1]->id)) { + // std::cerr << "pushing out of loop branch (1) out: " << bb->successor[1]->id << "\n"; + // worklist.push_back({bb->successor[1], ast_parent_map_loop[to(while_block->body)]}); + // visited.insert(bb->successor[1]); + // } + } + + if (bb->else_branch && blocks_id_map.count(bb->else_branch->id)) { + not_expr::Ptr negated_cond = std::make_shared(); + negated_cond->static_offset = while_block->cond->static_offset; + negated_cond->expr1 = while_block->cond; + while_block->cond = negated_cond; + + std::cerr << "loop cond else branch: " << bb->else_branch->id << "\n"; + ast_parent_map_loop[to(while_block->body)] = ast; + worklist.push_back({bb->else_branch, to(while_block->body)}); + visited.insert(bb->else_branch); + + // if (!blocks_id_map.count(bb->successor[0]->id)) { + // std::cerr << "pushing out of loop branch (0) out: " << bb->successor[0]->id << "\n"; + // worklist.push_back({bb->successor[0], ast_parent_map_loop[to(while_block->body)]}); + // visited.insert(bb->successor[0]); + // } + } + + if (blocks_id_map.count(bb->successor[1]->id) && !blocks_id_map.count(bb->successor[0]->id)) { + std::cerr << "inserting out of loop block (0): " << bb->successor[0]->id << bb->successor[0]->is_exit_block << "\n"; + ast_parent_map_loop[to(while_block->body)] = ast; + worklist.push_back({bb->successor[0], ast_parent_map_loop[to(while_block->body)]}); + visited.insert(bb->successor[0]); + } + else if (!blocks_id_map.count(bb->successor[1]->id) && blocks_id_map.count(bb->successor[0]->id)) { + std::cerr << "inserting out of loop block (1): " << bb->successor[1]->id << bb->successor[1]->is_exit_block << "\n"; + worklist.push_back({bb->successor[1], nullptr}); + visited.insert(bb->successor[1]); + } + } + } + else { + if_stmt_copy->cond = to(bb->parent)->cond; + bb->parent->dump(std::cerr, 0); + std::cerr << bb->successor[0]->id << " " << bb->successor[1]->id << "\n"; + + if (bb->then_branch) { + std::cerr << "non-cond if then: " << bb->id << " " << bb->then_branch->id << "\n"; + bb->then_branch->parent->dump(std::cerr, 0); + to(if_stmt_copy->then_stmt)->dump(std::cerr, 0); + ast_parent_map_loop[to(if_stmt_copy->then_stmt)] = ast; + if (!blocks_id_map.count(bb->then_branch->id) && !bb->then_branch->is_exit_block) { + return_blocks.push_back({bb->then_branch, to(if_stmt_copy->then_stmt)}); + } + else { + worklist.push_back({bb->then_branch, to(if_stmt_copy->then_stmt)}); + } + visited.insert(bb->then_branch); + } + + if (bb->else_branch) { + std::cerr << "non-cond if else: " << bb->id << " " << bb->else_branch->id <<"\n"; + bb->else_branch->parent->dump(std::cerr, 0); + to(if_stmt_copy->else_stmt)->dump(std::cerr, 0); + ast_parent_map_loop[to(if_stmt_copy->else_stmt)] = ast; + if (!blocks_id_map.count(bb->else_branch->id) && !bb->else_branch->is_exit_block) { + return_blocks.push_back({bb->else_branch, to(if_stmt_copy->else_stmt)}); + } + else { + worklist.push_back({bb->else_branch, to(if_stmt_copy->else_stmt)}); + } + visited.insert(bb->else_branch); + } + + if ((!bb->then_branch || !bb->else_branch) && bb->successor.size() == 2 && bb->successor[1]->is_exit_block) { + std::cerr << "inserting out of loop block" << bb->successor[1]->id << bb->successor[1]->is_exit_block << "\n"; + worklist.push_back({bb->successor[1], nullptr}); + visited.insert(bb->successor[1]); + } + + ast->stmts.push_back(to(if_stmt_copy)); + } + } + else if (isa(bb->parent)) { + if (to(bb->parent)->label1 == to(header_block->parent)->label1) { + bool is_last_block = false; + bool is_goto_to_outerloop = false; + std::cerr << "goto handler\n"; + std::cerr << "ast dump\n"; + ast->dump(std::cerr, 0); + std::cerr << "bb dump\n"; + bb->parent->dump(std::cerr, 0); + if (dta_.get_preorder_bb_map()[bb->id] == (int)dta_.get_preorder().size() - 1) { + is_last_block = true; + } + else { + // TODO: this can be cleaned up or reduced. + int next_preorder = dta_.get_preorder_bb_map()[bb->id] + 1 < (int)dta_.get_preorder().size() ? dta_.get_preorder()[dta_.get_preorder_bb_map()[bb->id] + 1] : -1; + int next_next_preorder = dta_.get_preorder_bb_map()[next_preorder] + 1 < (int)dta_.get_preorder().size() ? dta_.get_preorder()[dta_.get_preorder_bb_map()[next_preorder] + 1] : -1; + + if (loop_latch_blocks.size() == 1) + is_last_block = true; + else if (blocks_id_map.count(next_preorder)) + is_last_block = false; + else { + if (!blocks_id_map.count(next_preorder) || !blocks_id_map.count(next_next_preorder)) + is_last_block = true; + else if (unique_exit_block && (next_preorder == (int)unique_exit_block->id)) + is_last_block = true; + else if (unique_exit_block && (next_next_preorder == (int)unique_exit_block->id)) + is_last_block = true; + else if (next_preorder != -1 && next_next_preorder == -1 && dta_.cfg_[next_preorder]->is_exit_block) + is_last_block = true; + else if (next_preorder != -1 && next_next_preorder != -1 && dta_.cfg_[next_preorder]->is_exit_block && isa(dta_.cfg_[next_next_preorder]->parent)) + is_last_block = true; + else + is_last_block = false; + } + } + + if (!is_last_block && (int)bb->ast_depth - 2 > (int)header_block->ast_depth) { + // figure out the parent while loop for this basic block + auto target_bb = bb->successor[0]; + auto pointer_bb = bb; + std::vector> loop_parent_tree; + std::vector> mixed_walkback_tree; + do { + std::cerr << "iter: " << pointer_bb->id << "\n"; + + if (pointer_bb->predecessor.size() > 1) { + auto min_preorder_pred = std::min_element(pointer_bb->predecessor.begin(), pointer_bb->predecessor.end(), + [&dta_](std::shared_ptr bb1, std::shared_ptr bb2) { + return dta_.get_preorder_bb_map()[bb1->id] < dta_.get_preorder_bb_map()[bb2->id]; + }); + if (min_preorder_pred != pointer_bb->predecessor.end()) { + pointer_bb = *min_preorder_pred; + } + } + else { + pointer_bb = pointer_bb->predecessor[0]; + } + + // runtime can be optimized if we create a hashmap for (header_block->id => loop) map + // also a map for (conditional_block->id => loop) + for (auto loop: li.loops) { + if (isa(pointer_bb->parent) && mixed_walkback_tree.size() == 0) { + bool skip_if_stmt = false; + for (auto iloop: li.loops) { + if (iloop->condition_block->id == pointer_bb->id) { + skip_if_stmt = true; + break; + } + } + if (skip_if_stmt) + continue; + + std::cerr << "looping back from a if statement\n"; + mixed_walkback_tree.push_back(pointer_bb); + } + + if (loop->header_block == pointer_bb) { + loop_parent_tree.push_back(loop); + mixed_walkback_tree.push_back(loop->header_block); + break; + } + } + } while (target_bb != pointer_bb); + + std::cerr << "loop parent tree\n"; + for (auto loops : loop_parent_tree) { + std::cerr << loops->header_block->id << "\n"; + } + + std::cerr << "mixed walkback tree\n"; + for (auto bb: mixed_walkback_tree) { + std::cerr << bb->id << "\n"; + } + + bool use_mixed_tree = false; + if (isa(mixed_walkback_tree[0]->parent) && mixed_walkback_tree.size() > loop_parent_tree.size()) + use_mixed_tree = true; + + // generate guard variable definitions + std::cerr << "creating guard variable definitions\n"; + std::vector> guard_variables; + std::vector> guard_variable_defs; + for (unsigned i = 0; i < loop_parent_tree.size() - 2 + (unsigned)use_mixed_tree; i++) { + // create the var and set it's attributes + auto guard_variable = std::make_shared(); + guard_variable->var_name = "control_guard" + std::to_string(jump_condition_counter++); + guard_variable->var_type = std::make_shared(); + to(guard_variable->var_type)->scalar_type_id = scalar_type::INT_TYPE; + + // create a constant equal to 0 + auto int_constant_zero = std::make_shared(); + int_constant_zero->value = 0; + int_constant_zero->is_64bit = false; + + // create the variable declaration statement + auto guard_variable_declaration = std::make_shared(); + guard_variable_declaration->decl_var = guard_variable; + guard_variable_declaration->init_expr = int_constant_zero; + + guard_variables.push_back(guard_variable); + guard_variable_defs.push_back(guard_variable_declaration); + guard_variable_declaration->dump(std::cerr, 0); + } + + std::cerr << "creating guard variable assign statements\n"; + std::vector, std::shared_ptr>> set_guard_variable_exprs; + for (auto guard_var: guard_variables) { + // create a constant equal to 0 + auto int_constant_zero = std::make_shared(); + int_constant_zero->value = 0; + int_constant_zero->is_64bit = false; + + // create a constant equal to 1 + auto int_constant_one = std::make_shared(); + int_constant_one->value = 1; + int_constant_one->is_64bit = false; + + // create an expr for guard variable equal to 0 + auto guard_variable_expr_zero = std::make_shared(); + guard_variable_expr_zero->var1 = guard_var; + + // create an expr for guard variable equal to 1 + auto guard_variable_expr_one = std::make_shared(); + guard_variable_expr_one->var1 = guard_var; + + // create a guard variable assign expr for equal to 0 + auto guard_variable_assign_expr_zero = std::make_shared(); + guard_variable_assign_expr_zero->var1 = guard_variable_expr_zero; + guard_variable_assign_expr_zero->expr1 = int_constant_zero; + + // create a guard variable assign expr for equal to 1 + auto guard_variable_assign_expr_one = std::make_shared(); + guard_variable_assign_expr_one->var1 = guard_variable_expr_one; + guard_variable_assign_expr_one->expr1 = int_constant_one; + + // create the guard variable expression statement equal to 0 + auto guard_variable_expr_statement_zero = std::make_shared(); + guard_variable_expr_statement_zero->expr1 = guard_variable_assign_expr_zero; + + // create the guard variable expression statement equal to 1 + auto guard_variable_expr_statement_one = std::make_shared(); + guard_variable_expr_statement_one->expr1 = guard_variable_assign_expr_one; + + set_guard_variable_exprs.push_back({guard_variable_expr_statement_zero, guard_variable_expr_statement_one}); + guard_variable_expr_statement_zero->dump(std::cerr, 0); + guard_variable_expr_statement_one->dump(std::cerr, 0); + } + + std::cerr << "creating guard if statements\n"; + std::vector> guard_if_blocks; + for (unsigned i = 0; i < guard_variables.size(); i++) { + // create guard if statement + auto guard_if_statement = std::make_shared(); + auto guard_statement_block = std::make_shared(); + guard_if_statement->then_stmt = guard_statement_block; + guard_if_statement->else_stmt = std::make_shared(); + + // create guard if condition + auto guard_if_condition_expr = std::make_shared(); + guard_if_condition_expr->var1 = guard_variables[i]; + + // set the guard if condition + guard_if_statement->cond = guard_if_condition_expr; + + // insert set expressions inside if only if it is not the last guard block + if (guard_variables.size() >= 2 && i < guard_variables.size() - 1) + guard_statement_block->stmts.push_back(to(set_guard_variable_exprs[i + 1].second)); + + // insert break/continue inside the if statement based on the location of it + if (i < guard_variables.size() - 1) + guard_statement_block->stmts.push_back(std::make_shared()); + else + guard_statement_block->stmts.push_back(std::make_shared()); + + guard_if_blocks.push_back(guard_if_statement); + guard_if_statement->dump(std::cerr, 0); + } + + // first we need to set the innermost guard variable = 1; + ast->stmts.push_back(set_guard_variable_exprs[0].second); + + // now we can take care of inserting other operations + // 1) insert guard variable definition + // 2) set guard variable = 0 + // 3) inser the if guard block + unsigned i = 0; + if (use_mixed_tree) { + i = 0; + } + else { + i = 1; + } + for (unsigned blocks_counter = 0; i + 1 < loop_parent_tree.size() && blocks_counter < guard_variables.size(); i++, blocks_counter++) { + while_stmt::Ptr guard_set_insertion_loop = loop_parent_tree[i]->structured_ast_loop; + while_stmt::Ptr if_block_insertion_loop = loop_parent_tree[i + 1]->structured_ast_loop; + + auto guard_set_insertion_block = to(guard_set_insertion_loop->body); + auto if_block_insertion_block = to(if_block_insertion_loop->body); + + guard_set_insertion_block->stmts.insert(guard_set_insertion_block->stmts.begin(), to(set_guard_variable_exprs[blocks_counter].first)); + + auto guard_insertion_loop = std::find(if_block_insertion_block->stmts.begin(), if_block_insertion_block->stmts.end(), to(guard_set_insertion_loop)); + if (guard_insertion_loop != if_block_insertion_block->stmts.end()) { + if_block_insertion_block->stmts.insert(guard_insertion_loop + 1, to(guard_if_blocks[blocks_counter])); + if_block_insertion_block->stmts.insert(if_block_insertion_block->stmts.begin(), to(guard_variable_defs[blocks_counter])); + } + } + + std::cerr << "handling break cond\n"; + is_goto_to_outerloop = true; + } + if (!is_last_block) { + std::cerr << "inserted continue: " << bb->id << loop_id << "\n"; + ast->stmts.push_back(is_goto_to_outerloop ? to(std::make_shared()) : to(std::make_shared())); + while_block->continue_blocks.push_back(ast); + } + visited.insert(bb); + } + } + else { + assert(bb->successor.size() <= 1); + bool exit_bb_succ = false; + + std::cerr << "bb (open): " << bb->id << "\n"; + if (bb->is_exit_block && !blocks_id_map.count(bb->id)) { + for (auto subloop: subloops) { + if (bb == subloop->unique_exit_block) { + ast->stmts.push_back(to(std::make_shared())); + } + } + for (auto exit: loop_exit_blocks) { + for (auto pred: bb->predecessor) { + if (pred->id == exit->id && bb->successor.size()) { + return_blocks.push_back({bb->successor[0], ast}); + std::cerr << "found return block " << bb->successor[0]->id << "\n"; + exit_bb_succ = true; + break; + } + } + + if (exit_bb_succ) + break; + } + + if (exit_bb_succ) + continue; + + if (bb == unique_exit_block && dta_.get_preorder_bb_map()[bb->id] != (int)dta_.get_preorder().size() - 1) { + ast->stmts.push_back(to(std::make_shared())); + } + } + + if (!blocks_id_map.count(bb->id) && !bb->is_exit_block) { + std::cerr << "case for 26: " << bb->id << worklist.size() << loop_id << "\n"; + + if (isa(bb->successor[0]->parent) && (int)bb->ast_depth - 2 > (int)bb->successor[0]->successor[0]->ast_depth) { + return_blocks.push_back({bb, ast}); + } + else { + return_blocks.push_back({bb, nullptr}); + } + continue; + } + + if (!bb->is_exit_block && !isa(bb->parent)) { + std::cerr << "bb: " << bb->id << "\n"; + ast->dump(std::cerr, 0); + ast->stmts.push_back(to(bb->parent)); + } + + if (bb->successor.size()) { + if (visited.count(bb->successor[0])) + continue; + else + visited.insert(bb->successor[0]); + + if (bb->is_exit_block) { + worklist.push_back({bb->successor[0], ast_parent_map_loop[ast]}); + } + else { + worklist.push_back({bb->successor[0], ast}); + } + } + } + } + + return to(while_block); +} + +std::map ast_parent_map_global; +block::stmt_block::Ptr loop_info::convert_to_ast(block::stmt_block::Ptr ast) { + block::stmt_block::Ptr return_ast = std::make_shared(); + + std::deque, stmt_block::Ptr>> worklist; + std::unordered_set> visited; + worklist.push_back({dta.cfg_[0], return_ast}); + visited.insert(dta.cfg_[0]); + + while (worklist.size()) { + auto bb_ast_pair = worklist.front(); + auto bb = bb_ast_pair.first; + auto ast = bb_ast_pair.second; + worklist.pop_front(); + + if (isa(bb->parent)) { + for (auto loop : top_level_loops) { + if (loop->header_block->parent == bb->parent) { + std::cerr << "found outerloop\n"; + std::vector, stmt_block::Ptr>> loop_out_blocks; + ast->stmts.push_back(loop->convert_to_ast_impl(*this, dta, loop_out_blocks)); + loop->structured_ast_loop = to(ast->stmts.back()); + + for (auto block: loop_out_blocks) { + worklist.push_back({block.first, block.second ? block.second : ast}); + } + std::cerr << "finish outerloop\n"; + std::cerr << worklist.size() << "\n"; + break; + } + } + } + else if (isa(bb->parent)) { + + if (bb_loop_map.count(bb->id)) + continue; + + if_stmt::Ptr if_stmt_copy = std::make_shared(); + if_stmt_copy->then_stmt = to(std::make_shared()); + if_stmt_copy->else_stmt = to(std::make_shared()); + if_stmt_copy->cond = to(bb->parent)->cond; + if_stmt_copy->annotation = to(bb->parent)->annotation; + + // push the then branch onto worklist. (worklist should be a pair ) ? + if (bb->then_branch) { + ast_parent_map_global[to(if_stmt_copy->then_stmt)] = ast; + worklist.push_back({bb->then_branch, to(if_stmt_copy->then_stmt)}); + visited.insert(bb->then_branch); + } + + if (bb->else_branch) { + ast_parent_map_global[to(if_stmt_copy->else_stmt)] = ast; + worklist.push_back({bb->else_branch, to(if_stmt_copy->else_stmt)}); + visited.insert(bb->else_branch); + } + + ast->stmts.push_back(to(if_stmt_copy)); + } + else { + assert(bb->successor.size() <= 1); + + if (bb->is_exit_block) { + for (auto loop: loops) { + if (bb == loop->unique_exit_block) { + std::cerr << "inserted break: " << bb->id << "\n"; + ast->stmts.push_back(to(std::make_shared())); + } + } + } + + if (bb_loop_map.count(bb->id)) + continue; + + // what is happening is that when we see a if stmt exit block we should + // reduce the level of the tree, it is not being done now. + if (!bb->is_exit_block && !isa(bb->parent)) { + std::cerr << "out bb: " << bb->id << "\n"; + ast->stmts.push_back(to(bb->parent)); + } + + if (bb->successor.size()) { + if (visited.count(bb->successor[0])) + continue; + else + visited.insert(bb->successor[0]); + + if (bb->is_exit_block) + worklist.push_back({bb->successor[0], ast_parent_map_global[ast]}); + else + worklist.push_back({bb->successor[0], ast}); + } + } + } + + return return_ast; +} diff --git a/src/builder/builder_context.cpp b/src/builder/builder_context.cpp index 0d47559..6762789 100644 --- a/src/builder/builder_context.cpp +++ b/src/builder/builder_context.cpp @@ -303,12 +303,214 @@ block::stmt::Ptr builder_context::extract_ast_from_function_impl(void) { block::eliminate_redundant_vars(ast); } + // return ast; if (feature_unstructured) return ast; - block::loop_finder finder; - finder.ast = ast; - ast->accept(&finder); + basic_block::cfg_block BBs = generate_basic_blocks(block::to(ast)); + basic_block::cfg_block post_BBs = generate_basic_blocks(block::to(ast)); + + std::cerr << "++++++ basic blocks ++++++ \n"; + for (auto bb: BBs) { + std::cerr << bb->id << ":" << bb->name << ":" << " ; "; + for (auto pred: bb->predecessor) { + std::cerr << pred->name << ", "; + } + std::cerr << bb->ast_depth; + std::cerr << "\n"; + if (bb->branch_expr) { + std::cerr << " "; + bb->branch_expr->dump(std::cerr, 0); + } + std::cerr << " "; + std::cerr << "br "; + for (auto branches: bb->successor) { + std::cerr << branches->name << ", "; + } + std::cerr << "\n"; + } + std::cerr << "++++++ basic blocks ++++++ \n"; + + std::cerr << "++++++ dominance ++++++ \n"; + dominator_analysis dom(BBs); + dominator_analysis post_dom(post_BBs, true); + + std::cerr << "max depth: " << dom.max_depth << "\n"; + std::cerr << "max depth bb id: " << dom.max_depth_bb_id << "\n"; + std::cerr << "== postorder map ==\n"; + for (int i: dom.get_postorder_bb_map()) { + std::cerr << i << "\n"; + } + std::cerr << "== postorder map ==\n"; + + std::cerr << "== postorder ==\n"; + for (int i: dom.get_postorder()) { + std::cerr << i << "\n"; + } + std::cerr << "== postorder ==\n"; + + std::cerr << "== preorder map ==\n"; + for (int i: dom.get_preorder_bb_map()) { + std::cerr << i << "\n"; + } + std::cerr << "== preorder map ==\n"; + + std::cerr << "== preorder ==\n"; + for (int i: dom.get_preorder()) { + std::cerr << i << "\n"; + } + std::cerr << "== preorder ==\n"; + + std::cerr << "== idom ==\n"; + std::cerr << "get_idom(int) test: get_idom(0): " << dom.get_idom(0) << "\n"; + std::cerr << "get_idom(int) test: get_idom(-1): " << dom.get_idom(-1) << "\n"; + + for (unsigned int i = 0; i < dom.get_idom().size(); i++) { + std::cerr << i << " : " << dom.get_idom()[i] << "\n"; + } + std::cerr << "== idom ==\n"; + + std::cerr << "== idom map ==\n"; + std::cerr << "get_idom_map(int) test: get_idom_map(0): "; + for (int i : dom.get_idom_map(0)) std::cerr << i << " "; + std::cerr << "\n"; + + std::cerr << "get_idom_map(int) test: get_idom_map(-1): "; + for (int i : dom.get_idom_map(-1)) std::cerr << i << " "; + std::cerr << "\n"; + + for (auto children: dom.get_idom_map()) { + std::cerr << children.first << ": "; + for (int child: children.second) { + std::cerr << child << " "; + } + std::cerr << "\n"; + } + std::cerr << "== idom map ==\n"; + + std::cerr << "== postorder idom ==\n"; + for (auto idom: dom.get_postorder_idom_map()) { + std::cerr << idom << "\n"; + } + std::cerr << "== postorder idom ==\n"; + + std::cerr << "(postdom) max depth: " << post_dom.max_depth << "\n"; + std::cerr << "(postdom) max depth bb id: " << post_dom.max_depth_bb_id << "\n"; + std::cerr << "== (postdom) postorder map ==\n"; + for (int i: post_dom.get_postorder_bb_map()) { + std::cerr << i << "\n"; + } + std::cerr << "== (postdom) postorder map ==\n"; + + std::cerr << "== (postdom) postorder ==\n"; + for (int i: post_dom.get_postorder()) { + std::cerr << i << "\n"; + } + std::cerr << "== (postdom) postorder ==\n"; + + std::cerr << "== (postdom) preorder map ==\n"; + for (int i: dom.get_preorder_bb_map()) { + std::cerr << i << "\n"; + } + std::cerr << "== (postdom) preorder map ==\n"; + + std::cerr << "== (postdom) preorder ==\n"; + for (int i: dom.get_preorder()) { + std::cerr << i << "\n"; + } + std::cerr << "== (postdom) preorder ==\n"; + + std::cerr << "== (postdom) idom ==\n"; + std::cerr << "get_idom(int) test: get_idom(0): " << post_dom.get_idom(0) << "\n"; + std::cerr << "get_idom(int) test: get_idom(-1): " << post_dom.get_idom(-1) << "\n"; + + for (unsigned int i = 0; i < post_dom.get_idom().size(); i++) { + std::cerr << i << " : " << post_dom.get_idom()[i] << "\n"; + } + std::cerr << "== (postdom) idom ==\n"; + + std::cerr << "== (postdom) idom map ==\n"; + std::cerr << "get_idom_map(int) test: get_idom_map(0): "; + for (int i : post_dom.get_idom_map(0)) std::cerr << i << " "; + std::cerr << "\n"; + + std::cerr << "get_idom_map(int) test: get_idom_map(-1): "; + for (int i : post_dom.get_idom_map(-1)) std::cerr << i << " "; + std::cerr << "\n"; + + for (auto children: post_dom.get_idom_map()) { + std::cerr << children.first << ": "; + for (int child: children.second) { + std::cerr << child << " "; + } + std::cerr << "\n"; + } + std::cerr << "== (postdom) idom map ==\n"; + + std::cerr << "== (postdom) postorder idom ==\n"; + for (auto idom: post_dom.get_postorder_idom_map()) { + std::cerr << idom << "\n"; + } + std::cerr << "== (postdom) postorder idom ==\n"; + std::cerr << "++++++ dominance ++++++ \n"; + + std::cerr << "++++++ loop info ++++++ \n"; + loop_info LI(BBs, dom, post_dom); + int loop_num = 0; + for (auto loop: LI.loops) { + std::cerr << "++++++ loop " << loop_num++ << " ++++++ \n"; + + std::cerr << "loop headers: " << loop->header_block->id << "\n"; + + std::cerr << "blocks: "; + for (auto bb: loop->blocks) std::cerr << bb->id << " "; + std::cerr << "\n"; + + std::cerr << "loop latches: "; + for (auto bb: loop->loop_latch_blocks) std::cerr << bb->id << " "; + std::cerr << "\n"; + + std::cerr << "loop exits: "; + for (auto bb: loop->loop_exit_blocks) std::cerr << bb->id << " "; + std::cerr << "\n"; + if (loop->unique_exit_block) std::cerr << "loop unique exit block: " << loop->unique_exit_block->id << "\n"; + + std::cerr << "parent loop: (loop header: " << (loop->parent_loop ? (int)loop->parent_loop->header_block->id : -1) << ")\n"; + + std::cerr << "subloops: "; + for (auto subl: loop->subloops) std::cerr << "(loop header: " << subl->header_block->id << ") "; + std::cerr << "\n"; + } + + std::cerr << "++++++ top level loops ++++++ \n"; + for (auto top_level_loop: LI.top_level_loops) std::cerr << "(loop header: " << top_level_loop->header_block->id << ") "; + std::cerr << "\n"; + + std::cerr << "++++++ preorder loops tree ++++++ \n"; + for (auto loop_tree: LI.preorder_loops_map) { + std::cerr << "loop tree root: (loop header: " << LI.loops[loop_tree.first]->header_block->id << ")\n"; + std::cerr << "preorder: "; + for (auto node: loop_tree.second) std::cerr << node << " "; + std::cerr << "\n"; + } + + std::cerr << "++++++ postorder loops tree ++++++ \n"; + for (auto loop_tree: LI.postorder_loops_map) { + std::cerr << "loop tree root: (loop header: " << LI.loops[loop_tree.first]->header_block->id << ")\n"; + std::cerr << "postorder: "; + for (auto node: loop_tree.second) std::cerr << node << " "; + std::cerr << "\n"; + } + + std::cerr << "++++++ loop info ++++++ \n"; + + std::cerr << "++++++ convert to ast ++++++ \n"; + ast = LI.convert_to_ast(block::to(ast)); + std::cerr << "++++++ convert to ast ++++++ \n"; + + // block::loop_finder finder; + // finder.ast = ast; + // ast->accept(&finder); block::for_loop_finder for_finder; for_finder.ast = ast; @@ -405,7 +607,6 @@ block::stmt::Ptr builder_context::extract_ast_from_function_internal(std::vector ret_ast = ast; } catch (LoopBackException &e) { current_builder_context = nullptr; - block::goto_stmt::Ptr goto_stmt = std::make_shared(); goto_stmt->static_offset.clear(); goto_stmt->temporary_label_number = e.static_offset; @@ -421,7 +622,15 @@ block::stmt::Ptr builder_context::extract_ast_from_function_internal(std::vector add_stmt_to_current_block(goto_stmt, false); } else { for (unsigned int i = e.child_id; i < e.parent->stmts.size(); i++) { - add_stmt_to_current_block(e.parent->stmts[i], false); + if (isa(e.parent->stmts[i])) { + block::goto_stmt::Ptr goto_stmt = std::make_shared(); + goto_stmt->static_offset.clear(); + goto_stmt->temporary_label_number = to(e.parent->stmts[i])->temporary_label_number; + add_stmt_to_current_block(goto_stmt, false); + } + else { + add_stmt_to_current_block(e.parent->stmts[i], false); + } } } ret_ast = ast;