peephole
This commit is contained in:
parent
2ec8ff8ed5
commit
8e570f6b4d
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -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}"
|
||||
},
|
||||
]
|
||||
|
||||
@ -76,4 +76,10 @@ private:
|
||||
std::set<MInstMove *, MvCmp> active_moves;
|
||||
};
|
||||
|
||||
class PassPeepHole final : public MCPass {
|
||||
public:
|
||||
PassPeepHole() : MCPass("peep hole") {}
|
||||
void run(const MCModule &module) override;
|
||||
};
|
||||
|
||||
} // namespace CompSysY
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<sptr(MCPass)> mc_passes = {std::make_shared<PassRegAlloc>()};
|
||||
std::vector<sptr(MCPass)> mc_passes = {
|
||||
std::make_shared<PassRegAlloc>(),
|
||||
std::make_shared<PassPeepHole>(),
|
||||
};
|
||||
for (auto pass : mc_passes) {
|
||||
pass->run(mc_module);
|
||||
}
|
||||
|
||||
@ -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<BasicBlock *> 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<InstPhi*>(inst)) {
|
||||
if (auto inst_phi = dynamic_cast<InstPhi *>(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<BasicBlock*> post_order;
|
||||
static std::unordered_set<BasicBlock*> visit;
|
||||
static std::vector<BasicBlock *> post_order;
|
||||
static std::unordered_set<BasicBlock *> 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<InstBranch*>(inst) && inst->operand_list.size() == 3;
|
||||
};
|
||||
visit.clear(); post_order.clear();
|
||||
LOG(INFO) << "[DCE] Branch merge";
|
||||
auto is_branch = [](Instruction *inst) { return dynamic_cast<InstBranch *>(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<InstBranch*>(bb->inst_list.back().get())) {
|
||||
else if (auto inst = dynamic_cast<InstBranch *>(bb->inst_list.back().get())) {
|
||||
auto target = shared_cast<BasicBlock>(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<InstPhi>(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<InstPhi>(inst)) {
|
||||
if (inst->operand_list.size() == 1) {
|
||||
LOG(DEBUG) << "remove trivial phi";
|
||||
|
||||
112
src/pass_peephole.cpp
Normal file
112
src/pass_peephole.cpp
Normal file
@ -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<MInstMove>(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<MInstMove>(*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<MInstBinary>(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<MInstJump>(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<MInstLoad>(inst)) {
|
||||
if (inst_ld->itr == bb->inst_list.begin()) continue;
|
||||
auto prev_inst = std::prev(inst->itr);
|
||||
if (auto inst_st = shared_cast<MInstStore>(*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
|
||||
Loading…
Reference in New Issue
Block a user