#include "ir/PassManager.h" #include #include #include #include namespace ir { bool RunDCE(Function* func) { std::unordered_set live_instructions; std::queue 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(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 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