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",
|
"program": "${workspaceFolder}/build/sysy",
|
||||||
// "args": ["../sysytests/functional_2021/069_greatest_common_divisor.sy", "-S", "-o", "build/my.s", "-O1", "-emit-llvm"],
|
// "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_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}"
|
"cwd": "${workspaceFolder}"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@ -76,4 +76,10 @@ private:
|
|||||||
std::set<MInstMove *, MvCmp> active_moves;
|
std::set<MInstMove *, MvCmp> active_moves;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PassPeepHole final : public MCPass {
|
||||||
|
public:
|
||||||
|
PassPeepHole() : MCPass("peep hole") {}
|
||||||
|
void run(const MCModule &module) override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace CompSysY
|
} // namespace CompSysY
|
||||||
@ -256,7 +256,8 @@ void CFG::calculate() {
|
|||||||
changed = true;
|
changed = true;
|
||||||
it = node->dom.erase(it);
|
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);
|
mc_module.MC2ASM(ofs_virt_asm_file, true);
|
||||||
ofs_virt_asm_file.close();
|
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) {
|
for (auto pass : mc_passes) {
|
||||||
pass->run(mc_module);
|
pass->run(mc_module);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,7 @@ void remove_block(sptr(BasicBlock) victim) {
|
|||||||
|
|
||||||
// 高级编译器18.1
|
// 高级编译器18.1
|
||||||
bool Elim_Unreach_Code(Function *func) {
|
bool Elim_Unreach_Code(Function *func) {
|
||||||
|
LOG(INFO) << "[DCE] Unreachable code elim";
|
||||||
bool again = true;
|
bool again = true;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
std::unordered_set<BasicBlock *> reachable;
|
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
|
// procedures From Efficiently Computing SSA Form and the Control Dependence Graph, Zadeck 1991
|
||||||
// comp 512 Lecture10 gives a clear description
|
// comp 512 Lecture10 gives a clear description
|
||||||
bool Elim_Dead_Code(Function *func) {
|
bool Elim_Dead_Code(Function *func) {
|
||||||
|
LOG(INFO) << "[DCE] Dead code elim";
|
||||||
CFG RCFG;
|
CFG RCFG;
|
||||||
RCFG.build_from_func(func, true);
|
RCFG.build_from_func(func, true);
|
||||||
RCFG.calculate();
|
RCFG.calculate();
|
||||||
@ -94,10 +96,10 @@ bool Elim_Dead_Code(Function *func) {
|
|||||||
while (!worklist.empty()) {
|
while (!worklist.empty()) {
|
||||||
auto inst = *worklist.begin();
|
auto inst = *worklist.begin();
|
||||||
worklist.erase(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) {
|
for (auto pred : inst->parent_bb->pred_list) {
|
||||||
if (!mark[pred->inst_list.back().get()]) {
|
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());
|
worklist.insert(pred->inst_list.back().get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,10 +170,10 @@ bool Elim_Dead_Code(Function *func) {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<BasicBlock*> post_order;
|
static std::vector<BasicBlock *> post_order;
|
||||||
static std::unordered_set<BasicBlock*> visit;
|
static std::unordered_set<BasicBlock *> visit;
|
||||||
|
|
||||||
static void get_post_order(BasicBlock* rt) {
|
static void get_post_order(BasicBlock *rt) {
|
||||||
visit.insert(rt);
|
visit.insert(rt);
|
||||||
for (auto succ : rt->succ_list) {
|
for (auto succ : rt->succ_list) {
|
||||||
if (!INSET(visit, succ.get())) {
|
if (!INSET(visit, succ.get())) {
|
||||||
@ -181,14 +183,12 @@ static void get_post_order(BasicBlock* rt) {
|
|||||||
post_order.push_back(rt);
|
post_order.push_back(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 高级编译器18.2, comp512 Lecture10 gives a clearer version
|
// 高级编译器18.2, comp512 Lecture10 gives a clearer version
|
||||||
bool Fuse_Block(Function *func) {
|
bool Fuse_Block(Function *func) {
|
||||||
auto is_branch = [](Instruction* inst) {
|
LOG(INFO) << "[DCE] Branch merge";
|
||||||
return dynamic_cast<InstBranch*>(inst) && inst->operand_list.size() == 3;
|
auto is_branch = [](Instruction *inst) { return dynamic_cast<InstBranch *>(inst) && inst->operand_list.size() == 3; };
|
||||||
};
|
visit.clear();
|
||||||
visit.clear(); post_order.clear();
|
post_order.clear();
|
||||||
get_post_order(func->bb_list.front().get());
|
get_post_order(func->bb_list.front().get());
|
||||||
for (auto bb : post_order) {
|
for (auto bb : post_order) {
|
||||||
if (is_branch(bb->inst_list.back().get())) {
|
if (is_branch(bb->inst_list.back().get())) {
|
||||||
@ -205,10 +205,11 @@ bool Fuse_Block(Function *func) {
|
|||||||
bb->succ_list.push_back(target);
|
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]);
|
auto target = shared_cast<BasicBlock>(inst->operand_list[0]);
|
||||||
assert(target);
|
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 (shared_cast<InstPhi>(target->inst_list.front())) continue;
|
||||||
if (bb->inst_list.size() == 1) {
|
if (bb->inst_list.size() == 1) {
|
||||||
/* bb_i -> bb_j
|
/* bb_i -> bb_j
|
||||||
@ -281,10 +282,10 @@ bool Fuse_Block(Function *func) {
|
|||||||
/*
|
/*
|
||||||
clear some strange pattern
|
clear some strange pattern
|
||||||
*/
|
*/
|
||||||
static void other_clear(Function* func) {
|
static void other_clear(Function *func) {
|
||||||
for (auto bb : func->bb_list) {
|
for (auto bb : func->bb_list) {
|
||||||
for (auto itr = bb->inst_list.begin(); itr != bb->inst_list.end(); ) {
|
for (auto itr = bb->inst_list.begin(); itr != bb->inst_list.end();) {
|
||||||
auto inst = *itr ++;
|
auto inst = *itr++;
|
||||||
if (shared_cast<InstPhi>(inst)) {
|
if (shared_cast<InstPhi>(inst)) {
|
||||||
if (inst->operand_list.size() == 1) {
|
if (inst->operand_list.size() == 1) {
|
||||||
LOG(DEBUG) << "remove trivial phi";
|
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