// Mem2Reg(SSA 构造): // - 将局部变量的 alloca/load/store 提升为 SSA 形式 // - 使用标准的支配边界 + PHI 节点插入算法 #include "include/ir/IR.h" #include #include #include #include #include #include #include #include namespace ir { namespace { constexpr bool kDebugMem2Reg = false; // 计算基本块的后继 std::vector GetSuccessors(BasicBlock* bb) { std::vector succs; if (!bb) return succs; auto& insts = bb->GetInstructions(); if (insts.empty()) return succs; auto* term = insts.back().get(); if (!term) return succs; switch (term->GetOpcode()) { case Opcode::Br: { auto* br = static_cast(term); succs.push_back(br->GetTarget()); break; } case Opcode::CondBr: { auto* cbr = static_cast(term); succs.push_back(cbr->GetTrueTarget()); succs.push_back(cbr->GetFalseTarget()); break; } case Opcode::Ret: break; default: break; } return succs; } // 计算基本块的前驱(通过扫描所有块的终止指令,不依赖缓存) std::vector GetPredecessors(BasicBlock* bb, Function* func = nullptr) { std::vector preds; if (!bb || !func) return preds; for (auto& block : func->GetBlocks()) { auto succs = GetSuccessors(block.get()); for (auto* succ : succs) { if (succ == bb) { preds.push_back(block.get()); break; } } } return preds; } // 支配树相关信息 struct DominatorInfo { std::unordered_map idom; std::unordered_map> dom_tree; BasicBlock* entry = nullptr; }; // 计算两个块的最近公共支配者 BasicBlock* Intersect(BasicBlock* b1, BasicBlock* b2, const std::unordered_map& idom) { auto* finger1 = b1; auto* finger2 = b2; while (finger1 != finger2) { while (finger1 && idom.count(finger1) && idom.at(finger1) && finger1 != idom.at(finger1)) { finger1 = idom.at(finger1); } while (finger2 && idom.count(finger2) && idom.at(finger2) && finger2 != idom.at(finger2)) { finger2 = idom.at(finger2); } if (finger1 == finger2) break; if (finger1 && idom.count(finger1) && idom.at(finger1)) finger1 = idom.at(finger1); if (finger2 && idom.count(finger2) && idom.at(finger2)) finger2 = idom.at(finger2); } return finger1; } // 预先计算所有块的支配者 DominatorInfo ComputeDominators(Function* func) { DominatorInfo dom_info; auto& blocks = func->GetBlocks(); if (blocks.empty()) return dom_info; dom_info.entry = func->GetEntry(); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Computing dominators for function: " << func->GetName() << std::endl; std::cerr << "[Mem2Reg] Entry block: " << dom_info.entry->GetName() << std::endl; std::cerr << "[Mem2Reg] Total blocks: " << blocks.size() << std::endl; // 调试前驱信息 for (auto& bb : blocks) { auto preds = GetPredecessors(bb.get(), func); std::cerr << " Block " << bb->GetName() << " has " << preds.size() << " predecessors: {"; bool first = true; for (auto* pred : preds) { if (!first) std::cerr << ", "; std::cerr << pred->GetName(); first = false; } std::cerr << "}" << std::endl; } } // 使用标准的迭代数据流算法计算支配者 // 初始化:entry的idom是自己,其他都是nullptr for (auto& bb : blocks) { dom_info.idom[bb.get()] = nullptr; } dom_info.idom[dom_info.entry] = dom_info.entry; // 迭代直到收敛 bool changed = true; int iteration = 0; while (changed) { changed = false; ++iteration; if (iteration > 1000) { std::cerr << "[Mem2Reg] ERROR: Dominator computation did not converge after 1000 iterations!" << std::endl; break; } for (auto& bb : blocks) { if (bb.get() == dom_info.entry) continue; auto preds = GetPredecessors(bb.get(), func); if (preds.empty()) continue; // 找到第一个已经有idom的前驱 BasicBlock* new_idom = nullptr; for (auto* pred : preds) { if (dom_info.idom[pred] != nullptr) { new_idom = pred; break; } } if (!new_idom) continue; // 与其他有idom的前驱求交集 for (auto* pred : preds) { if (pred == new_idom) continue; if (dom_info.idom[pred] == nullptr) continue; new_idom = Intersect(new_idom, pred, dom_info.idom); if (!new_idom) break; } if (new_idom && dom_info.idom[bb.get()] != new_idom) { dom_info.idom[bb.get()] = new_idom; changed = true; } } } if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Dominator computation completed after " << iteration << " iterations" << std::endl; } // 构建支配树 for (auto& bb : blocks) { if (bb.get() == dom_info.entry) continue; auto* idom = dom_info.idom[bb.get()]; if (idom && idom != bb.get()) { dom_info.dom_tree[idom].push_back(bb.get()); } } if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Dominator tree:" << std::endl; int non_null_count = 0; for (auto& bb : blocks) { auto* idom = dom_info.idom[bb.get()]; if (idom) non_null_count++; std::cerr << " " << bb->GetName() << " dominated by: " << (idom ? idom->GetName() : "null") << std::endl; } std::cerr << "[Mem2Reg] Blocks with non-null idom: " << non_null_count << "/" << blocks.size() << std::endl; } return dom_info; } // 计算支配边界 std::unordered_map> ComputeDominanceFrontier( Function* func, const DominatorInfo& dom_info) { std::unordered_map> df; auto& blocks = func->GetBlocks(); for (auto& bb : blocks) { df[bb.get()] = std::set(); } for (auto& bb : blocks) { auto preds = GetPredecessors(bb.get(), func); if (preds.size() < 2) continue; auto* bb_idom = dom_info.idom.count(bb.get()) ? dom_info.idom.at(bb.get()) : nullptr; if (!bb_idom) continue; for (auto* pred : preds) { auto* runner = pred; while (runner != bb_idom) { df[runner].insert(bb.get()); if (!runner || !dom_info.idom.count(runner) || !dom_info.idom.at(runner)) { break; } auto* next = dom_info.idom.at(runner); if (next == runner) break; runner = next; } } } if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Dominance frontiers:" << std::endl; for (auto& bb : blocks) { if (!df[bb.get()].empty()) { std::cerr << " " << bb->GetName() << " -> {"; bool first = true; for (auto* df_bb : df[bb.get()]) { if (!first) std::cerr << ", "; std::cerr << df_bb->GetName(); first = false; } std::cerr << "}" << std::endl; } } } return df; } // 检查是否是可以 SSA 化的 alloca bool IsPromotableAlloca(AllocaInst* alloca) { if (alloca->IsArrayAlloca()) { return false; } auto uses = alloca->GetUses(); if (uses.empty()) { return false; // 没有使用,不需要提升 } bool has_load = false; for (auto& use : uses) { auto* user = use.GetUser(); if (!user) return false; auto* inst = dynamic_cast(user); if (!inst) return false; auto opcode = inst->GetOpcode(); if (opcode != Opcode::Load && opcode != Opcode::Store) { return false; } if (opcode == Opcode::Store) { auto* store = static_cast(inst); if (store->GetPtr() != alloca) { return false; } } if (opcode == Opcode::Load) { has_load = true; } } return has_load; // 只有有 load 才需要提升 } std::vector FindPromotableAllocas(Function* func) { std::vector promotable; // 扫描所有基本块中的 allocas(不仅限于 entry 块) for (auto& bb : func->GetBlocks()) { for (auto& inst_ptr : bb->GetInstructions()) { auto* inst = inst_ptr.get(); if (auto* alloca = dynamic_cast(inst)) { if (IsPromotableAlloca(alloca)) { promotable.push_back(alloca); } } } } if (kDebugMem2Reg && !promotable.empty()) { std::cerr << "[Mem2Reg] Found " << promotable.size() << " promotable allocas in " << func->GetName() << std::endl; for (auto* alloca : promotable) { std::cerr << " - " << alloca->GetName() << std::endl; } } return promotable; } // 插入 PHI 节点 void InsertPhiNodes(Function* func, const std::vector& allocas, const DominatorInfo& dom_info, const std::unordered_map>& df, std::unordered_map>& phi_nodes, std::unordered_set& skip_allocas) { for (auto* alloca : allocas) { std::set store_blocks; int store_count = 0; for (auto& bb : func->GetBlocks()) { for (auto& inst_ptr : bb->GetInstructions()) { auto* inst = inst_ptr.get(); if (auto* store = dynamic_cast(inst)) { if (store->GetPtr() == alloca) { store_blocks.insert(bb.get()); store_count++; } } } } if (kDebugMem2Reg && !store_blocks.empty()) { std::cerr << "[Mem2Reg] Store blocks for " << alloca->GetName() << ": {"; bool first = true; for (auto* bb : store_blocks) { if (!first) std::cerr << ", "; std::cerr << bb->GetName(); first = false; } std::cerr << "}" << std::endl; } std::set phi_blocks; std::vector worklist(store_blocks.begin(), store_blocks.end()); std::set visited(store_blocks.begin(), store_blocks.end()); while (!worklist.empty()) { auto* bb = worklist.back(); worklist.pop_back(); auto df_it = df.find(bb); if (df_it == df.end()) continue; for (auto* df_block : df_it->second) { if (phi_blocks.insert(df_block).second && visited.insert(df_block).second) { worklist.push_back(df_block); } } } if (kDebugMem2Reg && !phi_blocks.empty()) { std::cerr << "[Mem2Reg] PHI blocks for " << alloca->GetName() << ": {"; bool first = true; for (auto* bb : phi_blocks) { if (!first) std::cerr << ", "; std::cerr << bb->GetName(); first = false; } std::cerr << "}" << std::endl; } if (store_count > 1 && !phi_blocks.empty()) { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Alloca " << alloca->GetName() << " has multiple stores (store_count=" << store_count << ", phi_blocks=" << phi_blocks.size() << "), promoting anyway" << std::endl; } } for (auto* bb : phi_blocks) { auto& insts = const_cast>&>(bb->GetInstructions()); if (insts.empty()) continue; // 使用 alloca 的元素类型作为 PHI 的类型 auto* phi = bb->Prepend(alloca->GetElementType(), ""); phi->SetAlloca(alloca); phi_nodes[alloca][bb] = phi; } } } // 全局 PHI 计数器 int gPhiCounter = 0; // 重命名 void Rename(BasicBlock* bb, const DominatorInfo& dom_info, AllocaInst* alloca, std::unordered_map>& value_stack, std::unordered_map>& phi_nodes, std::unordered_map& initial_values) { // 处理当前块的 PHI 节点 auto phi_it = phi_nodes.find(alloca); if (phi_it != phi_nodes.end()) { auto phi_block_it = phi_it->second.find(bb); if (phi_block_it != phi_it->second.end()) { auto* phi = phi_block_it->second; // 给 PHI 节点一个名字 if (phi->GetName().empty()) { phi->SetName("%phi" + std::to_string(gPhiCounter++)); } value_stack[alloca].push_back(phi); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Push PHI " << phi->GetName() << " for " << alloca->GetName() << " in block " << bb->GetName() << std::endl; } } } // 先处理指令:store 推栈,load 替换 for (auto& inst_ptr : bb->GetInstructions()) { auto* inst = inst_ptr.get(); if (dynamic_cast(inst)) continue; if (auto* store = dynamic_cast(inst)) { if (store->GetPtr() == alloca) { auto* val = store->GetValue(); value_stack[alloca].push_back(val); // 记录初始值:第一个 store 的值作为初始值(覆盖默认值 0) // 这样可以正确处理循环不变量的情况 if (initial_values.count(alloca)) { auto* current_init = initial_values[alloca]; // 如果当前初始值是默认值 0(ConstantInt 0),则更新为 store 的值 if (auto* const_int = dynamic_cast(current_init)) { if (const_int->GetValue() == 0) { initial_values[alloca] = val; if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Update initial value for " << alloca->GetName() << " from 0 to " << val->GetName() << " in block " << bb->GetName() << std::endl; } } } } else { initial_values[alloca] = val; if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Set initial value for " << alloca->GetName() << " to " << val->GetName() << " in block " << bb->GetName() << std::endl; } } if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Push store value " << val->GetName() << " for " << alloca->GetName() << " in block " << bb->GetName() << std::endl; } } } if (auto* load = dynamic_cast(inst)) { if (load->GetPtr() == alloca) { auto stack_it = value_stack.find(alloca); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Checking load " << load->GetName() << " in " << bb->GetName() << ", stack size: " << (stack_it != value_stack.end() ? stack_it->second.size() : 0) << std::endl; } if (stack_it != value_stack.end() && !stack_it->second.empty()) { auto* current_val = stack_it->second.back(); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Replacing load " << load->GetName() << " of " << alloca->GetName() << " in block " << bb->GetName() << " with value: " << (current_val ? current_val->GetName() : "null") << std::endl; if (current_val && current_val->GetType()) { std::cerr << "[Mem2Reg] Replacement value type: " << (int)current_val->GetType()->GetKind() << std::endl; } } // 类型安全检查:确保替换值的类型与 load 的结果类型完全匹配 if (current_val && current_val->GetType()) { auto* load_type = load->GetType().get(); auto* val_type = current_val->GetType().get(); if (load_type && val_type && load_type == val_type) { load->ReplaceAllUsesWith(current_val); } else { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] WARNING: Type mismatch! Load type " << (load_type ? std::to_string((int)load_type->GetKind()) : "null") << " vs value type " << (val_type ? std::to_string((int)val_type->GetKind()) : "null") << std::endl; } } } } else { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: ERROR - Empty stack for load " << load->GetName() << " in block " << bb->GetName() << std::endl; } } } } } // 处理完指令后,填充后继块的 PHI 节点 auto successors = GetSuccessors(bb); for (auto* succ : successors) { auto succ_phi_it = phi_nodes.find(alloca); if (succ_phi_it != phi_nodes.end()) { auto succ_block_it = succ_phi_it->second.find(succ); if (succ_block_it != succ_phi_it->second.end()) { auto* phi = succ_block_it->second; // 如果栈为空,使用初始值 Value* incoming_val = nullptr; if (!value_stack[alloca].empty()) { incoming_val = value_stack[alloca].back(); if (kDebugMem2Reg && incoming_val == phi) { std::cerr << "[Mem2Reg] Rename: Self-referencing PHI in " << succ->GetName() << " for alloca " << alloca->GetName() << " (variable unchanged on this path)" << std::endl; } } else if (initial_values.count(alloca)) { incoming_val = initial_values[alloca]; } // 检查是否已经为这个前驱添加过条目 bool already_added = false; for (size_t i = 1; i < phi->GetNumOperands(); i += 2) { if (phi->GetOperand(i) == bb) { already_added = true; break; } } if (!already_added && incoming_val) { phi->AddOperand(incoming_val); phi->AddOperand(bb); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Adding operand to PHI in " << succ->GetName() << " from " << bb->GetName() << ", value: " << incoming_val->GetName() << std::endl; } } else if (!already_added && !incoming_val && kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: WARNING - No value for PHI in " << succ->GetName() << " from " << bb->GetName() << std::endl; } } } } // 递归处理支配树中的子块 auto dom_tree_it = dom_info.dom_tree.find(bb); if (dom_tree_it != dom_info.dom_tree.end()) { for (auto* child : dom_tree_it->second) { Rename(child, dom_info, alloca, value_stack, phi_nodes, initial_values); } } // 回溯 for (auto rit = bb->GetInstructions().rbegin(); rit != bb->GetInstructions().rend(); ++rit) { auto* inst = rit->get(); if (dynamic_cast(inst)) continue; if (auto* store = dynamic_cast(inst)) { if (store->GetPtr() == alloca) { auto& stack = value_stack[alloca]; if (!stack.empty()) { stack.pop_back(); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Pop store value for " << alloca->GetName() << " in block " << bb->GetName() << std::endl; } } } } } // 弹出 PHI auto phi_it2 = phi_nodes.find(alloca); if (phi_it2 != phi_nodes.end()) { auto phi_block_it = phi_it2->second.find(bb); if (phi_block_it != phi_it2->second.end()) { auto& stack = value_stack[alloca]; if (!stack.empty()) { stack.pop_back(); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Rename: Pop PHI for " << alloca->GetName() << " in block " << bb->GetName() << std::endl; } } } } } // 删除冗余指令 void RemoveRedundantInstructions(Function* func, const std::vector& allocas) { std::set to_delete; std::set alloca_set(allocas.begin(), allocas.end()); for (auto* alloca : allocas) { to_delete.insert(alloca); } for (auto& bb : func->GetBlocks()) { for (auto& inst_ptr : bb->GetInstructions()) { auto* inst = inst_ptr.get(); if (auto* load = dynamic_cast(inst)) { auto* ptr = load->GetPtr(); if (auto* alloca = dynamic_cast(ptr)) { if (alloca_set.count(alloca) && load->GetUses().empty()) { to_delete.insert(load); } } } else if (auto* store = dynamic_cast(inst)) { auto* ptr = store->GetPtr(); if (auto* alloca = dynamic_cast(ptr)) { if (alloca_set.count(alloca)) { to_delete.insert(store); } } } } } for (auto& bb : func->GetBlocks()) { auto& insts = const_cast>&>(bb->GetInstructions()); for (auto it = insts.begin(); it != insts.end();) { auto* inst = it->get(); if (to_delete.count(inst) && !dynamic_cast(inst)) { for (size_t i = 0; i < inst->GetNumOperands(); ++i) { if (auto* op = inst->GetOperand(i)) { auto& uses = const_cast&>(op->GetUses()); uses.erase( std::remove_if(uses.begin(), uses.end(), [inst](const Use& use) { return use.GetUser() == inst; }), uses.end()); } } it = insts.erase(it); } else { ++it; } } } for (auto& bb : func->GetBlocks()) { auto& insts = const_cast>&>(bb->GetInstructions()); for (auto it = insts.begin(); it != insts.end();) { if (dynamic_cast(it->get()) && to_delete.count(it->get())) { auto* alloca = static_cast(it->get()); auto& uses = const_cast&>(alloca->GetUses()); uses.clear(); it = insts.erase(it); } else { ++it; } } } } } // anonymous namespace // Mem2Reg 主函数 void RunMem2Reg(Module& module) { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] === Starting Mem2Reg Pass ===" << std::endl; } for (auto& func_ptr : module.GetFunctions()) { auto* func = func_ptr.get(); if (func->IsExternal()) continue; // 跳过过大的函数以避免编译超时 if (func->GetBlocks().size() > 2000) { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Skipping large function " << func->GetName() << " with " << func->GetBlocks().size() << " blocks" << std::endl; } continue; } if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Processing function: " << func->GetName() << std::endl; } auto promotable_allocas = FindPromotableAllocas(func); if (promotable_allocas.empty()) { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] No promotable allocas in " << func->GetName() << std::endl; } continue; } auto dom_info = ComputeDominators(func); auto df = ComputeDominanceFrontier(func, dom_info); std::unordered_map> phi_nodes; std::unordered_set skip_allocas; InsertPhiNodes(func, promotable_allocas, dom_info, df, phi_nodes, skip_allocas); // 过滤掉需要跳过的 alloca std::vector filtered_allocas; for (auto* alloca : promotable_allocas) { if (skip_allocas.find(alloca) == skip_allocas.end()) { filtered_allocas.push_back(alloca); } } if (filtered_allocas.empty()) { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] No promotable allocas left after filtering in " << func->GetName() << std::endl; } continue; } // 计算总 PHI 节点数量 int total_phi_count = 0; for (auto& pair : phi_nodes) { total_phi_count += pair.second.size(); } // 启发式:如果 PHI 节点数量过多,跳过该函数 // PHI 节点在 llc -O0 下会生成 StoreStack 操作,可能导致性能下降 // 阈值设置:基本块数量的 1/4,最小 10,最大 30 int block_count = func->GetBlocks().size(); int phi_threshold = std::max(50, block_count); if (total_phi_count > phi_threshold) { if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] Skipping function " << func->GetName() << " due to too many PHI nodes: " << total_phi_count << " (threshold: " << phi_threshold << ")" << std::endl; } continue; } for (auto* alloca : filtered_allocas) { std::unordered_map> value_stack; std::unordered_map initial_values; // 根据 alloca 的元素类型创建对应类型的默认常量 0 auto* elem_type = alloca->GetElementType().get(); Value* default_val = nullptr; if (elem_type->IsInt32()) { default_val = new ConstantInt(Type::GetInt32Type(), 0); } else if (elem_type->IsInt1()) { default_val = new ConstantInt(Type::GetInt1Type(), 0); } else if (elem_type->IsFloat32()) { default_val = new ConstantFloat(Type::GetFloat32Type(), 0.0); } if (default_val) { initial_values[alloca] = default_val; } if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] === Renaming for alloca: " << alloca->GetName() << " ===" << std::endl; } Rename(func->GetEntry(), dom_info, alloca, value_stack, phi_nodes, initial_values); } RemoveRedundantInstructions(func, filtered_allocas); if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] === Finished " << func->GetName() << " ===" << std::endl; } } if (kDebugMem2Reg) { std::cerr << "[Mem2Reg] === Mem2Reg Pass Complete ===" << std::endl; } } } // namespace ir