diff --git a/.vscode/launch.json b/.vscode/launch.json index 2ce020e..b836c38 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "program": "${workspaceFolder}/build/sysy", // "args": ["../sysytests/functional_2021/069_greatest_common_divisor.sy", "-S", "-o", "build/my.s", "-O1", "-emit-llvm"], // "args" : ["-S", "../sysytests/functional_2022/21_if_test2.sy", "-o", "build/dbg.s", "-emit-llvm", "-O1",], - "args" : ["-S", "../sysytests/functional_h_2022/04_break_continue.sy", "-o", "build/dbg.s", "-emit-llvm", "-O1",], + "args" : ["-S", "../sysytests/functional_h_2022/29_long_line.sy", "-o", "build/dbg.s", "-emit-llvm", "-O1",], "cwd": "${workspaceFolder}" }, ] diff --git a/include/mc_pass.h b/include/mc_pass.h index bf0237d..7e120d3 100644 --- a/include/mc_pass.h +++ b/include/mc_pass.h @@ -76,4 +76,10 @@ private: std::set active_moves; }; +class PassPeepHole final : public MCPass { +public: + PassPeepHole() : MCPass("peep hole") {} + void run(const MCModule &module) override; +}; + } // namespace CompSysY \ No newline at end of file diff --git a/src/algo_dominance.cpp b/src/algo_dominance.cpp index dd5d137..4cc5b5c 100644 --- a/src/algo_dominance.cpp +++ b/src/algo_dominance.cpp @@ -250,13 +250,14 @@ void CFG::calculate() { // node->dom = tmp; // } for (auto it = node->dom.begin(); it != node->dom.end();) { - auto *x = *it; + auto *x = *it; auto check = [x](CFGNode *p) { return !INSET(p->dom, x); }; if (x != node && std::any_of(BEGINEND(node->pred_list), check)) { changed = true; it = node->dom.erase(it); } - else ++it; + else + ++it; } } } diff --git a/src/main.cpp b/src/main.cpp index 4b1ee4b..d93637d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -147,7 +147,10 @@ int main(int argc, const char **argv) { mc_module.MC2ASM(ofs_virt_asm_file, true); ofs_virt_asm_file.close(); - std::vector mc_passes = {std::make_shared()}; + std::vector mc_passes = { + std::make_shared(), + std::make_shared(), + }; for (auto pass : mc_passes) { pass->run(mc_module); } diff --git a/src/pass_dce.cpp b/src/pass_dce.cpp index 400d95f..853c313 100644 --- a/src/pass_dce.cpp +++ b/src/pass_dce.cpp @@ -45,6 +45,7 @@ void remove_block(sptr(BasicBlock) victim) { // 高级编译器18.1 bool Elim_Unreach_Code(Function *func) { + LOG(INFO) << "[DCE] Unreachable code elim"; bool again = true; bool changed = false; std::unordered_set reachable; @@ -69,6 +70,7 @@ bool Elim_Unreach_Code(Function *func) { // procedures From Efficiently Computing SSA Form and the Control Dependence Graph, Zadeck 1991 // comp 512 Lecture10 gives a clear description bool Elim_Dead_Code(Function *func) { + LOG(INFO) << "[DCE] Dead code elim"; CFG RCFG; RCFG.build_from_func(func, true); RCFG.calculate(); @@ -94,10 +96,10 @@ bool Elim_Dead_Code(Function *func) { while (!worklist.empty()) { auto inst = *worklist.begin(); worklist.erase(worklist.begin()); - if (auto inst_phi = dynamic_cast(inst)) { + if (auto inst_phi = dynamic_cast(inst)) { for (auto pred : inst->parent_bb->pred_list) { if (!mark[pred->inst_list.back().get()]) { - mark[pred->inst_list.back().get()]= true; + mark[pred->inst_list.back().get()] = true; worklist.insert(pred->inst_list.back().get()); } } @@ -168,10 +170,10 @@ bool Elim_Dead_Code(Function *func) { return changed; } -static std::vector post_order; -static std::unordered_set visit; +static std::vector post_order; +static std::unordered_set visit; -static void get_post_order(BasicBlock* rt) { +static void get_post_order(BasicBlock *rt) { visit.insert(rt); for (auto succ : rt->succ_list) { if (!INSET(visit, succ.get())) { @@ -181,14 +183,12 @@ static void get_post_order(BasicBlock* rt) { post_order.push_back(rt); } - - // 高级编译器18.2, comp512 Lecture10 gives a clearer version bool Fuse_Block(Function *func) { - auto is_branch = [](Instruction* inst) { - return dynamic_cast(inst) && inst->operand_list.size() == 3; - }; - visit.clear(); post_order.clear(); + LOG(INFO) << "[DCE] Branch merge"; + auto is_branch = [](Instruction *inst) { return dynamic_cast(inst) && inst->operand_list.size() == 3; }; + visit.clear(); + post_order.clear(); get_post_order(func->bb_list.front().get()); for (auto bb : post_order) { if (is_branch(bb->inst_list.back().get())) { @@ -205,10 +205,11 @@ bool Fuse_Block(Function *func) { bb->succ_list.push_back(target); } } - else if (auto inst = dynamic_cast(bb->inst_list.back().get())) { + else if (auto inst = dynamic_cast(bb->inst_list.back().get())) { auto target = shared_cast(inst->operand_list[0]); assert(target); - // branch has side-effect on phi nodes, dealing with that is beyond this shabby compiler's capability, thus simply ignore + // branch has side-effect on phi nodes, dealing with that is beyond this shabby compiler's capability, thus simply + // ignore if (shared_cast(target->inst_list.front())) continue; if (bb->inst_list.size() == 1) { /* bb_i -> bb_j @@ -233,10 +234,10 @@ bool Fuse_Block(Function *func) { for (auto pred : bb->pred_list) { // find the pos of bb in pred's succlist, and replace with target, in-place auto itr = STD_FIND(pred->succ_list, *bb->itr); - *itr = target; + *itr = target; // remember to rewrite pred's jump/branch auto op_itr = STD_FIND(pred->inst_list.back()->operand_list, *bb->itr); - *op_itr = target; + *op_itr = target; // for target, there's no need to keep this in-place, we delete it and push new target->pred_list.push_back(pred); } @@ -259,7 +260,7 @@ bool Fuse_Block(Function *func) { for (auto succ : target->succ_list) { bb->succ_list.push_back(succ); auto itr = STD_FIND(succ->pred_list, target); - *itr = *bb->itr; + *itr = *bb->itr; } // remove bb_i's last jump bb->inst_list.back()->u_remove_from_usees(); @@ -281,10 +282,10 @@ bool Fuse_Block(Function *func) { /* clear some strange pattern */ -static void other_clear(Function* func) { +static void other_clear(Function *func) { for (auto bb : func->bb_list) { - for (auto itr = bb->inst_list.begin(); itr != bb->inst_list.end(); ) { - auto inst = *itr ++; + for (auto itr = bb->inst_list.begin(); itr != bb->inst_list.end();) { + auto inst = *itr++; if (shared_cast(inst)) { if (inst->operand_list.size() == 1) { LOG(DEBUG) << "remove trivial phi"; @@ -300,7 +301,7 @@ static void other_clear(Function* func) { void PassDCE::run(const Module &module) { LOG(INFO) << "Run pass " << pass_name; for (auto func : module.function_list) { - if (func->is_libfunc()) continue; + if (func->is_libfunc()) continue; Elim_Dead_Code(func.get()); Elim_Unreach_Code(func.get()); other_clear(func.get()); diff --git a/src/pass_peephole.cpp b/src/pass_peephole.cpp new file mode 100644 index 0000000..aa52bd2 --- /dev/null +++ b/src/pass_peephole.cpp @@ -0,0 +1,112 @@ +#include "mc_pass.h" + +namespace CompSysY { + +static void peephole(MFunction *func) { + auto check_mv_ident = [](MInstMove *inst) { + if (inst->dst.is_reg() && inst->src.is_reg()) { + if (inst->dst.value == inst->src.value) { + return true; + } + } + return false; + }; + auto check_mv_dup = [](MInstMove *inst1, MInstMove *inst2) { + if (inst1->dst.value == inst2->dst.value) { + if (inst1->src.is_reg() && inst2->src.is_reg()) { + // for regs, tags may differ + return inst1->src.value == inst2->src.value; + } + // for imm and glob, compare their tag and value + return inst1->src == inst2->src; + } + return false; + }; + auto check_useless_bin = [](MInstBinary *inst) { + if (!inst->op2.is_imm()) return false; + if (inst->op1 != inst->dst) return false; + switch (inst->inst_tag) { + case MInstTag::Add: return inst->op2.value == 0; + case MInstTag::Sub: return inst->op2.value == 0; + case MInstTag::Lsh: return inst->op2.value == 0; + case MInstTag::Rsh: return inst->op2.value == 0; + default: break; + } + return false; + }; + auto check_trivial_jmp = [](MInstJump *inst) { + // jump to the next block + auto next_bb = std::next(inst->parent_bb->itr); + if (next_bb != inst->parent_bb->parent_func->bb_list.end()) { + if (inst->target == *next_bb) { + return true; + } + } + return false; + }; + auto check_useless_ld = [](MInstLoad *inst_ld, MInstStore *inst_st) { + // load from the same addr after a store can be converted into a mov + if (inst_ld->addr.value == inst_st->addr.value) { + if (inst_ld->offset == inst_st->offset) { + return true; + } + } + return false; + }; + for (auto bb : func->bb_list) { + for (auto itr = bb->inst_list.begin(); itr != bb->inst_list.end();) { + auto inst = *itr++; + if (auto inst_mv = shared_cast(inst)) { + if (check_mv_ident(inst_mv.get())) { + bb->inst_list.erase(inst->itr); + continue; + } + auto next_inst_itr = std::next(inst->itr); + if (next_inst_itr != bb->inst_list.end()) { + if (auto inst_mv2 = shared_cast(*next_inst_itr)) { + if (check_mv_dup(inst_mv.get(), inst_mv2.get())) { + bb->inst_list.erase(inst->itr); + VLOG(6) << "[PeepHole] remove duplicate move"; + } + } + } + } + else if (auto inst_bin = shared_cast(inst)) { + if (check_useless_bin(inst_bin.get())) { + bb->inst_list.erase(inst->itr); + VLOG(6) << "[PeepHole] remove identical binary"; + } + } + else if (auto inst_jmp = shared_cast(inst)) { + if (check_trivial_jmp(inst_jmp.get())) { + bb->inst_list.erase(inst->itr); + VLOG(6) << "[PeepHole] remove trivial jump"; + } + } + else if (auto inst_ld = shared_cast(inst)) { + if (inst_ld->itr == bb->inst_list.begin()) continue; + auto prev_inst = std::prev(inst->itr); + if (auto inst_st = shared_cast(*prev_inst)) { + if (check_useless_ld(inst_ld.get(), inst_st.get())) { + assert(inst_ld->dst.is_reg() && inst_st->data.is_reg()); + if (inst_ld->dst.value != inst_st->data.value) { + auto inst_mv = MInstMove::New(inst_ld, InsertPos::Before); + inst_mv->dst = inst_ld->dst; + inst_mv->src = inst_st->data; + } + bb->inst_list.erase(inst_ld->itr); + VLOG(6) << "[PeepHole] remove trivial load after store"; + } + } + } + } + } +} + +void PassPeepHole::run(const MCModule &module) { + for (auto func : module.function_list) { + peephole(func.get()); + } +} + +} // namespace CompSysY \ No newline at end of file