Compare commits
3 Commits
d0f3637539
...
a262014348
| Author | SHA1 | Date | |
|---|---|---|---|
|
a262014348
|
|||
|
986015bc09
|
|||
|
ac1e226b4b
|
@@ -20,8 +20,14 @@ public:
|
||||
private:
|
||||
static void optimize(const std::unique_ptr<furlang::ir::function>& func);
|
||||
|
||||
static void de_ssa(const std::unique_ptr<furlang::ir::function>& func);
|
||||
|
||||
static void constant_propagation(const std::unique_ptr<furlang::ir::function>& func);
|
||||
|
||||
static void dead_code_elimination(const std::unique_ptr<furlang::ir::function>& func);
|
||||
|
||||
static void copy_propagation(const std::unique_ptr<furlang::ir::function>& func);
|
||||
|
||||
static void dfs_rpo(furlang::ir::block_index block,
|
||||
const block_map_t& successors,
|
||||
std::unordered_set<furlang::ir::block_index>& visited,
|
||||
|
||||
@@ -20,6 +20,10 @@ 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);
|
||||
ssa::copy_propagation(func);
|
||||
ssa::dead_code_elimination(func);
|
||||
ssa::de_ssa(func);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +267,38 @@ void ssa::optimize(const std::unique_ptr<furlang::ir::function>& func) {
|
||||
renameBlock(entry);
|
||||
}
|
||||
|
||||
void ssa::de_ssa(const std::unique_ptr<furlang::ir::function>& func) {
|
||||
using namespace furlang::ir;
|
||||
|
||||
std::unordered_map<block_index, std::vector<std::unique_ptr<instruction>>> copies;
|
||||
for (block_index 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 ((*it)->type() != furlang::ir::instruction_t::Phi) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
auto& phi = dynamic_cast<phi_instruction&>(**it);
|
||||
auto dstReg = phi.destination().reg();
|
||||
for (auto& [srcOp, label] : phi.labels()) {
|
||||
copies[label].emplace_back(
|
||||
std::make_unique<assign_instruction>(std::move(srcOp), operand::new_reg(dstReg)));
|
||||
}
|
||||
it = instrs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [blockIdx, cpys] : copies) {
|
||||
if (blockIdx >= func->blocks().size()) continue;
|
||||
const auto& block = func->blocks()[blockIdx];
|
||||
auto& instrs = block->instructions();
|
||||
for (auto& copy : cpys) {
|
||||
instrs.push_back(std::move(copy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class lattice_t {
|
||||
Top,
|
||||
Constant,
|
||||
@@ -481,6 +517,111 @@ void ssa::constant_propagation(const std::unique_ptr<furlang::ir::function>& fun
|
||||
}
|
||||
}
|
||||
|
||||
void ssa::dead_code_elimination(const std::unique_ptr<furlang::ir::function>& func) {
|
||||
using block_idx = furlang::ir::block_index;
|
||||
using reg_t = furlang::ir::register_operand;
|
||||
|
||||
std::unordered_map<reg_t, furlang::ir::instruction*> defMap;
|
||||
std::unordered_set<furlang::ir::instruction*> alive;
|
||||
std::queue<furlang::ir::instruction*> 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::copy_propagation(const std::unique_ptr<furlang::ir::function>& func) {
|
||||
using block_idx = furlang::ir::block_index;
|
||||
using reg_t = furlang::ir::register_operand;
|
||||
|
||||
std::unordered_map<reg_t, reg_t> aliasMap;
|
||||
|
||||
std::function<reg_t(const reg_t&)> findRep = [&](const reg_t& reg) -> reg_t {
|
||||
auto it = aliasMap.find(reg);
|
||||
if (it == aliasMap.end()) return reg;
|
||||
reg_t act = findRep(it->second);
|
||||
aliasMap[reg] = act;
|
||||
return act;
|
||||
};
|
||||
|
||||
for (block_idx blockIdx = 0; blockIdx < func->blocks().size(); ++blockIdx) {
|
||||
const auto& block = func->blocks()[blockIdx];
|
||||
for (auto& instr : block->instructions()) {
|
||||
if (instr->type() != furlang::ir::instruction_t::Assign) continue;
|
||||
auto& srcOp = *instr->sources().front();
|
||||
if (srcOp.type() != furlang::ir::operand_t::Register ||
|
||||
instr->destination().type() != furlang::ir::operand_t::Register)
|
||||
continue;
|
||||
reg_t dstReg = instr->destination().reg();
|
||||
reg_t srcReg = srcOp.reg();
|
||||
reg_t repSrc = findRep(srcReg);
|
||||
reg_t repDst = findRep(dstReg);
|
||||
if (repSrc == repDst) continue;
|
||||
aliasMap[repDst] = repSrc;
|
||||
}
|
||||
}
|
||||
|
||||
for (block_idx blockIdx = 0; blockIdx < func->blocks().size(); ++blockIdx) {
|
||||
const auto& block = func->blocks()[blockIdx];
|
||||
for (auto& instr : block->instructions()) {
|
||||
for (auto& op : instr->sources()) {
|
||||
if (op->type() != furlang::ir::operand_t::Register) continue;
|
||||
op->reg() = findRep(op->reg());
|
||||
}
|
||||
if (instr->type() != furlang::ir::instruction_t::Phi) continue;
|
||||
auto& phi = dynamic_cast<furlang::ir::phi_instruction&>(*instr);
|
||||
for (auto& [op, label] : phi.labels()) {
|
||||
if (op.type() != furlang::ir::operand_t::Register) continue;
|
||||
op.reg() = findRep(op.reg());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& op : block->exit()->sources()) {
|
||||
if (op->type() != furlang::ir::operand_t::Register) continue;
|
||||
op->reg() = findRep(op->reg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ssa::dfs_rpo(furlang::ir::block_index block,
|
||||
const block_map_t& successors,
|
||||
std::unordered_set<furlang::ir::block_index>& visited,
|
||||
|
||||
@@ -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<const operand*> sources() const override {
|
||||
std::vector<const operand*> 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.
|
||||
*
|
||||
|
||||
@@ -29,9 +29,11 @@ using register_t = std::uint32_t;
|
||||
* @see operand_t::Register
|
||||
*/
|
||||
struct register_operand {
|
||||
register_t reg;
|
||||
register_t reg = 0;
|
||||
std::uint32_t ver = 0;
|
||||
|
||||
register_operand() = default;
|
||||
|
||||
register_operand(register_t reg)
|
||||
: reg(reg) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user