Commit 18fa0178 authored by 陈清源's avatar 陈清源

lab4 publish

parent 720f0a57
This diff is collapsed.
#ifndef SYSYC_DOMINATORS_HPP
#define SYSYC_DOMINATORS_HPP
#include "BasicBlock.h"
#include "PassManager.hpp"
#include <list>
#include <map>
#include <set>
class Dominators : public Pass {
public:
explicit Dominators(Module *m) : Pass(m) {}
~Dominators() = default;
void run() override;
void create_doms(Function *f);
void create_reverse_post_order(Function *f);
void create_idom(Function *f);
void create_dominance_frontier(Function *f);
void create_dom_tree_succ(Function *f);
// for debug
void print_idom(Function *f);
void print_dominance_frontier(Function *f);
/****************api about Dominator****************/
void add_dom(BasicBlock *bb, BasicBlock *dom_bb) { doms_[bb].insert(dom_bb); }
std::set<BasicBlock *> &get_doms(BasicBlock *bb) { return doms_[bb]; }
void set_doms(BasicBlock *bb, std::set<BasicBlock *> &doms) {
doms_[bb].clear();
doms_[bb].insert(doms.begin(), doms.end());
}
BasicBlock *get_idom(BasicBlock *bb) { return idom_[bb]; }
void set_idom(BasicBlock *bb, BasicBlock *idom) { idom_[bb] = idom; }
void add_dominance_frontier(BasicBlock *bb, BasicBlock *dom_frontier_bb) {
dom_frontier_[bb].insert(dom_frontier_bb);
}
std::set<BasicBlock *> &get_dominance_frontier(BasicBlock *bb) { return dom_frontier_[bb]; }
void set_dominance_frontier(BasicBlock *bb, std::set<BasicBlock *> &df) {
dom_frontier_[bb].clear();
dom_frontier_[bb].insert(df.begin(), df.end());
}
// successor blocks of this node in dominance tree
std::set<BasicBlock *> get_dom_tree_succ_blocks(BasicBlock *bb) { return dom_tree_succ_blocks_[bb]; }
void add_dom_tree_succ_block(BasicBlock *bb, BasicBlock *dom_tree_succ_bb) {
dom_tree_succ_blocks_[bb].insert(dom_tree_succ_bb);
}
/****************api about Dominator****************/
private:
void post_order_visit(BasicBlock *bb, std::set<BasicBlock *> &visited);
BasicBlock *intersect(BasicBlock *b1, BasicBlock *b2);
std::list<BasicBlock *> reverse_post_order_{};
std::map<BasicBlock *, int> post_order_id_{}; // the root has highest ID
std::map<BasicBlock *, std::set<BasicBlock *>> doms_{}; // dominance set
std::map<BasicBlock *, BasicBlock *> idom_{}; // immediate dominance
std::map<BasicBlock *, std::set<BasicBlock *>> dom_frontier_{}; // dominance frontier set
std::map<BasicBlock *, std::set<BasicBlock *>> dom_tree_succ_blocks_{};
};
#endif
#ifndef SYSYC_MEM2REG_HPP
#define SYSYC_MEM2REG_HPP
#include "BasicBlock.h"
#include "Dominators.h"
#include "Function.h"
#include "IRBuilder.h"
#include "Instruction.h"
#include "Module.h"
#include "PassManager.hpp"
#include <memory>
class Mem2Reg : public Pass {
private:
Function *func_;
std::unique_ptr<Dominators> dominators_;
public:
Mem2Reg(Module *m) : Pass(m) {}
~Mem2Reg(){};
void run() override;
void generate_phi();
void re_name(BasicBlock *bb);
void remove_alloca();
};
#endif
\ No newline at end of file
#ifndef PASSMANAGER_HPP
#define PASSMANAGER_HPP
#include "Module.h"
#include <memory>
#include <vector>
class Pass {
public:
Pass(Module *m) : m_(m) {}
virtual ~Pass() = default;
virtual void run() = 0;
protected:
Module *m_;
};
class PassManager {
public:
PassManager(Module *m) : m_(m) {}
template <typename PassType, typename... Args>
void add_pass(bool print_ir, Args &&...args) {
passes_.push_back(
std::pair<std::unique_ptr<Pass>, bool>(new PassType(m_, std::forward<Args>(args)...), print_ir));
}
void run() {
for (auto &pass : passes_) {
pass.first->run();
if (pass.second) {
m_->set_print_name();
std::cout << m_->print();
}
}
}
private:
std::vector<std::pair<std::unique_ptr<Pass>, bool>> passes_;
Module *m_;
};
#endif
\ No newline at end of file
......@@ -2,4 +2,5 @@ add_subdirectory(parser)
add_subdirectory(common)
add_subdirectory(io)
add_subdirectory(lightir)
add_subdirectory(cminusfc)
\ No newline at end of file
add_subdirectory(cminusfc)
add_subdirectory(optimization)
\ No newline at end of file
#include "Dominators.h"
#include "Mem2Reg.hpp"
#include "PassManager.hpp"
#include "cminusf_builder.hpp"
#include "logging.hpp"
#include <fstream>
#include <iostream>
#include <memory>
......@@ -6,20 +11,15 @@
using namespace std::literals::string_literals;
void print_help(std::string exe_name) {
std::cout << "Usage: " << exe_name <<
" [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] <input-file>" << std::endl;
std::cout << "Usage: " << exe_name << " [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] [-mem2reg] <input-file>"
<< std::endl;
}
int main(int argc, char **argv) {
std::string target_path;
std::string input_path;
bool mem2reg = false;
bool const_propagation = false;
bool activevars = false;
bool loop_inv_hoist = false;
bool loop_search = false;
bool emit = false;
for (int i = 1; i < argc; ++i) {
......@@ -38,14 +38,6 @@ int main(int argc, char **argv) {
emit = true;
} else if (argv[i] == "-mem2reg"s) {
mem2reg = true;
} else if (argv[i] == "-loop-search"s) {
loop_search = true;
} else if (argv[i] == "-loop-inv-hoist"s) {
loop_inv_hoist = true;
} else if (argv[i] == "-const-propagation"s) {
const_propagation = true;
} else if (argv[i] == "-active-vars"s) {
activevars = true;
} else {
if (input_path.empty()) {
input_path = argv[i];
......@@ -85,6 +77,14 @@ int main(int argc, char **argv) {
auto m = builder.getModule();
m->set_print_name();
PassManager PM(m.get());
if (mem2reg) {
PM.add_pass<Mem2Reg>(emit);
}
PM.run();
auto IR = m->print();
std::ofstream output_stream;
......
add_library(
OP_lib STATIC
Dominators.cpp
Mem2Reg.cpp
)
#include "Dominators.h"
#include <algorithm>
#include <string>
void Dominators::run() {
for (auto &f1 : m_->get_functions()) {
auto f = &f1;
if (f->get_basic_blocks().size() == 0)
continue;
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
doms_.insert({bb, {}});
idom_.insert({bb, {}});
dom_frontier_.insert({bb, {}});
dom_tree_succ_blocks_.insert({bb, {}});
}
create_reverse_post_order(f);
create_idom(f);
create_dominance_frontier(f);
create_dom_tree_succ(f);
// for debug
// print_idom(f);
// print_dominance_frontier(f);
}
}
void Dominators::create_doms(Function *f) {
// init
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
add_dom(bb, bb);
}
// iterate
bool changed = true;
std::vector<BasicBlock *> ret(f->get_num_basic_blocks());
std::vector<BasicBlock *> pre(f->get_num_basic_blocks());
while (changed) {
changed = false;
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
auto &bbs = bb->get_pre_basic_blocks();
auto &first = get_doms((*bbs.begin()));
pre.insert(pre.begin(), first.begin(), first.end());
pre.resize(first.size());
ret.resize(f->get_num_basic_blocks());
for (auto iter = ++bbs.begin(); iter != bbs.end(); ++iter) {
auto &now = get_doms((*iter));
auto it = std::set_intersection(pre.begin(), pre.end(), now.begin(), now.end(), ret.begin());
ret.resize(it - ret.begin());
pre.resize(ret.size());
pre.insert(pre.begin(), ret.begin(), ret.end());
}
std::set<BasicBlock *> doms;
doms.insert(bb);
doms.insert(pre.begin(), pre.end());
if (get_doms(bb) != doms) {
set_doms(bb, doms);
changed = true;
}
}
}
}
void Dominators::create_reverse_post_order(Function *f) {
reverse_post_order_.clear();
post_order_id_.clear();
std::set<BasicBlock *> visited;
post_order_visit(f->get_entry_block(), visited);
reverse_post_order_.reverse();
}
void Dominators::post_order_visit(BasicBlock *bb, std::set<BasicBlock *> &visited) {
visited.insert(bb);
for (auto b : bb->get_succ_basic_blocks()) {
if (visited.find(b) == visited.end())
post_order_visit(b, visited);
}
post_order_id_[bb] = reverse_post_order_.size();
reverse_post_order_.push_back(bb);
}
void Dominators::create_idom(Function *f) {
// init
for (auto &bb : f->get_basic_blocks())
set_idom(&bb, nullptr);
auto root = f->get_entry_block();
set_idom(root, root);
// iterate
bool changed = true;
while (changed) {
changed = false;
for (auto bb : this->reverse_post_order_) {
if (bb == root) {
continue;
}
// find one pred which has idom
BasicBlock *pred = nullptr;
for (auto p : bb->get_pre_basic_blocks()) {
if (get_idom(p)) {
pred = p;
break;
}
}
assert(pred);
BasicBlock *new_idom = pred;
for (auto p : bb->get_pre_basic_blocks()) {
if (p == pred)
continue;
if (get_idom(p)) {
new_idom = intersect(p, new_idom);
}
}
if (get_idom(bb) != new_idom) {
set_idom(bb, new_idom);
changed = true;
}
}
}
}
// find closest parent of b1 and b2
BasicBlock *Dominators::intersect(BasicBlock *b1, BasicBlock *b2) {
while (b1 != b2) {
while (post_order_id_[b1] < post_order_id_[b2]) {
assert(get_idom(b1));
b1 = get_idom(b1);
}
while (post_order_id_[b2] < post_order_id_[b1]) {
assert(get_idom(b2));
b2 = get_idom(b2);
}
}
return b1;
}
void Dominators::create_dominance_frontier(Function *f) {
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
if (bb->get_pre_basic_blocks().size() >= 2) {
for (auto p : bb->get_pre_basic_blocks()) {
auto runner = p;
while (runner != get_idom(bb)) {
add_dominance_frontier(runner, bb);
runner = get_idom(runner);
}
}
}
}
}
void Dominators::create_dom_tree_succ(Function *f) {
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
auto idom = get_idom(bb);
// e.g, entry bb
if (idom != bb) {
add_dom_tree_succ_block(idom, bb);
}
}
}
void Dominators::print_idom(Function *f) {
int counter = 0;
std::map<BasicBlock *, std::string> bb_id;
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
if (bb->get_name().empty())
bb_id[bb] = "bb" + std::to_string(counter);
else
bb_id[bb] = bb->get_name();
counter++;
}
printf("Immediate dominance of function %s:\n", f->get_name().c_str());
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
std::string output;
output = bb_id[bb] + ": ";
if (get_idom(bb)) {
output += bb_id[get_idom(bb)];
} else {
output += "null";
}
printf("%s\n", output.c_str());
}
}
void Dominators::print_dominance_frontier(Function *f) {
int counter = 0;
std::map<BasicBlock *, std::string> bb_id;
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
if (bb->get_name().empty())
bb_id[bb] = "bb" + std::to_string(counter);
else
bb_id[bb] = bb->get_name();
counter++;
}
printf("Dominance Frontier of function %s:\n", f->get_name().c_str());
for (auto &bb1 : f->get_basic_blocks()) {
auto bb = &bb1;
std::string output;
output = bb_id[bb] + ": ";
if (get_dominance_frontier(bb).empty()) {
output += "null";
} else {
bool first = true;
for (auto df : get_dominance_frontier(bb)) {
if (first) {
first = false;
} else {
output += ", ";
}
output += bb_id[df];
}
}
printf("%s\n", output.c_str());
}
}
#include "Mem2Reg.hpp"
#include "IRBuilder.h"
#include <memory>
// 判断是否是全局变量地址
#define IS_GLOBAL_VARIABLE(l_val) dynamic_cast<GlobalVariable *>(l_val)
// 判断是否是 getelementptr 指令
#define IS_GEP_INSTR(l_val) dynamic_cast<GetElementPtrInst *>(l_val)
std::map<Value *, std::vector<Value *>> var_val_stack; // 全局变量初值提前存入栈中
void Mem2Reg::run() {
// 创建支配树分析 Pass 的实例
dominators_ = std::make_unique<Dominators>(m_);
// 建立支配树
dominators_->run();
// 以函数为单元遍历实现 Mem2Reg 算法
for (auto &f : m_->get_functions()) {
func_ = &f;
if (func_->get_basic_blocks().size() >= 1) {
// 对应伪代码中 phi 指令插入的阶段
generate_phi();
// 对应伪代码中重命名阶段
re_name(func_->get_entry_block());
}
// 移除冗余的局部变量的分配空间
remove_alloca();
}
}
void Mem2Reg::generate_phi() {
// global_live_var_name 是全局名字集合,以 alloca 出的局部变量来统计。
// 步骤一:找到活跃在多个 block 的全局名字集合,以及它们所属的 bb 块
std::set<Value *> global_live_var_name;
std::map<Value *, std::set<BasicBlock *>> live_var_2blocks;
for (auto &bb1 : func_->get_basic_blocks()) {
auto bb = &bb1;
std::set<Value *> var_is_killed;
for (auto &instr1 : bb->get_instructions()) {
auto instr = &instr1;
if (instr->is_store()) {
// store i32 a, i32 *b
// a is r_val, b is l_val
auto r_val = static_cast<StoreInst *>(instr)->get_rval();
auto l_val = static_cast<StoreInst *>(instr)->get_lval();
if (!IS_GLOBAL_VARIABLE(l_val) && !IS_GEP_INSTR(l_val)) {
global_live_var_name.insert(l_val);
live_var_2blocks[l_val].insert(bb);
}
}
}
}
// 步骤二:从支配树获取支配边界信息,并在对应位置插入 phi 指令
std::map<std::pair<BasicBlock *, Value *>, bool> bb_has_var_phi; // bb has phi for var
for (auto var : global_live_var_name) {
std::vector<BasicBlock *> work_list;
work_list.assign(live_var_2blocks[var].begin(), live_var_2blocks[var].end());
for (int i = 0; i < work_list.size(); i++) {
auto bb = work_list[i];
for (auto bb_dominance_frontier_bb : dominators_->get_dominance_frontier(bb)) {
if (bb_has_var_phi.find({bb_dominance_frontier_bb, var}) == bb_has_var_phi.end()) {
// generate phi for bb_dominance_frontier_bb & add bb_dominance_frontier_bb to work list
auto phi =
PhiInst::create_phi(var->get_type()->get_pointer_element_type(), bb_dominance_frontier_bb);
phi->set_lval(var);
bb_dominance_frontier_bb->add_instr_begin(phi);
work_list.push_back(bb_dominance_frontier_bb);
bb_has_var_phi[{bb_dominance_frontier_bb, var}] = true;
}
}
}
}
}
void Mem2Reg::re_name(BasicBlock *bb) {
std::vector<Instruction *> wait_delete;
// 步骤三:将 phi 指令作为 lval 的最新定值,lval 即是为局部变量 alloca 出的地址空间
for (auto &instr1 : bb->get_instructions()) {
auto instr = &instr1;
if (instr->is_phi()) {
auto l_val = static_cast<PhiInst *>(instr)->get_lval();
var_val_stack[l_val].push_back(instr);
}
}
for (auto &instr1 : bb->get_instructions()) {
auto instr = &instr1;
// 步骤四:用 lval 最新的定值替代对应的load指令
if (instr->is_load()) {
auto l_val = static_cast<LoadInst *>(instr)->get_lval();
if (!IS_GLOBAL_VARIABLE(l_val) && !IS_GEP_INSTR(l_val)) {
if (var_val_stack.find(l_val) != var_val_stack.end()) {
// 此处指令替换会维护 UD 链与 DU 链
instr->replace_all_use_with(var_val_stack[l_val].back());
wait_delete.push_back(instr);
}
}
}
// 步骤五:将 store 指令的 rval,也即被存入内存的值,作为 lval 的最新定值
if (instr->is_store()) {
auto l_val = static_cast<StoreInst *>(instr)->get_lval();
auto r_val = static_cast<StoreInst *>(instr)->get_rval();
if (!IS_GLOBAL_VARIABLE(l_val) && !IS_GEP_INSTR(l_val)) {
var_val_stack[l_val].push_back(r_val);
wait_delete.push_back(instr);
}
}
}
// 步骤六:为 lval 对应的 phi 指令参数补充完整
for (auto succ_bb : bb->get_succ_basic_blocks()) {
for (auto &instr1 : succ_bb->get_instructions()) {
auto instr = &instr1;
if (instr->is_phi()) {
auto l_val = static_cast<PhiInst *>(instr)->get_lval();
if (var_val_stack.find(l_val) != var_val_stack.end()) {
assert(var_val_stack[l_val].size() != 0);
static_cast<PhiInst *>(instr)->add_phi_pair_operand(var_val_stack[l_val].back(), bb);
}
// 对于 phi 参数只有一个前驱定值的情况,将会输出 [ undef, bb ] 的参数格式
}
}
}
// 步骤七:对 bb 在支配树上的所有后继节点,递归执行 re_name 操作
for (auto dom_succ_bb : dominators_->get_dom_tree_succ_blocks(bb)) {
re_name(dom_succ_bb);
}
// 步骤八:pop出 lval 的最新定值
for (auto &instr1 : bb->get_instructions()) {
auto instr = &instr1;
if (instr->is_store()) {
auto l_val = static_cast<StoreInst *>(instr)->get_lval();
if (!IS_GLOBAL_VARIABLE(l_val) && !IS_GEP_INSTR(l_val)) {
var_val_stack[l_val].pop_back();
}
} else if (instr->is_phi()) {
auto l_val = static_cast<PhiInst *>(instr)->get_lval();
if (var_val_stack.find(l_val) != var_val_stack.end()) {
var_val_stack[l_val].pop_back();
}
}
}
// 清除冗余的指令
for (auto instr : wait_delete) {
bb->erase_instr(instr);
}
}
void Mem2Reg::remove_alloca() {
for (auto &bb1 : func_->get_basic_blocks()) {
auto bb = &bb1;
std::vector<Instruction *> wait_delete;
for (auto &instr1 : bb->get_instructions()) {
auto instr = &instr1;
auto is_alloca = dynamic_cast<AllocaInst *>(instr);
if (is_alloca) {
bool is_int = is_alloca->get_type()->get_pointer_element_type()->is_integer_type();
bool is_float = is_alloca->get_type()->get_pointer_element_type()->is_float_type();
if (is_int || is_float) {
wait_delete.push_back(instr);
}
}
}
for (auto instr : wait_delete) {
bb->erase_instr(instr);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment