From b4fda8d7d02c4273aa845da004bed31131c755b0 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Fri, 12 Jun 2026 12:21:52 +0200 Subject: [PATCH] feat(furc): start working on ssa optimizations Compute dominance frontiers. Refs: #2 --- furc/include/furc/front/ssa.hpp | 32 ++++++++ furc/src/front/ssa.cpp | 129 ++++++++++++++++++++++++++++++++ furc/src/main.cpp | 3 + 3 files changed, 164 insertions(+) create mode 100644 furc/include/furc/front/ssa.hpp create mode 100644 furc/src/front/ssa.cpp diff --git a/furc/include/furc/front/ssa.hpp b/furc/include/furc/front/ssa.hpp new file mode 100644 index 0000000..23c569c --- /dev/null +++ b/furc/include/furc/front/ssa.hpp @@ -0,0 +1,32 @@ +#ifndef FURC_FRONT_SSA_HPP +#define FURC_FRONT_SSA_HPP + +#include "furlang/ir/function.hpp" +#include "furlang/ir/instruction.hpp" +#include "furlang/ir/module.hpp" + +#include +#include +#include +#include + +namespace furc { +namespace front { + +class ssa { + using block_map_t = std::unordered_map>; +public: + static void optimize(furlang::ir::module& mod); +private: + static void optimize(const std::unique_ptr& func); + + static void dfs_rpo(furlang::ir::block_index block, + const block_map_t& successors, + std::unordered_set& visited, + std::vector& rpo); +}; + +} // namespace front +} // namespace furc + +#endif // FURC_FRONT_SSA_HPP diff --git a/furc/src/front/ssa.cpp b/furc/src/front/ssa.cpp new file mode 100644 index 0000000..e5a92db --- /dev/null +++ b/furc/src/front/ssa.cpp @@ -0,0 +1,129 @@ +#include "furc/front/ssa.hpp" + +#include "furlang/ir/instruction.hpp" + +#include +#include +#include +#include +#include + +namespace furc::front { + +void ssa::optimize(furlang::ir::module& mod) { + for (const auto& func : mod.functions()) { + ssa::optimize(func); + } +} + +void ssa::optimize(const std::unique_ptr& func) { + block_map_t predecessors; + block_map_t successors; + + 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(); + switch (exit->type()) { + case furlang::ir::instruction_t::Branch: { + const auto& br = reinterpret_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); + predecessors[br.if_block()].push_back(i); + predecessors[br.else_block()].push_back(i); + successors[i].push_back(br.if_block()); + successors[i].push_back(br.else_block()); + } break; + default: break; + } + } + + std::unordered_set visited; + std::vector rpoOrder; + dfs_rpo(0, successors, visited, rpoOrder); + std::reverse(rpoOrder.begin(), rpoOrder.end()); + + std::unordered_map rpoIndex; + for (std::size_t i = 0; i < rpoOrder.size(); ++i) { + rpoIndex[rpoOrder[i]] = i; + } + + auto intersect = [&](furlang::ir::block_index block1, furlang::ir::block_index block2) { + while (block1 != block2) { + while (rpoIndex[block1] > rpoIndex[block2]) { + block1 = idoms[block1]; + } + while (rpoIndex[block2] > rpoIndex[block1]) { + block2 = idoms[block2]; + } + } + return block1; + }; + + auto entry = rpoOrder.front(); + idoms[entry] = entry; + + bool changed = true; + while (changed) { + changed = false; + + for (std::size_t i = 1; i < rpoOrder.size(); ++i) { + auto block = rpoOrder[i]; + + furlang::ir::block_index newIdom = 0; + bool found = false; + for (auto pred : predecessors[block]) { + if (idoms.find(pred) == idoms.end()) continue; + if (!found) { + newIdom = pred; + found = true; + } else { + newIdom = intersect(pred, newIdom); + } + } + + if (idoms.find(block) == idoms.end() || idoms[block] != newIdom) { + idoms[block] = newIdom; + changed = true; + } + } + } + + std::unordered_map> df; + for (auto block : rpoOrder) { + df[block] = std::unordered_set{}; + } + + for (auto block : rpoOrder) { + if (predecessors[block].size() < 2) continue; + + for (auto pred : predecessors[block]) { + auto runner = pred; + while (runner != idoms[block]) { + df[runner].insert(block); + runner = idoms[runner]; + } + } + } +} + +void ssa::dfs_rpo(furlang::ir::block_index block, + const block_map_t& successors, + std::unordered_set& visited, + std::vector& rpo) { + visited.insert(block); + if (auto it = successors.find(block); it != successors.end()) { + for (auto successor : it->second) { + if (visited.find(successor) == visited.end()) { + dfs_rpo(successor, successors, visited, rpo); + } + } + } + rpo.push_back(block); +} + +} // namespace furc::front diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 265c3a3..711596e 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -3,6 +3,7 @@ #include "furc/ast/program.hpp" #include "furc/front/ir_generator.hpp" #include "furc/front/parser.hpp" +#include "furc/front/ssa.hpp" #include @@ -34,6 +35,8 @@ int main(void) { program->accept(generator); auto module = std::move(generator.move_module()); + furc::front::ssa::optimize(module); + std::cout << "Generated IR:\n"; for (const auto& function : module.functions()) { std::cout << function->name() << ":\n";