76 lines
1.8 KiB
C++
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
|