diff --git a/furc/include/furc/front/ssa.hpp b/furc/include/furc/front/ssa.hpp index 088c602..76299a7 100644 --- a/furc/include/furc/front/ssa.hpp +++ b/furc/include/furc/front/ssa.hpp @@ -22,6 +22,8 @@ private: static void constant_propagation(const std::unique_ptr& func); + static void dead_code_elimination(const std::unique_ptr& func); + static void dfs_rpo(furlang::ir::block_index block, const block_map_t& successors, std::unordered_set& visited, diff --git a/furc/src/front/ssa.cpp b/furc/src/front/ssa.cpp index 544e8fd..809cc5d 100644 --- a/furc/src/front/ssa.cpp +++ b/furc/src/front/ssa.cpp @@ -20,6 +20,7 @@ void ssa::optimize(furlang::ir::module& mod) { for (const auto& func : mod.functions()) { ssa::optimize(func); ssa::constant_propagation(func); + ssa::dead_code_elimination(func); } } @@ -481,6 +482,58 @@ void ssa::constant_propagation(const std::unique_ptr& fun } } +void ssa::dead_code_elimination(const std::unique_ptr& func) { + using block_idx = furlang::ir::block_index; + using reg_t = furlang::ir::register_operand; + + std::unordered_map defMap; + std::unordered_set alive; + std::queue worklist; + + for (block_idx blockIdx = 0; blockIdx < func->blocks().size(); ++blockIdx) { + const auto& block = func->blocks()[blockIdx]; + + for (auto& instr : block->instructions()) { + if (instr->has_destination() && instr->destination().type() == furlang::ir::operand_t::Register) { + defMap[instr->destination().reg()] = instr.get(); + } + } + + auto* exit = block->exit().get(); + alive.insert(exit); + worklist.push(exit); + } + + while (!worklist.empty()) { + const auto* instr = worklist.front(); + worklist.pop(); + + for (const auto& op : instr->sources()) { + if (op->type() != furlang::ir::operand_t::Register) continue; + auto src = op->reg(); + + if (defMap.find(src) == defMap.end()) continue; + auto* defInstr = defMap[src]; + if (alive.insert(defInstr).second) { + worklist.push(defInstr); + } + } + } + + for (block_idx blockIdx = 0; blockIdx < func->blocks().size(); ++blockIdx) { + const auto& block = func->blocks()[blockIdx]; + auto& instrs = block->instructions(); + + for (auto it = instrs.begin(); it != instrs.end();) { + if (alive.find(it->get()) == alive.end()) { + it = instrs.erase(it); + } else { + ++it; + } + } + } +} + void ssa::dfs_rpo(furlang::ir::block_index block, const block_map_t& successors, std::unordered_set& visited, diff --git a/furlang/include/furlang/ir/instruction.hpp b/furlang/include/furlang/ir/instruction.hpp index 9b4260c..4517e09 100644 --- a/furlang/include/furlang/ir/instruction.hpp +++ b/furlang/include/furlang/ir/instruction.hpp @@ -574,6 +574,8 @@ public: */ instruction_t type() const override { return instruction_t::Phi; } + bool has_destination() const override { return true; } + /** * @brief Returns this instruction's destination register. * @@ -588,6 +590,14 @@ public: */ const operand& destination() const override { return m_dst; } + std::vector sources() const override { + std::vector srcs; + srcs.reserve(m_labels.size()); + for (const auto& [op, _block] : m_labels) + srcs.push_back(&op); + return srcs; + } + /** * @brief Returns this instruction's labels. *