From 865691df264788cc6b725a078f806eb11c1d2b78 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Fri, 12 Jun 2026 13:45:35 +0200 Subject: [PATCH] feat(furc, ssa): implement phi instruction placement Refs: #2 --- furc/src/front/ssa.cpp | 71 +++++++++++++++++++++- furlang/include/furlang/ir/instruction.hpp | 24 +++++++- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/furc/src/front/ssa.cpp b/furc/src/front/ssa.cpp index e5a92db..34603ff 100644 --- a/furc/src/front/ssa.cpp +++ b/furc/src/front/ssa.cpp @@ -1,9 +1,11 @@ #include "furc/front/ssa.hpp" #include "furlang/ir/instruction.hpp" +#include "furlang/ir/operand.hpp" #include #include +#include #include #include #include @@ -20,19 +22,46 @@ void ssa::optimize(const std::unique_ptr& func) { block_map_t predecessors; block_map_t successors; + std::unordered_map> regSites; + std::unordered_map> regUses; + std::unordered_map idoms; for (furlang::ir::block_index i = 0; i < func->blocks().size(); ++i) { const auto& block = func->blocks()[i]; - const auto& exit = block->exit(); + + for (const auto& instr : block->instructions()) { + switch (instr->type()) { + case furlang::ir::instruction_t::Assign: { + const auto& assign = dynamic_cast(*instr); + regSites[assign.destination().reg()].insert(i); + if (assign.source().type() == furlang::ir::operand_t::Register) { + regUses[i].insert(assign.source().reg()); + } + } break; + case furlang::ir::instruction_t::BinaryOp: { + const auto& binOp = dynamic_cast(*instr); + regSites[binOp.dst().reg()].insert(i); + if (binOp.lhs().type() == furlang::ir::operand_t::Register) { + regUses[i].insert(binOp.lhs().reg()); + } + if (binOp.rhs().type() == furlang::ir::operand_t::Register) { + regUses[i].insert(binOp.rhs().reg()); + } + } break; + default: break; + } + } + + const auto& exit = block->exit(); switch (exit->type()) { case furlang::ir::instruction_t::Branch: { - const auto& br = reinterpret_cast(*exit); + const auto& br = dynamic_cast(*exit); predecessors[br.block()].push_back(i); successors[i].push_back(br.block()); } break; case furlang::ir::instruction_t::BranchCond: { - const auto& br = reinterpret_cast(*exit); + const auto& br = dynamic_cast(*exit); predecessors[br.if_block()].push_back(i); predecessors[br.else_block()].push_back(i); successors[i].push_back(br.if_block()); @@ -109,6 +138,42 @@ void ssa::optimize(const std::unique_ptr& func) { } } } + + std::unordered_map> phis; + + for (const auto& [reg, blocks] : regSites) { + std::vector worklist(blocks.begin(), blocks.end()); + + std::unordered_set added; + while (!worklist.empty()) { + auto block = worklist.back(); + worklist.pop_back(); + for (auto frontier : df[block]) { + if (added.find(frontier) != added.end()) continue; + phis[frontier].insert(reg); + added.insert(frontier); + if (blocks.find(frontier) == blocks.end()) { + worklist.push_back(frontier); + } + } + } + } + + for (furlang::ir::block_index i = 0; i < func->blocks().size(); ++i) { + if (phis.find(i) == phis.end()) continue; + const auto& block = func->blocks()[i]; + const auto& preds = predecessors[i]; + + for (auto reg : phis[i]) { + if (regUses[i].find(reg) == regUses[i].end()) continue; + + auto phiInstr = std::make_unique(reg); + for (auto pred : preds) { + phiInstr->labels().emplace_back(furlang::ir::operand::new_reg(reg), pred); + } + block->instructions().emplace(block->instructions().begin(), std::move(phiInstr)); + } + } } void ssa::dfs_rpo(furlang::ir::block_index block, diff --git a/furlang/include/furlang/ir/instruction.hpp b/furlang/include/furlang/ir/instruction.hpp index 94978b6..bc84926 100644 --- a/furlang/include/furlang/ir/instruction.hpp +++ b/furlang/include/furlang/ir/instruction.hpp @@ -468,8 +468,8 @@ protected: */ class phi_instruction final : public instruction { public: - phi_instruction(std::vector>&& labels) - : m_labels(std::move(labels)) {} + phi_instruction(register_operand dst) + : m_dst(dst) {} ~phi_instruction() override = default; @@ -494,6 +494,20 @@ public: */ instruction_t type() const override { return instruction_t::Phi; } + /** + * @brief Returns this instruction's destination register. + * + * @return The register. + */ + register_operand destination() const { return m_dst; } + + /** + * @brief Returns this instruction's labels. + * + * @return The labels. + */ + std::vector>& labels() { return m_labels; } + /** * @brief Returns this instruction's labels. * @@ -501,11 +515,15 @@ public: */ const std::vector>& labels() const { return m_labels; } private: + register_operand m_dst; std::vector> m_labels; protected: std::ostream& print(std::ostream& os) const override { - os << "phi"; + os << "phi " << m_dst << " ="; + bool first = true; for (const auto& pair : m_labels) { + if (!first) os << ','; + first = false; os << ' ' << pair.second << ": " << pair.first; } return os;