|
|
|
|
@ -0,0 +1,130 @@
|
|
|
|
|
// 死代码删除(DCE):
|
|
|
|
|
// - 删除无用指令与无用基本块
|
|
|
|
|
// - 通常与 CFG 简化配合使用
|
|
|
|
|
//
|
|
|
|
|
// 算法:标记 + 清扫
|
|
|
|
|
// 1. 标记所有有副作用的指令为"有用"(ret, br, condbr, store, call)
|
|
|
|
|
// 2. 沿数据依赖反向传播,将有用指令依赖的定义也标记为有用
|
|
|
|
|
// 3. 删除所有未被标记的非终结指令
|
|
|
|
|
|
|
|
|
|
#include "ir/IR.h"
|
|
|
|
|
|
|
|
|
|
#include <queue>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
namespace ir {
|
|
|
|
|
namespace passes {
|
|
|
|
|
|
|
|
|
|
// 判断一条指令是否有副作用(不可随意删除)
|
|
|
|
|
static bool HasSideEffect(Instruction* inst) {
|
|
|
|
|
Opcode op = inst->GetOpcode();
|
|
|
|
|
// 终结指令、store、call 均有副作用
|
|
|
|
|
if (op == Opcode::Ret || op == Opcode::Br || op == Opcode::CondBr ||
|
|
|
|
|
op == Opcode::Store || op == Opcode::Call) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RunDCE(Function& func) {
|
|
|
|
|
if (func.IsExternal()) return false;
|
|
|
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
|
|
// 标记阶段
|
|
|
|
|
std::unordered_set<Instruction*> useful;
|
|
|
|
|
std::queue<Instruction*> worklist;
|
|
|
|
|
|
|
|
|
|
// 初始标记:所有有副作用的指令
|
|
|
|
|
for (const auto& bb : func.GetBlocks()) {
|
|
|
|
|
if (!bb) continue;
|
|
|
|
|
for (const auto& inst_ptr : bb->GetInstructions()) {
|
|
|
|
|
auto* inst = inst_ptr.get();
|
|
|
|
|
if (HasSideEffect(inst)) {
|
|
|
|
|
useful.insert(inst);
|
|
|
|
|
worklist.push(inst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 反向传播:有用指令的操作数定义也标记为有用
|
|
|
|
|
while (!worklist.empty()) {
|
|
|
|
|
auto* inst = worklist.front();
|
|
|
|
|
worklist.pop();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < inst->GetNumOperands(); ++i) {
|
|
|
|
|
auto* operand = inst->GetOperand(i);
|
|
|
|
|
if (!operand) continue;
|
|
|
|
|
auto* def_inst = dynamic_cast<Instruction*>(operand);
|
|
|
|
|
if (def_inst && !useful.count(def_inst)) {
|
|
|
|
|
useful.insert(def_inst);
|
|
|
|
|
worklist.push(def_inst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清扫阶段:删除未标记为有用的指令
|
|
|
|
|
for (const auto& bb : func.GetBlocks()) {
|
|
|
|
|
if (!bb) continue;
|
|
|
|
|
std::vector<Instruction*> to_remove;
|
|
|
|
|
for (const auto& inst_ptr : bb->GetInstructions()) {
|
|
|
|
|
auto* inst = inst_ptr.get();
|
|
|
|
|
if (!useful.count(inst)) {
|
|
|
|
|
to_remove.push_back(inst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (auto* inst : to_remove) {
|
|
|
|
|
// 如果还有使用者,不能直接删除(用 undef/0 替换)
|
|
|
|
|
// 在标记-清扫正确的前提下,未标记的指令不应有有用的使用者
|
|
|
|
|
// 但安全起见,先检查
|
|
|
|
|
if (!inst->GetUses().empty()) {
|
|
|
|
|
// 仍有使用者 —— 跳过(可能是循环引用的 phi)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
bb->RemoveInstruction(inst);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简化版 DCE:只删除没有使用者且无副作用的指令(更安全的实现)
|
|
|
|
|
bool RunSimpleDCE(Function& func) {
|
|
|
|
|
if (func.IsExternal()) return false;
|
|
|
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
|
bool local_changed = true;
|
|
|
|
|
|
|
|
|
|
while (local_changed) {
|
|
|
|
|
local_changed = false;
|
|
|
|
|
for (const auto& bb : func.GetBlocks()) {
|
|
|
|
|
if (!bb) continue;
|
|
|
|
|
std::vector<Instruction*> to_remove;
|
|
|
|
|
|
|
|
|
|
for (const auto& inst_ptr : bb->GetInstructions()) {
|
|
|
|
|
auto* inst = inst_ptr.get();
|
|
|
|
|
// 跳过有副作用的指令
|
|
|
|
|
if (HasSideEffect(inst)) continue;
|
|
|
|
|
// 跳过 alloca(可能后续还会用到)
|
|
|
|
|
if (inst->GetOpcode() == Opcode::Alloca) continue;
|
|
|
|
|
// 如果没有使用者,可以安全删除
|
|
|
|
|
if (inst->GetUses().empty()) {
|
|
|
|
|
to_remove.push_back(inst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto* inst : to_remove) {
|
|
|
|
|
bb->RemoveInstruction(inst);
|
|
|
|
|
local_changed = true;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace passes
|
|
|
|
|
} // namespace ir
|