// CFG 简化: // - 删除不可达块、合并空块、简化分支等 // - 改善 IR 结构,便于后续优化与后端生成 #include "ir/IR.h" #include #include #include #include namespace ir { namespace { // 从入口块开始进行 BFS/DFS,标记所有可达的基本块 std::unordered_set FindReachableBlocks(Function* func) { std::unordered_set reachable; std::vector worklist; auto* entry = func->GetEntry(); if (!entry) return reachable; reachable.insert(entry); worklist.push_back(entry); while (!worklist.empty()) { auto* bb = worklist.back(); worklist.pop_back(); // 遍历该块的所有后继块 for (const auto& inst_ptr : bb->GetInstructions()) { auto* inst = inst_ptr.get(); // 无条件分支:跳转到目标块 if (auto* br = dynamic_cast(inst)) { auto* target = br->GetTarget(); if (reachable.insert(target).second) { worklist.push_back(target); } } // 条件分支:跳转到 true 和 false 目标 else if (auto* condbr = dynamic_cast(inst)) { auto* true_target = condbr->GetTrueTarget(); auto* false_target = condbr->GetFalseTarget(); if (reachable.insert(true_target).second) { worklist.push_back(true_target); } if (reachable.insert(false_target).second) { worklist.push_back(false_target); } } // 终止指令,没有后继 if (inst->IsTerminator()) break; } } return reachable; } // 获取基本块的 terminator 指令 Instruction* GetTerminator(BasicBlock* bb) { const auto& insts = bb->GetInstructions(); if (insts.empty()) return nullptr; return insts.back().get(); } } // namespace void RunCFGSimplify(Module& module) { for (auto& func_ptr : module.GetFunctions()) { auto* func = func_ptr.get(); if (func->IsExternal()) continue; auto& blocks = const_cast>&>(func->GetBlocks()); bool changed = true; while (changed) { changed = false; auto reachable = FindReachableBlocks(func); std::unordered_set unreachable; for (auto& bb : blocks) { if (reachable.find(bb.get()) == reachable.end()) { unreachable.insert(bb.get()); } } for (auto& bb_ptr : blocks) { auto* bb = bb_ptr.get(); if (unreachable.find(bb) != unreachable.end()) continue; std::vector> phi_replacements; std::vector phi_to_delete; for (auto& inst_ptr : bb->GetInstructions()) { auto* phi = dynamic_cast(inst_ptr.get()); if (!phi) break; Value* valid_val = nullptr; size_t valid_count = 0; for (size_t i = 0; i < phi->GetNumOperands(); i += 2) { auto* val = phi->GetOperand(i); auto* pred = static_cast(phi->GetOperand(i + 1)); if (unreachable.find(pred) == unreachable.end()) { valid_val = val; valid_count++; } } if (valid_count == 1 && valid_val) { phi_replacements.push_back({phi, valid_val}); } else if (valid_count == 0) { phi_to_delete.push_back(phi); } } for (auto& [phi, val] : phi_replacements) { phi->ReplaceAllUsesWith(val); phi_to_delete.push_back(phi); } for (auto* phi : phi_to_delete) { for (size_t i = 0; i < phi->GetNumOperands(); ++i) { if (auto* op = phi->GetOperand(i)) { op->RemoveUse(phi, i); } } } auto& insts = const_cast>&>(bb->GetInstructions()); auto new_end = std::remove_if(insts.begin(), insts.end(), [&phi_to_delete](const std::unique_ptr& inst_ptr) { return std::find(phi_to_delete.begin(), phi_to_delete.end(), inst_ptr.get()) != phi_to_delete.end(); } ); insts.erase(new_end, insts.end()); } for (auto& bb_ptr : blocks) { if (unreachable.find(bb_ptr.get()) != unreachable.end()) { for (auto& inst_ptr : bb_ptr->GetInstructions()) { auto* inst = inst_ptr.get(); for (size_t i = 0; i < inst->GetNumOperands(); ++i) { if (auto* op = inst->GetOperand(i)) { op->RemoveUse(inst, i); } } } } } size_t old_size = blocks.size(); blocks.erase( std::remove_if(blocks.begin(), blocks.end(), [&reachable](const std::unique_ptr& bb_ptr) { return reachable.find(bb_ptr.get()) == reachable.end(); } ), blocks.end() ); if (blocks.size() != old_size) { changed = true; } for (auto& bb_ptr : blocks) { auto* bb = bb_ptr.get(); auto* term = GetTerminator(bb); if (!term) continue; if (auto* condbr = dynamic_cast(term)) { auto* cond = condbr->GetCond(); if (auto* const_int = dynamic_cast(cond)) { auto* true_target = condbr->GetTrueTarget(); auto* false_target = condbr->GetFalseTarget(); auto* target = (const_int->GetValue() != 0) ? true_target : false_target; bb->RemoveInstruction(condbr); bb->Append(Type::GetVoidType(), target); changed = true; } } } } for (auto& bb_ptr : blocks) { auto* bb = bb_ptr.get(); const auto& preds = bb->GetPredecessors(); if (preds.size() == 1) { std::vector> phi_replacements; for (auto& inst_ptr : bb->GetInstructions()) { auto* phi = dynamic_cast(inst_ptr.get()); if (!phi) break; if (phi->GetNumOperands() >= 2) { Value* incoming_val = phi->GetOperand(0); phi_replacements.push_back({phi, incoming_val}); } } for (auto& [phi, val] : phi_replacements) { phi->ReplaceAllUsesWith(val); } std::vector phis_to_clean; for (auto& inst_ptr : bb->GetInstructions()) { auto* phi = dynamic_cast(inst_ptr.get()); if (!phi) break; phis_to_clean.push_back(phi); } for (auto* phi : phis_to_clean) { for (size_t i = 0; i < phi->GetNumOperands(); ++i) { if (auto* op = phi->GetOperand(i)) { op->RemoveUse(phi, i); } } } auto& insts = const_cast>&>(bb->GetInstructions()); auto new_end = std::remove_if(insts.begin(), insts.end(), [](const std::unique_ptr& inst_ptr) { return dynamic_cast(inst_ptr.get()) != nullptr; } ); insts.erase(new_end, insts.end()); } } } } } // namespace ir