Files
nudt-compiler-cpp/src/ir/passes/DCE.cpp

76 lines
1.8 KiB
C++

#include "ir/PassManager.h"
#include <iostream>
#include <unordered_set>
#include <queue>
#include <vector>
namespace ir {
bool RunDCE(Function* func) {
std::unordered_set<Instruction*> live_instructions;
std::queue<Instruction*> worklist;
// 1. Mark inherently live instructions
for (const auto& bbPtr : func->GetBlocks()) {
for (const auto& instPtr : bbPtr->GetInstructions()) {
auto* inst = instPtr.get();
bool inherently_live = false;
switch (inst->GetOpcode()) {
case Opcode::Ret:
case Opcode::Br:
case Opcode::Store:
case Opcode::Call:
inherently_live = true;
break;
default:
break;
}
if (inherently_live) {
live_instructions.insert(inst);
worklist.push(inst);
}
}
}
// 2. Propagate liveness along the def-use chains
while (!worklist.empty()) {
auto* inst = worklist.front();
worklist.pop();
for (size_t i = 0; i < inst->GetNumOperands(); ++i) {
auto* operand = inst->GetOperand(i);
if (auto* op_inst = dynamic_cast<Instruction*>(operand)) {
if (live_instructions.find(op_inst) == live_instructions.end()) {
live_instructions.insert(op_inst);
worklist.push(op_inst);
}
}
}
}
// 3. Sweep dead instructions
bool changed = false;
for (const auto& bbPtr : func->GetBlocks()) {
std::vector<Instruction*> dead_instructions;
for (const auto& instPtr : bbPtr->GetInstructions()) {
auto* inst = instPtr.get();
if (live_instructions.find(inst) == live_instructions.end()) {
dead_instructions.push_back(inst);
}
}
if (!dead_instructions.empty()) {
changed = true;
for (auto* inst : dead_instructions) {
bbPtr->EraseInstruction(inst);
}
}
}
return changed;
}
} // namespace ir