diff --git a/src/include/ir/IR.h b/src/include/ir/IR.h index 87a35e0e..36f33120 100644 --- a/src/include/ir/IR.h +++ b/src/include/ir/IR.h @@ -214,6 +214,8 @@ class User : public Value { Value* GetOperand(size_t index) const; void SetOperand(size_t index, Value* value); void AddOperand(Value* value); + // 清除所有操作数并注销 use 记录,用于重建 PHI 等场景。 + void ClearOperands(); private: std::vector operands_; @@ -542,4 +544,8 @@ class IRPrinter { void Print(const Module& module, std::ostream& os); }; +// IR 验证器:校验模块合法性(Debug 模式)。 +// 检查 SSA 支配性、基本块终结指令、PHI 一致性等。 +void VerifyIR(Module &module); + } // namespace ir diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp index be13b535..47ba4eca 100644 --- a/src/ir/Instruction.cpp +++ b/src/ir/Instruction.cpp @@ -47,6 +47,15 @@ void User::AddOperand(Value* value) { value->AddUse(this, operand_index); } +void User::ClearOperands() { + for (size_t i = 0; i < operands_.size(); ++i) { + if (operands_[i]) { + operands_[i]->RemoveUse(this, i); + } + } + operands_.clear(); +} + Instruction::Instruction(Opcode op, std::shared_ptr ty, std::string name) : User(std::move(ty), std::move(name)), opcode_(op) {} diff --git a/src/ir/analysis/DominatorTree.cpp b/src/ir/analysis/DominatorTree.cpp index a2301727..c9068e5d 100644 --- a/src/ir/analysis/DominatorTree.cpp +++ b/src/ir/analysis/DominatorTree.cpp @@ -1,3 +1,5 @@ +#include "ir/analysis/DominatorTree.h" + #include "ir/IR.h" #include @@ -5,313 +7,254 @@ #include #include -namespace ir -{ +namespace ir { - namespace - { +namespace { - std::unordered_map> ComputePredecessors(Function *func) - { - std::unordered_map> preds; - for (const auto &bb : func->GetBlocks()) - { - preds[bb.get()] = {}; - } - for (const auto &bb : func->GetBlocks()) - { - if (!bb->HasTerminator()) - { - continue; - } - auto *terminator = bb->GetInstructions().back().get(); - if (auto *br = dynamic_cast(terminator)) - { - preds[br->GetTarget()].push_back(bb.get()); - } - else if (auto *condbr = dynamic_cast(terminator)) - { - preds[condbr->GetTrueTarget()].push_back(bb.get()); - preds[condbr->GetFalseTarget()].push_back(bb.get()); - } - } - return preds; +std::unordered_map> ComputePredecessors( + Function* func) { + std::unordered_map> preds; + for (const auto& bb : func->GetBlocks()) { + preds[bb.get()] = {}; + } + for (const auto& bb : func->GetBlocks()) { + if (!bb->HasTerminator()) { + continue; + } + auto* terminator = bb->GetInstructions().back().get(); + if (auto* br = dynamic_cast(terminator)) { + preds[br->GetTarget()].push_back(bb.get()); + } else if (auto* condbr = dynamic_cast(terminator)) { + preds[condbr->GetTrueTarget()].push_back(bb.get()); + preds[condbr->GetFalseTarget()].push_back(bb.get()); } + } + return preds; +} - std::unordered_map> ComputeSuccessors(Function *func) - { - std::unordered_map> succs; - for (const auto &bb : func->GetBlocks()) - { - succs[bb.get()] = {}; - if (!bb->HasTerminator()) - { - continue; - } - auto *terminator = bb->GetInstructions().back().get(); - if (auto *br = dynamic_cast(terminator)) - { - succs[bb.get()].push_back(br->GetTarget()); - } - else if (auto *condbr = dynamic_cast(terminator)) - { - succs[bb.get()].push_back(condbr->GetTrueTarget()); - succs[bb.get()].push_back(condbr->GetFalseTarget()); - } - } - return succs; +std::unordered_map> ComputeSuccessors( + Function* func) { + std::unordered_map> succs; + for (const auto& bb : func->GetBlocks()) { + succs[bb.get()] = {}; + if (!bb->HasTerminator()) { + continue; } + auto* terminator = bb->GetInstructions().back().get(); + if (auto* br = dynamic_cast(terminator)) { + succs[bb.get()].push_back(br->GetTarget()); + } else if (auto* condbr = dynamic_cast(terminator)) { + succs[bb.get()].push_back(condbr->GetTrueTarget()); + succs[bb.get()].push_back(condbr->GetFalseTarget()); + } + } + return succs; +} - std::vector PostOrder(Function *func, - const std::unordered_map> &succs) - { - std::vector order; - std::unordered_set visited; - std::vector> stack; - - auto *entry = func->GetEntry(); - if (!entry) - { - return order; - } +std::vector PostOrder( + Function* func, + const std::unordered_map>& succs) { + std::vector order; + std::unordered_set visited; + std::vector> stack; - stack.push_back({entry, 0}); - visited.insert(entry); - - while (!stack.empty()) - { - auto &top = stack.back(); - auto *bb = top.first; - auto &idx = top.second; - - auto it = succs.find(bb); - const auto &children = (it != succs.end()) ? it->second : std::vector{}; - - bool found_next = false; - while (idx < children.size()) - { - auto *child = children[idx++]; - if (visited.find(child) == visited.end()) - { - visited.insert(child); - stack.push_back({child, 0}); - found_next = true; - break; - } - } + auto* entry = func->GetEntry(); + if (!entry) { + return order; + } - if (!found_next) - { - order.push_back(bb); - stack.pop_back(); - } + stack.push_back({entry, 0}); + visited.insert(entry); + + while (!stack.empty()) { + auto& top = stack.back(); + auto* bb = top.first; + auto& idx = top.second; + + auto it = succs.find(bb); + const auto& children = + (it != succs.end()) ? it->second : std::vector{}; + + bool found_next = false; + while (idx < children.size()) { + auto* child = children[idx++]; + if (visited.find(child) == visited.end()) { + visited.insert(child); + stack.push_back({child, 0}); + found_next = true; + break; } + } - return order; + if (!found_next) { + order.push_back(bb); + stack.pop_back(); } + } - std::unordered_set Intersect(const std::unordered_set &a, - const std::unordered_set &b) - { - std::unordered_set result; - for (auto *bb : a) - { - if (b.find(bb) != b.end()) - { - result.insert(bb); - } - } - return result; + return order; +} + +std::unordered_set Intersect( + const std::unordered_set& a, + const std::unordered_set& b) { + std::unordered_set result; + for (auto* bb : a) { + if (b.find(bb) != b.end()) { + result.insert(bb); } + } + return result; +} +} // namespace + +void DominatorTree::Compute(Function* func) { + doms_.clear(); + idom_.clear(); + children_.clear(); + df_.clear(); + + auto preds = ComputePredecessors(func); + auto succs = ComputeSuccessors(func); + auto post_order = PostOrder(func, succs); + + std::unordered_map post_order_idx; + for (size_t i = 0; i < post_order.size(); ++i) { + post_order_idx[post_order[i]] = i; } - class DominatorTree - { - public: - void Compute(Function *func) - { - doms_.clear(); - idom_.clear(); - children_.clear(); - df_.clear(); - - auto preds = ComputePredecessors(func); - auto succs = ComputeSuccessors(func); - auto post_order = PostOrder(func, succs); - - std::unordered_map post_order_idx; - for (size_t i = 0; i < post_order.size(); ++i) - { - post_order_idx[post_order[i]] = i; - } + auto* entry = func->GetEntry(); + if (!entry) { + return; + } - auto *entry = func->GetEntry(); - if (!entry) - { - return; - } + std::unordered_set all_blocks; + for (const auto& bb : func->GetBlocks()) { + all_blocks.insert(bb.get()); + } - std::unordered_set all_blocks; - for (const auto &bb : func->GetBlocks()) - { - all_blocks.insert(bb.get()); - } + doms_[entry] = {entry}; + for (auto* bb : post_order) { + if (bb != entry) { + doms_[bb] = all_blocks; + } + } - doms_[entry] = {entry}; - for (auto *bb : post_order) - { - if (bb != entry) - { - doms_[bb] = all_blocks; - } + bool changed = true; + while (changed) { + changed = false; + for (auto it = post_order.rbegin(); it != post_order.rend(); ++it) { + auto* bb = *it; + if (bb == entry) { + continue; } - bool changed = true; - while (changed) - { - changed = false; - for (auto it = post_order.rbegin(); it != post_order.rend(); ++it) - { - auto *bb = *it; - if (bb == entry) - { - continue; - } - - auto pred_it = preds.find(bb); - if (pred_it == preds.end() || pred_it->second.empty()) - { - continue; - } - - std::unordered_set new_dom; - bool first = true; - for (auto *pred : pred_it->second) - { - auto dom_it = doms_.find(pred); - if (dom_it == doms_.end()) - { - continue; - } - if (first) - { - new_dom = dom_it->second; - first = false; - } - else - { - new_dom = Intersect(new_dom, dom_it->second); - } - } - new_dom.insert(bb); - - if (doms_[bb] != new_dom) - { - doms_[bb] = new_dom; - changed = true; - } - } + auto pred_it = preds.find(bb); + if (pred_it == preds.end() || pred_it->second.empty()) { + continue; } - for (auto *bb : post_order) - { - if (bb == entry) - { - idom_[bb] = nullptr; + std::unordered_set new_dom; + bool first = true; + for (auto* pred : pred_it->second) { + auto dom_it = doms_.find(pred); + if (dom_it == doms_.end()) { continue; } - - auto &dom_set = doms_[bb]; - BasicBlock *idom = nullptr; - size_t min_idx = post_order.size(); - - for (auto *d : dom_set) - { - if (d == bb) - { - continue; - } - auto idx_it = post_order_idx.find(d); - if (idx_it != post_order_idx.end() && idx_it->second < min_idx) - { - min_idx = idx_it->second; - idom = d; - } + if (first) { + new_dom = dom_it->second; + first = false; + } else { + new_dom = Intersect(new_dom, dom_it->second); } + } + new_dom.insert(bb); - idom_[bb] = idom; - if (idom) - { - children_[idom].push_back(bb); - } + if (doms_[bb] != new_dom) { + doms_[bb] = new_dom; + changed = true; } + } + } - for (auto *bb : post_order) - { - if (bb == entry) - { - continue; - } + for (auto* bb : post_order) { + if (bb == entry) { + idom_[bb] = nullptr; + continue; + } - auto pred_it = preds.find(bb); - if (pred_it == preds.end()) - { - continue; - } + auto& dom_set = doms_[bb]; + BasicBlock* idom = nullptr; + size_t min_idx = post_order.size(); - for (auto *pred : pred_it->second) - { - auto *runner = pred; - while (runner && runner != idom_[bb]) - { - df_[runner].insert(bb); - runner = idom_[runner]; - } - } + for (auto* d : dom_set) { + if (d == bb) { + continue; } - } - - bool Dominates(BasicBlock *a, BasicBlock *b) const - { - auto it = doms_.find(b); - if (it == doms_.end()) - { - return false; + auto idx_it = post_order_idx.find(d); + if (idx_it != post_order_idx.end() && idx_it->second < min_idx) { + min_idx = idx_it->second; + idom = d; } - return it->second.find(a) != it->second.end(); } - BasicBlock *GetIdom(BasicBlock *bb) const - { - auto it = idom_.find(bb); - return (it != idom_.end()) ? it->second : nullptr; + idom_[bb] = idom; + if (idom) { + children_[idom].push_back(bb); } + } - const std::vector &GetChildren(BasicBlock *bb) const - { - static const std::vector empty; - auto it = children_.find(bb); - return (it != children_.end()) ? it->second : empty; + for (auto* bb : post_order) { + if (bb == entry) { + continue; } - const std::unordered_set &GetDominanceFrontier(BasicBlock *bb) const - { - static const std::unordered_set empty; - auto it = df_.find(bb); - return (it != df_.end()) ? it->second : empty; + auto pred_it = preds.find(bb); + if (pred_it == preds.end()) { + continue; } - const std::unordered_map> &GetAllDominanceFrontiers() const - { - return df_; + for (auto* pred : pred_it->second) { + auto* runner = pred; + while (runner && runner != idom_[bb]) { + df_[runner].insert(bb); + runner = idom_[runner]; + } } + } +} - private: - std::unordered_map> doms_; - std::unordered_map idom_; - std::unordered_map> children_; - std::unordered_map> df_; - }; +bool DominatorTree::Dominates(BasicBlock* a, BasicBlock* b) const { + auto it = doms_.find(b); + if (it == doms_.end()) { + return false; + } + return it->second.find(a) != it->second.end(); +} + +BasicBlock* DominatorTree::GetIdom(BasicBlock* bb) const { + auto it = idom_.find(bb); + return (it != idom_.end()) ? it->second : nullptr; +} + +const std::vector& DominatorTree::GetChildren( + BasicBlock* bb) const { + static const std::vector empty; + auto it = children_.find(bb); + return (it != children_.end()) ? it->second : empty; +} + +const std::unordered_set& DominatorTree::GetDominanceFrontier( + BasicBlock* bb) const { + static const std::unordered_set empty; + auto it = df_.find(bb); + return (it != df_.end()) ? it->second : empty; +} +const std::unordered_map>& +DominatorTree::GetAllDominanceFrontiers() const { + return df_; } + +} // namespace ir diff --git a/src/ir/analysis/DominatorTree.h b/src/ir/analysis/DominatorTree.h new file mode 100644 index 00000000..a3099788 --- /dev/null +++ b/src/ir/analysis/DominatorTree.h @@ -0,0 +1,37 @@ +// 支配树:计算函数的支配关系、直接支配者、支配边界。 +// 核心算法是迭代数据流分析,用于 IR 验证器、Mem2Reg 等 pass。 +#pragma once + +#include +#include +#include + +namespace ir { + +class BasicBlock; +class Function; + +class DominatorTree { + public: + void Compute(Function* func); + + bool Dominates(BasicBlock* a, BasicBlock* b) const; + + BasicBlock* GetIdom(BasicBlock* bb) const; + + const std::vector& GetChildren(BasicBlock* bb) const; + + const std::unordered_set& GetDominanceFrontier( + BasicBlock* bb) const; + + const std::unordered_map>& + GetAllDominanceFrontiers() const; + + private: + std::unordered_map> doms_; + std::unordered_map idom_; + std::unordered_map> children_; + std::unordered_map> df_; +}; + +} // namespace ir diff --git a/src/ir/passes/CFGSimplify.cpp b/src/ir/passes/CFGSimplify.cpp index 76fbc24c..c1277b5e 100644 --- a/src/ir/passes/CFGSimplify.cpp +++ b/src/ir/passes/CFGSimplify.cpp @@ -65,6 +65,56 @@ Instruction* GetTerminator(BasicBlock* bb) { return insts.back().get(); } +// 清理 PHI 节点中对已移除前驱的引用。 +// 当某个基本块不再跳转到 target_block 时,target_block 的 PHI 节点 +// 需要移除引用该前驱的条目。 +void CleanupPhiReferences(BasicBlock* target_block, BasicBlock* removed_pred) { + auto& insts = const_cast>&>( + target_block->GetInstructions()); + + std::vector phis_to_delete; + + for (auto& inst_ptr : insts) { + auto* phi = dynamic_cast(inst_ptr.get()); + if (!phi) break; + + // 收集保留的 (value, block) 对 + std::vector> keep_pairs; + for (size_t i = 0; i < phi->GetNumOperands(); i += 2) { + auto* val = phi->GetOperand(i); + auto* pred = static_cast(phi->GetOperand(i + 1)); + if (pred != removed_pred) { + keep_pairs.push_back({val, pred}); + } + } + + if (keep_pairs.empty()) { + phis_to_delete.push_back(phi); + } else if (keep_pairs.size() == 1) { + phi->ReplaceAllUsesWith(keep_pairs[0].first); + phis_to_delete.push_back(phi); + } else if (keep_pairs.size() * 2 != phi->GetNumOperands()) { + // 部分条目被移除:重建操作数列表 + phi->ClearOperands(); + for (auto& [val, pred] : keep_pairs) { + phi->AddOperand(val); + phi->AddOperand(pred); + } + } + } + + // 删除标记的 PHI 节点 + if (!phis_to_delete.empty()) { + auto new_end = std::remove_if( + insts.begin(), insts.end(), + [&phis_to_delete](const std::unique_ptr& inst_ptr) { + return std::find(phis_to_delete.begin(), phis_to_delete.end(), + inst_ptr.get()) != phis_to_delete.end(); + }); + insts.erase(new_end, insts.end()); + } +} + } // namespace void RunCFGSimplify(Module& module) { @@ -93,27 +143,36 @@ void RunCFGSimplify(Module& module) { 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; - + + // 收集所有可达前驱对应的 (value, block) 对 + std::vector> valid_pairs; + bool has_unreachable = false; + 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++; + valid_pairs.push_back({val, pred}); + } else { + has_unreachable = true; } } - - if (valid_count == 1 && valid_val) { - phi_replacements.push_back({phi, valid_val}); - } else if (valid_count == 0) { + + if (valid_pairs.size() == 1) { + phi_replacements.push_back({phi, valid_pairs[0].first}); + } else if (valid_pairs.empty()) { phi_to_delete.push_back(phi); + } else if (has_unreachable && valid_pairs.size() >= 2) { + // 部分前驱不可达:清理后仅保留可达条目 + phi->ClearOperands(); + for (auto& [val, pred] : valid_pairs) { + phi->AddOperand(val); + phi->AddOperand(pred); + } } } @@ -148,19 +207,23 @@ void RunCFGSimplify(Module& module) { 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; - + + auto* live_target = (const_int->GetValue() != 0) ? true_target : false_target; + auto* dead_target = (const_int->GetValue() != 0) ? false_target : true_target; + bb->RemoveInstruction(condbr); - bb->Append(Type::GetVoidType(), target); + bb->Append(Type::GetVoidType(), live_target); changed = true; + + // 清理 dead_target 的 PHI 节点中对 bb 的引用 + CleanupPhiReferences(dead_target, bb); } } } diff --git a/src/ir/passes/CMakeLists.txt b/src/ir/passes/CMakeLists.txt index d5039096..aa716f16 100644 --- a/src/ir/passes/CMakeLists.txt +++ b/src/ir/passes/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(ir_passes STATIC CSE.cpp DCE.cpp CFGSimplify.cpp + IRVerifier.cpp ) target_link_libraries(ir_passes PUBLIC diff --git a/src/ir/passes/IRVerifier.cpp b/src/ir/passes/IRVerifier.cpp new file mode 100644 index 00000000..da05b266 --- /dev/null +++ b/src/ir/passes/IRVerifier.cpp @@ -0,0 +1,214 @@ +// IR 验证器:校验 IR 模块的合法性。 +// 检查项: +// 1. SSA 支配性:每条指令的操作数(也是指令)必须由当前基本块支配 +// 2. 基本块终结指令:每个非空基本块必须以终结指令结尾 +// 3. PHI 一致性:PHI 节点操作数结构正确 +// +// 验证失败时输出错误信息并 abort(),仅在 Debug 模式下生效。 + +#include "ir/IR.h" +#include "ir/analysis/DominatorTree.h" +#include "utils/Log.h" + +#include +#include +#include +#include +#include + +namespace ir { + +namespace { + +// 收集某个基本块的前驱(基于终结指令的跳转目标) +std::unordered_map> CollectPredecessors( + Function* func) { + std::unordered_map> preds; + for (const auto& bb : func->GetBlocks()) { + preds[bb.get()] = {}; + } + for (const auto& bb : func->GetBlocks()) { + if (!bb->HasTerminator()) { + continue; + } + auto* term = bb->GetInstructions().back().get(); + if (auto* br = dynamic_cast(term)) { + preds[br->GetTarget()].push_back(bb.get()); + } else if (auto* condbr = dynamic_cast(term)) { + preds[condbr->GetTrueTarget()].push_back(bb.get()); + preds[condbr->GetFalseTarget()].push_back(bb.get()); + } + } + return preds; +} + +// 验证单个函数的 IR +void VerifyFunction(Function* func) { + const auto& blocks = func->GetBlocks(); + if (blocks.empty()) { + return; // 空函数(external declaration),无需验证 + } + + // 构建前驱映射(用于 PHI 验证) + auto pred_map = CollectPredecessors(func); + + // 构建支配树 + DominatorTree dom_tree; + dom_tree.Compute(func); + + // 收集所有基本块指针用于查找 + std::unordered_set block_set; + for (const auto& bb : blocks) { + block_set.insert(bb.get()); + } + + for (const auto& bb : blocks) { + BasicBlock* current_bb = bb.get(); + + // 检查 1: 非空基本块必须以终结指令结尾 + const auto& instructions = current_bb->GetInstructions(); + if (!instructions.empty()) { + auto* last_inst = instructions.back().get(); + if (!last_inst->IsTerminator()) { + std::ostringstream oss; + oss << "IR 验证失败: 函数 '" << func->GetName() << "' 的基本块 '" + << current_bb->GetName() + << "' 的最后一条指令不是终结指令 (opcode=" + << static_cast(last_inst->GetOpcode()) << ")"; + LogError(oss.str(), std::cerr); + std::abort(); + } + } + + // 检查 2: SSA 支配性 + PHI 一致性 + for (const auto& inst_ptr : instructions) { + auto* inst = inst_ptr.get(); + + if (inst->GetOpcode() == Opcode::Phi) { + // PHI 一致性检查: + // - 操作数个数必须为偶数 + // - 每个奇数索引的操作数(基本块引用)必须是前驱 + size_t num_operands = inst->GetNumOperands(); + if (num_operands % 2 != 0) { + std::ostringstream oss; + oss << "IR 验证失败: 函数 '" << func->GetName() + << "' 的基本块 '" << current_bb->GetName() + << "' 中的 PHI 节点操作数个数为奇数 (" << num_operands << ")"; + LogError(oss.str(), std::cerr); + std::abort(); + } + + // 收集已出现的前驱,检查重复 + std::unordered_set seen_preds; + const auto& bb_preds = pred_map[current_bb]; + + for (size_t i = 1; i < num_operands; i += 2) { + Value* block_op = inst->GetOperand(i); + auto* pred_bb = dynamic_cast(block_op); + if (!pred_bb) { + std::ostringstream oss; + oss << "IR 验证失败: 函数 '" << func->GetName() + << "' 的基本块 '" << current_bb->GetName() + << "' 中的 PHI 节点操作数 " << i << " 不是基本块"; + LogError(oss.str(), std::cerr); + std::abort(); + } + + // 检查该基本块是否为实际前驱 + bool is_pred = false; + for (auto* p : bb_preds) { + if (p == pred_bb) { + is_pred = true; + break; + } + } + if (!is_pred) { + std::ostringstream oss; + oss << "IR 验证失败: 函数 '" << func->GetName() + << "' 的基本块 '" << current_bb->GetName() + << "' 中的 PHI 节点引用了非前驱基本块 '" + << pred_bb->GetName() << "'"; + LogError(oss.str(), std::cerr); + std::abort(); + } + + // 检查重复前驱 + if (seen_preds.find(pred_bb) != seen_preds.end()) { + std::ostringstream oss; + oss << "IR 验证失败: 函数 '" << func->GetName() + << "' 的基本块 '" << current_bb->GetName() + << "' 中的 PHI 节点包含重复前驱 '" + << pred_bb->GetName() << "'"; + LogError(oss.str(), std::cerr); + std::abort(); + } + seen_preds.insert(pred_bb); + + // PHI 的 SSA 支配性检查: + // 每个值操作数(偶数索引)的定义必须支配对应的前驱基本块 + Value* val_op = inst->GetOperand(i - 1); + auto* val_inst = dynamic_cast(val_op); + if (val_inst && val_inst->GetParent()) { + if (!dom_tree.Dominates(val_inst->GetParent(), pred_bb)) { + std::ostringstream oss; + oss << "IR 验证失败: 函数 '" << func->GetName() + << "' 的基本块 '" << current_bb->GetName() + << "' 中的 PHI 值操作数 '" << val_inst->GetName() + << "' (定义于 '" << val_inst->GetParent()->GetName() + << "') 不支配前驱 '" << pred_bb->GetName() << "'"; + LogError(oss.str(), std::cerr); + std::abort(); + } + } + } + } else { + // 非 PHI 指令:检查每个操作数的 SSA 支配性 + for (size_t i = 0; i < inst->GetNumOperands(); ++i) { + Value* op = inst->GetOperand(i); + // 跳过常量、参数和基本块引用 + if (op->IsConstant()) continue; + auto* op_bb_ref = dynamic_cast(op); + if (op_bb_ref) continue; + auto* op_arg = dynamic_cast(op); + if (op_arg) continue; + if (op->IsFunction()) continue; + + auto* op_inst = dynamic_cast(op); + if (!op_inst) continue; + + BasicBlock* def_bb = op_inst->GetParent(); + if (!def_bb) continue; + + // 支配性检查:定义的基本块必须支配当前基本块 + if (!dom_tree.Dominates(def_bb, current_bb)) { + std::ostringstream oss; + oss << "IR 验证失败: 函数 '" << func->GetName() + << "' 中的指令 '" << inst->GetName() + << "' (opcode=" << static_cast(inst->GetOpcode()) + << ", 基本块 '" << current_bb->GetName() + << "') 使用了未支配的操作数 '" << op_inst->GetName() + << "' (定义于 '" << def_bb->GetName() << "')"; + LogError(oss.str(), std::cerr); + std::abort(); + } + } + } + } + } +} + +} // namespace + +void VerifyIR(Module& module) { + for (const auto& func_ptr : module.GetFunctions()) { + auto* func = func_ptr.get(); + // 跳过外部声明(没有函数体) + if (func->IsExternal()) continue; + // 跳过空函数体 + if (func->GetBlocks().empty()) continue; + + VerifyFunction(func); + } +} + +} // namespace ir diff --git a/src/main.cpp b/src/main.cpp index 708e8230..4a8dc84a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,6 +48,11 @@ int main(int argc, char** argv) { pass_manager.Run(); } + // Debug 模式:验证 IR 合法性 +#ifndef NDEBUG + ir::VerifyIR(*module); +#endif + // 汇编输出到文件或标准输出 if (opts.emit_asm) { auto machine_module = mir::LowerModuleToMIR(*module);