diff --git a/furc/src/middle/ssa.cpp b/furc/src/middle/ssa.cpp index 96dc994..bd5999d 100644 --- a/furc/src/middle/ssa.cpp +++ b/furc/src/middle/ssa.cpp @@ -31,6 +31,10 @@ struct block_info { std::unordered_set df; }; +struct register_info { + std::unordered_set sites; // Definition Sites +}; + void rpo_dfs(std::unordered_set& visited, std::vector& order, std::size_t block, @@ -65,28 +69,43 @@ std::size_t intersect(std::vector& blocks, std::size_t b1, std::size } void process_function(ir_function& func) { - std::vector blocks(func.blocks.size()); + std::vector blocks(func.blocks.size()); + std::vector registers(func.regCount); + + std::unordered_set nonLocals; // 1. Compute CFG for (std::size_t i = 0; i < func.blocks.size(); ++i) { const auto& block = func.blocks[i]; 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(); switch (termInstr.type) { case ir_instruction::Branch: { - const auto& src = termInstr.sources.front(); - if (src.type != ir_operand::Block) throw std::runtime_error("invalid operand"); - blocks[src.value.block].preds.insert(i); - blocks[i].sucs.insert(src.value.block); + const auto& dst = termInstr.destination.value(); + if (dst.type != ir_operand::Block) throw std::runtime_error("invalid operand"); + blocks[dst.value.block].preds.insert(i); + blocks[i].sucs.insert(dst.value.block); } break; case ir_instruction::BranchCond: { - const auto& src = termInstr.sources.front(); - if (src.type != ir_operand::Block) throw std::runtime_error("invalid operand"); - blocks[src.value.blockPair.first].preds.insert(i); - blocks[src.value.blockPair.second].preds.insert(i); - blocks[i].preds.insert(src.value.blockPair.first); - blocks[i].preds.insert(src.value.blockPair.second); + const auto& dst = termInstr.destination.value(); + if (dst.type != ir_operand::BlockPair) throw std::runtime_error("invalid operand"); + blocks[dst.value.blockPair.first].preds.insert(i); + blocks[dst.value.blockPair.second].preds.insert(i); + blocks[i].preds.insert(dst.value.blockPair.first); + blocks[i].preds.insert(dst.value.blockPair.second); } break; default: break; } @@ -131,6 +150,36 @@ void process_function(ir_function& func) { } } } + + // 4. Inserting Phi-nodes (Semi-Pruned SSA form) + std::vector 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 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