This commit is contained in:
ridethepig 2023-06-19 16:14:43 +08:00
parent 2ec8ff8ed5
commit 8e570f6b4d
6 changed files with 147 additions and 24 deletions

2
.vscode/launch.json vendored
View File

@ -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}"
},
]

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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";
@ -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());

112
src/pass_peephole.cpp Normal file
View 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