Compare commits
5 Commits
5efcf1b9b0
...
12a131c2b8
| Author | SHA1 | Date | |
|---|---|---|---|
|
12a131c2b8
|
|||
|
5403c0e1a4
|
|||
|
a1dac8ae3f
|
|||
|
a311795915
|
|||
|
090d8ad81e
|
+2
-1
@@ -33,7 +33,8 @@ Checks: >
|
|||||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
-cppcoreguidelines-use-enum-class,
|
-cppcoreguidelines-use-enum-class,
|
||||||
-bugprone-forward-declaration-namespace,
|
-bugprone-forward-declaration-namespace,
|
||||||
-bugprone-tagged-union-member-count
|
-bugprone-tagged-union-member-count,
|
||||||
|
-bugprone-unchecked-optional-access
|
||||||
|
|
||||||
WarningsAsErrors: "*"
|
WarningsAsErrors: "*"
|
||||||
|
|
||||||
|
|||||||
@@ -304,7 +304,11 @@ struct ir_context {
|
|||||||
|
|
||||||
void terminate() { add_instr(ir_instruction::Return); }
|
void terminate() { add_instr(ir_instruction::Return); }
|
||||||
|
|
||||||
void terminate(ir_operand value) { add_instr(ir_instruction::Return, value); }
|
void terminate(ir_operand value) {
|
||||||
|
ir_instruction instr = { ir_instruction::Return };
|
||||||
|
instr.sources.emplace_back(value);
|
||||||
|
add_instr(std::move(instr));
|
||||||
|
}
|
||||||
|
|
||||||
void terminate(std::uint64_t block) { add_instr(ir_instruction::Branch, ir_operand{ ir_operand::Block, block }); }
|
void terminate(std::uint64_t block) { add_instr(ir_instruction::Branch, ir_operand{ ir_operand::Block, block }); }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "furc/front/lexer.hpp"
|
#include "furc/front/lexer.hpp"
|
||||||
#include "furc/front/parser.hpp"
|
#include "furc/front/parser.hpp"
|
||||||
#include "furc/middle/ir.hpp"
|
#include "furc/middle/ir.hpp"
|
||||||
|
#include "furc/middle/ssa.hpp"
|
||||||
#include "furlang/arena.hpp"
|
#include "furlang/arena.hpp"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
@@ -16,6 +17,7 @@ int main(void) {
|
|||||||
furc::lexer lexer = { "<AK>", content };
|
furc::lexer lexer = { "<AK>", content };
|
||||||
furc::parser parser = { std::move(lexer), arena };
|
furc::parser parser = { std::move(lexer), arena };
|
||||||
furc::ir_module irModule = furc::ir_generator::generate(parser.parse());
|
furc::ir_module irModule = furc::ir_generator::generate(parser.parse());
|
||||||
|
furc::ssa::process(irModule);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-11
@@ -26,6 +26,13 @@ struct block_info {
|
|||||||
std::unordered_set<std::size_t> preds;
|
std::unordered_set<std::size_t> preds;
|
||||||
std::unordered_set<std::size_t> sucs;
|
std::unordered_set<std::size_t> sucs;
|
||||||
std::size_t idom = 0;
|
std::size_t idom = 0;
|
||||||
|
|
||||||
|
// Dominance Frontiers
|
||||||
|
std::unordered_set<std::size_t> df;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct register_info {
|
||||||
|
std::unordered_set<std::size_t> sites; // Definition Sites
|
||||||
};
|
};
|
||||||
|
|
||||||
void rpo_dfs(std::unordered_set<std::size_t>& visited,
|
void rpo_dfs(std::unordered_set<std::size_t>& visited,
|
||||||
@@ -62,28 +69,43 @@ std::size_t intersect(std::vector<block_info>& blocks, std::size_t b1, std::size
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process_function(ir_function& func) {
|
void process_function(ir_function& func) {
|
||||||
std::vector<block_info> blocks(func.blocks.size());
|
std::vector<block_info> blocks(func.blocks.size());
|
||||||
|
std::vector<register_info> registers(func.regCount);
|
||||||
|
|
||||||
|
std::unordered_set<std::uint64_t> nonLocals;
|
||||||
|
|
||||||
// 1. Compute CFG
|
// 1. Compute CFG
|
||||||
for (std::size_t i = 0; i < func.blocks.size(); ++i) {
|
for (std::size_t i = 0; i < func.blocks.size(); ++i) {
|
||||||
const auto& block = func.blocks[i];
|
const auto& block = func.blocks[i];
|
||||||
if (block.instructions.empty()) continue;
|
if (block.instructions.empty()) continue;
|
||||||
|
|
||||||
|
for (const auto& instr : block.instructions) {
|
||||||
|
for (const auto& op : instr.sources) {
|
||||||
|
if (op.type != ir_operand::Register) continue;
|
||||||
|
const auto& reg = registers[op.value.reg.name];
|
||||||
|
if (reg.sites.find(i) != reg.sites.end()) continue;
|
||||||
|
nonLocals.insert(op.value.reg.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!instr.destination.has_value() || instr.destination->type != ir_operand::Register) continue;
|
||||||
|
registers[instr.destination->value.reg.name].sites.insert(i);
|
||||||
|
}
|
||||||
|
|
||||||
const auto& termInstr = block.instructions.back();
|
const auto& termInstr = block.instructions.back();
|
||||||
switch (termInstr.type) {
|
switch (termInstr.type) {
|
||||||
case ir_instruction::Branch: {
|
case ir_instruction::Branch: {
|
||||||
const auto& src = termInstr.sources.front();
|
const auto& dst = termInstr.destination.value();
|
||||||
if (src.type != ir_operand::Block) throw std::runtime_error("invalid operand");
|
if (dst.type != ir_operand::Block) throw std::runtime_error("invalid operand");
|
||||||
blocks[src.value.block].preds.insert(i);
|
blocks[dst.value.block].preds.insert(i);
|
||||||
blocks[i].sucs.insert(src.value.block);
|
blocks[i].sucs.insert(dst.value.block);
|
||||||
} break;
|
} break;
|
||||||
case ir_instruction::BranchCond: {
|
case ir_instruction::BranchCond: {
|
||||||
const auto& src = termInstr.sources.front();
|
const auto& dst = termInstr.destination.value();
|
||||||
if (src.type != ir_operand::Block) throw std::runtime_error("invalid operand");
|
if (dst.type != ir_operand::BlockPair) throw std::runtime_error("invalid operand");
|
||||||
blocks[src.value.blockPair.first].preds.insert(i);
|
blocks[dst.value.blockPair.first].preds.insert(i);
|
||||||
blocks[src.value.blockPair.second].preds.insert(i);
|
blocks[dst.value.blockPair.second].preds.insert(i);
|
||||||
blocks[i].preds.insert(src.value.blockPair.first);
|
blocks[i].preds.insert(dst.value.blockPair.first);
|
||||||
blocks[i].preds.insert(src.value.blockPair.second);
|
blocks[i].preds.insert(dst.value.blockPair.second);
|
||||||
} break;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -116,6 +138,48 @@ void process_function(ir_function& func) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Computing Dominance Frontiers
|
||||||
|
for (std::size_t j = 0; j < blocks.size(); ++j) {
|
||||||
|
const auto& join = blocks[j];
|
||||||
|
if (join.preds.size() < 2) continue;
|
||||||
|
for (std::size_t runner : join.preds) {
|
||||||
|
while (runner != join.idom) {
|
||||||
|
blocks[runner].df.insert(j);
|
||||||
|
runner = blocks[runner].idom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Inserting Phi-nodes (Semi-Pruned SSA form)
|
||||||
|
std::vector<std::size_t> worklist;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < registers.size(); ++i) {
|
||||||
|
const auto& reg = registers[i];
|
||||||
|
if (reg.sites.size() < 2 || nonLocals.find(i) == nonLocals.end()) continue;
|
||||||
|
|
||||||
|
worklist.insert(worklist.end(), reg.sites.begin(), reg.sites.end());
|
||||||
|
|
||||||
|
std::unordered_set<std::size_t> done;
|
||||||
|
while (!worklist.empty()) {
|
||||||
|
const auto blockIdx = worklist.back();
|
||||||
|
worklist.pop_back();
|
||||||
|
for (auto frontier : blocks[blockIdx].df) {
|
||||||
|
if (done.find(frontier) != done.end()) continue;
|
||||||
|
done.insert(frontier);
|
||||||
|
|
||||||
|
auto& target = func.blocks[frontier];
|
||||||
|
|
||||||
|
ir_instruction instr = { ir_instruction::Phi };
|
||||||
|
for (const auto& pred : blocks[frontier].preds)
|
||||||
|
instr.sources.emplace_back(ir_operand::PhiPair, i, pred);
|
||||||
|
|
||||||
|
target.instructions.emplace(target.instructions.begin(), std::move(instr));
|
||||||
|
|
||||||
|
if (reg.sites.find(frontier) == reg.sites.end()) worklist.push_back(frontier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user