死代码删除

mirror
mirror 1 week ago
parent 585046456a
commit fad1e8b1b9

@ -524,3 +524,10 @@ class IRBuilder {
Context& ctx_;
BasicBlock* insert_block_;
};
class IRPrinter {
public:
void Print(const Module& module, std::ostream& os);
};
} // namespace ir

@ -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
Loading…
Cancel
Save