+68
-3
@@ -1,9 +1,11 @@
|
|||||||
#include "furc/front/ssa.hpp"
|
#include "furc/front/ssa.hpp"
|
||||||
|
|
||||||
#include "furlang/ir/instruction.hpp"
|
#include "furlang/ir/instruction.hpp"
|
||||||
|
#include "furlang/ir/operand.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -20,19 +22,46 @@ void ssa::optimize(const std::unique_ptr<furlang::ir::function>& func) {
|
|||||||
block_map_t predecessors;
|
block_map_t predecessors;
|
||||||
block_map_t successors;
|
block_map_t successors;
|
||||||
|
|
||||||
|
std::unordered_map<furlang::ir::register_operand, std::unordered_set<furlang::ir::block_index>> regSites;
|
||||||
|
std::unordered_map<furlang::ir::block_index, std::unordered_set<furlang::ir::register_operand>> regUses;
|
||||||
|
|
||||||
std::unordered_map<furlang::ir::block_index, furlang::ir::block_index> idoms;
|
std::unordered_map<furlang::ir::block_index, furlang::ir::block_index> idoms;
|
||||||
|
|
||||||
for (furlang::ir::block_index i = 0; i < func->blocks().size(); ++i) {
|
for (furlang::ir::block_index i = 0; i < func->blocks().size(); ++i) {
|
||||||
const auto& block = func->blocks()[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<const furlang::ir::assign_instruction&>(*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<const furlang::ir::binary_op_instruction&>(*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()) {
|
switch (exit->type()) {
|
||||||
case furlang::ir::instruction_t::Branch: {
|
case furlang::ir::instruction_t::Branch: {
|
||||||
const auto& br = reinterpret_cast<const furlang::ir::branch_instruction&>(*exit);
|
const auto& br = dynamic_cast<const furlang::ir::branch_instruction&>(*exit);
|
||||||
predecessors[br.block()].push_back(i);
|
predecessors[br.block()].push_back(i);
|
||||||
successors[i].push_back(br.block());
|
successors[i].push_back(br.block());
|
||||||
} break;
|
} break;
|
||||||
case furlang::ir::instruction_t::BranchCond: {
|
case furlang::ir::instruction_t::BranchCond: {
|
||||||
const auto& br = reinterpret_cast<const furlang::ir::branch_cond_instruction&>(*exit);
|
const auto& br = dynamic_cast<const furlang::ir::branch_cond_instruction&>(*exit);
|
||||||
predecessors[br.if_block()].push_back(i);
|
predecessors[br.if_block()].push_back(i);
|
||||||
predecessors[br.else_block()].push_back(i);
|
predecessors[br.else_block()].push_back(i);
|
||||||
successors[i].push_back(br.if_block());
|
successors[i].push_back(br.if_block());
|
||||||
@@ -109,6 +138,42 @@ void ssa::optimize(const std::unique_ptr<furlang::ir::function>& func) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_map<furlang::ir::block_index, std::unordered_set<furlang::ir::register_operand>> phis;
|
||||||
|
|
||||||
|
for (const auto& [reg, blocks] : regSites) {
|
||||||
|
std::vector<furlang::ir::block_index> worklist(blocks.begin(), blocks.end());
|
||||||
|
|
||||||
|
std::unordered_set<furlang::ir::block_index> 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<furlang::ir::phi_instruction>(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,
|
void ssa::dfs_rpo(furlang::ir::block_index block,
|
||||||
|
|||||||
@@ -468,8 +468,8 @@ protected:
|
|||||||
*/
|
*/
|
||||||
class phi_instruction final : public instruction {
|
class phi_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
phi_instruction(std::vector<std::pair<operand, block_index>>&& labels)
|
phi_instruction(register_operand dst)
|
||||||
: m_labels(std::move(labels)) {}
|
: m_dst(dst) {}
|
||||||
|
|
||||||
~phi_instruction() override = default;
|
~phi_instruction() override = default;
|
||||||
|
|
||||||
@@ -494,6 +494,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
instruction_t type() const override { return instruction_t::Phi; }
|
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<std::pair<operand, block_index>>& labels() { return m_labels; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns this instruction's labels.
|
* @brief Returns this instruction's labels.
|
||||||
*
|
*
|
||||||
@@ -501,11 +515,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
const std::vector<std::pair<operand, block_index>>& labels() const { return m_labels; }
|
const std::vector<std::pair<operand, block_index>>& labels() const { return m_labels; }
|
||||||
private:
|
private:
|
||||||
|
register_operand m_dst;
|
||||||
std::vector<std::pair<operand, block_index>> m_labels;
|
std::vector<std::pair<operand, block_index>> m_labels;
|
||||||
protected:
|
protected:
|
||||||
std::ostream& print(std::ostream& os) const override {
|
std::ostream& print(std::ostream& os) const override {
|
||||||
os << "phi";
|
os << "phi " << m_dst << " =";
|
||||||
|
bool first = true;
|
||||||
for (const auto& pair : m_labels) {
|
for (const auto& pair : m_labels) {
|
||||||
|
if (!first) os << ',';
|
||||||
|
first = false;
|
||||||
os << ' ' << pair.second << ": " << pair.first;
|
os << ' ' << pair.second << ": " << pair.first;
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
|
|||||||
Reference in New Issue
Block a user