From 5d4353929066b7697bf79960ca6d34284097aa1a Mon Sep 17 00:00:00 2001 From: lzkk <956449176@qq.com> Date: Thu, 28 May 2026 08:46:44 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E4=BB=A3=E7=A0=81=E5=BD=BB=E5=BA=95?= =?UTF-8?q?=E6=B8=85=E7=90=86=E2=80=94=E2=80=94=E5=88=A0=E9=99=A4=E6=AD=BB?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E3=80=81=E6=97=A7=E5=A4=87=E4=BB=BD=E3=80=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除: - warning/ src.bak.full/ llvm/ docs/superpowers/ (95MB+ 磁盘释放) - Inline.cpp (621行,从未正确集成) - PassManagerModule 死类 + 3个未使用pass声明 (PassManager.h) - RunStrengthReduction/RunLoopUnrolling/RunLoopFission (LoopInfo.cpp 805行) - FindInductionVars/AllUsesInLoop/IsSRLoopInvariantValue 死辅助函数 - 生成文件: Error.txt results.csv/json time_opt.txt settings.json 更新 .gitignore 防止未来污染 --- .gitignore | 19 + src/include/ir/passes/PassManager.h | 56 -- src/ir/analysis/LoopInfo.cpp | 971 +--------------------------- src/ir/passes/Inline.cpp | 621 ------------------ 4 files changed, 21 insertions(+), 1646 deletions(-) delete mode 100644 src/ir/passes/Inline.cpp diff --git a/.gitignore b/.gitignore index ef54b105..4f495dbb 100644 --- a/.gitignore +++ b/.gitignore @@ -87,8 +87,27 @@ test_fail/ # Local test & build # ========================= 2026test/ +2026test_results/ build_clang/ build_debug/ build_ubsan/ build_eval/ test5.sh + +# ========================= +# Tooling +# ========================= +.claude/ +.claudeignore +.codegraph/ +.count_tmp.s + +# ========================= +# Generated reports +# ========================= +results.csv +results.json +Error.txt +time_opt.txt +settings.json +指令数基线.md diff --git a/src/include/ir/passes/PassManager.h b/src/include/ir/passes/PassManager.h index 3f679d20..d67d23cf 100644 --- a/src/include/ir/passes/PassManager.h +++ b/src/include/ir/passes/PassManager.h @@ -10,66 +10,12 @@ namespace ir { void RunMem2Reg(Module& module); void RunLICM(Module* module); -void RunStrengthReduction(Module* module); -void RunLoopUnrolling(Module* module); -void RunLoopFission(Module* module); void RunConstFold(Module& module); void RunConstProp(Module& module); void RunDCE(Module& module); void RunCFGSimplify(Module& module); void RunCSE(Module& module); -class PassManagerModule { - public: - explicit PassManagerModule(Module* module) : module_(module) {} - - void Run() { - if (!module_) { - return; - } - - RunMem2Reg(*module_); - - RunLICM(module_); - - RunStrengthReduction(module_); - - RunLoopFission(module_); - - RunLoopUnrolling(module_); - - bool changed = true; - int max_iterations = 10; - int iterations = 0; - - while (changed && iterations < max_iterations) { - changed = false; - iterations++; - - auto before = SerializeModule(*module_); - - RunConstFold(*module_); - RunConstProp(*module_); - RunCFGSimplify(*module_); - RunCSE(*module_); - RunDCE(*module_); - - auto after = SerializeModule(*module_); - changed = (before != after); - } - } - - private: - std::string SerializeModule(const Module& module) { - std::ostringstream oss; - IRPrinter printer; - printer.Print(module, oss); - return oss.str(); - } - - Module* module_; -}; - class PassManager { public: PassManager() = default; @@ -105,8 +51,6 @@ class PassManager { changed = (before.str() != after.str()); } } - - private: }; } // namespace ir diff --git a/src/ir/analysis/LoopInfo.cpp b/src/ir/analysis/LoopInfo.cpp index 37d69c7e..b188f062 100644 --- a/src/ir/analysis/LoopInfo.cpp +++ b/src/ir/analysis/LoopInfo.cpp @@ -592,935 +592,10 @@ namespace ir int step_sign = 1; }; - std::vector FindInductionVars(const LoopInfo *loop) - { - std::vector inductions; - - for (auto &inst : loop->header->GetInstructions()) - { - auto *phi = dynamic_cast(inst.get()); - if (!phi) - continue; - if (!phi->GetType()->IsInt32()) - continue; - if (phi->GetNumOperands() < 4 || phi->GetNumOperands() % 2 != 0) - continue; - - Value *outside_val = nullptr; - BasicBlock *outside_block = nullptr; - Value *common_step = nullptr; - int common_step_sign = 0; - Instruction *step_inst = nullptr; - BasicBlock *latch_block = nullptr; - bool valid = true; - - for (size_t i = 0; i < phi->GetNumOperands(); i += 2) - { - auto *val = phi->GetOperand(i); - auto *bb = dynamic_cast(phi->GetOperand(i + 1)); - if (!bb) - { - valid = false; - break; - } - - if (loop->blocks.count(bb) == 0) - { - if (outside_val != nullptr) - { - valid = false; - break; - } - outside_val = val; - outside_block = bb; - } - else - { - auto *bin_inst = dynamic_cast(val); - if (!bin_inst) - { - valid = false; - break; - } - - Value *step = nullptr; - int step_sign = 0; - - if (bin_inst->GetOpcode() == Opcode::Add) - { - if (bin_inst->GetLhs() == phi) - { - step = bin_inst->GetRhs(); - step_sign = 1; - } - else if (bin_inst->GetRhs() == phi) - { - step = bin_inst->GetLhs(); - step_sign = 1; - } - } - else if (bin_inst->GetOpcode() == Opcode::Sub) - { - if (bin_inst->GetLhs() == phi) - { - step = bin_inst->GetRhs(); - step_sign = -1; - } - } - - if (!step || step_sign == 0) - { - valid = false; - break; - } - if (!dynamic_cast(step)) - { - valid = false; - break; - } - if (common_step_sign == 0) - { - common_step = step; - common_step_sign = step_sign; - step_inst = bin_inst; - latch_block = bb; - } - else - { - auto *prev_const = dynamic_cast(common_step); - auto *cur_const = dynamic_cast(step); - if (!prev_const || !cur_const || - prev_const->GetValue() * common_step_sign != - cur_const->GetValue() * step_sign) - { - valid = false; - break; - } - } - } - } - if (!valid || !outside_val || common_step_sign == 0 || !step_inst || !latch_block) - continue; - - InductionVar iv; - iv.phi = phi; - iv.init_val = outside_val; - iv.init_block = outside_block; - iv.step_val = common_step; - iv.step_inst = step_inst; - iv.latch_block = latch_block; - iv.step_sign = common_step_sign; - - inductions.push_back(iv); - - if (kDebugSR) - { - std::cerr << "[SR] Found induction var: " << phi->GetName() - << " init=" << (outside_val ? outside_val->GetName() : "null") - << " step=" << (common_step_sign > 0 ? "+" : "-") << common_step->GetName() - << " operands=" << phi->GetNumOperands() << std::endl; - } - } - - return inductions; - } - - bool IsSRLoopInvariantValue(Value *val, const std::set &loop_blocks) - { - if (!val) - return false; - if (dynamic_cast(val)) - return true; - if (dynamic_cast(val)) - return true; - if (dynamic_cast(val)) - return true; - if (dynamic_cast(val)) - return true; - - auto *inst = dynamic_cast(val); - if (!inst) - return false; - - auto *parent = inst->GetParent(); - if (parent && loop_blocks.count(parent) == 0) - return true; - - return false; - } - - bool AllUsesInLoop(Value *val, const std::set &loop_blocks) - { - for (auto &use : val->GetUses()) - { - auto *user = use.GetUser(); - if (!user) - continue; - auto *inst = dynamic_cast(user); - if (!inst) - continue; - auto *parent = inst->GetParent(); - if (!parent || loop_blocks.count(parent) == 0) - return false; - } - return true; - } - - void RunStrengthReductionOnFunction(Function *func, Module *module) - { - int block_count = func->GetBlocks().size(); - if (block_count > 500) - return; - - auto loops = FindLoops(func); - if (loops.empty()) - return; - - auto &ctx = module->GetContext(); - - for (auto &loop : loops) - { - if (!loop->preheader) - continue; - - auto inductions = FindInductionVars(loop.get()); - if (inductions.empty()) - continue; - - for (auto &iv : inductions) - { - std::vector> muls_to_reduce; - - for (auto *bb : loop->blocks) - { - for (auto &inst : bb->GetInstructions()) - { - auto *mul = dynamic_cast(inst.get()); - if (!mul || mul->GetOpcode() != Opcode::Mul) - continue; - if (mul == iv.step_inst) - continue; - - Value *other = nullptr; - if (mul->GetLhs() == iv.phi) - { - other = mul->GetRhs(); - } - else if (mul->GetRhs() == iv.phi) - { - other = mul->GetLhs(); - } - else - { - continue; - } - - if (other == iv.phi) - continue; - - if (!IsSRLoopInvariantValue(other, loop->blocks)) - continue; - - if (!AllUsesInLoop(mul, loop->blocks)) - continue; - - muls_to_reduce.push_back(std::make_pair(mul, other)); - } - } - - for (auto &entry : muls_to_reduce) - { - auto *mul = entry.first; - auto *k = entry.second; - - auto *derived_phi = loop->header->Prepend(iv.phi->GetType(), ctx.NextTemp()); - - Value *init_val = nullptr; - auto *init_const = dynamic_cast(iv.init_val); - if (init_const && init_const->GetValue() == 0) - { - init_val = ctx.GetConstInt(0); - } - else - { - auto init_mul = std::make_unique( - Opcode::Mul, iv.init_val->GetType(), iv.init_val, k, ctx.NextTemp()); - init_val = init_mul.get(); - loop->preheader->InsertInstructionBeforeTerminator(std::move(init_mul)); - } - - Value *increment = nullptr; - auto *step_const = dynamic_cast(iv.step_val); - int step_v = step_const ? step_const->GetValue() : 0; - int effective_step = step_v * iv.step_sign; - - if (effective_step == 1) - { - increment = k; - } - else if (effective_step == -1) - { - auto neg = std::make_unique( - Opcode::Sub, k->GetType(), ctx.GetConstInt(0), k, ctx.NextTemp()); - increment = neg.get(); - loop->preheader->InsertInstructionBeforeTerminator(std::move(neg)); - } - else - { - auto *step_for_mul = ctx.GetConstInt(effective_step); - auto step_mul = std::make_unique( - Opcode::Mul, k->GetType(), step_for_mul, k, ctx.NextTemp()); - increment = step_mul.get(); - loop->preheader->InsertInstructionBeforeTerminator(std::move(step_mul)); - } - - derived_phi->AddOperand(init_val); - derived_phi->AddOperand(iv.init_block); - - for (size_t i = 0; i < iv.phi->GetNumOperands(); i += 2) - { - auto *bb = dynamic_cast(iv.phi->GetOperand(i + 1)); - if (!bb) - continue; - - if (loop->blocks.count(bb) == 0) - continue; - - auto update_add = std::make_unique( - Opcode::Add, derived_phi->GetType(), derived_phi, increment, ctx.NextTemp()); - auto *update_add_ptr = update_add.get(); - bb->InsertInstructionBeforeTerminator(std::move(update_add)); - - derived_phi->AddOperand(update_add_ptr); - derived_phi->AddOperand(bb); - } - - mul->ReplaceAllUsesWith(derived_phi); - - if (kDebugSR) - { - std::cerr << "[SR] Replaced " << mul->GetName() << " = mul " - << iv.phi->GetName() << ", " << k->GetName() - << " with derived phi " << derived_phi->GetName() << std::endl; - } - } - } - } - } - - std::unique_ptr CloneInstruction(Instruction *inst, Context &ctx, - std::unordered_map &value_map) - { - Opcode op = inst->GetOpcode(); - - switch (op) - { - case Opcode::Add: - case Opcode::Sub: - case Opcode::Mul: - case Opcode::Div: - case Opcode::Mod: - case Opcode::Eq: - case Opcode::Ne: - case Opcode::Lt: - case Opcode::Le: - case Opcode::Gt: - case Opcode::Ge: - { - auto *bin = static_cast(inst); - auto *lhs_orig = bin->GetLhs(); - auto *rhs_orig = bin->GetRhs(); - auto *lhs = value_map.count(lhs_orig) ? value_map[lhs_orig] : lhs_orig; - auto *rhs = value_map.count(rhs_orig) ? value_map[rhs_orig] : rhs_orig; - auto cloned = std::make_unique(op, inst->GetType(), lhs, rhs, ctx.NextTemp()); - value_map[inst] = cloned.get(); - return cloned; - } - - case Opcode::SIToFP: - case Opcode::FPToSI: - case Opcode::ZExt: - { - auto *cast = static_cast(inst); - auto *operand_orig = cast->GetOperandValue(); - auto *operand = value_map.count(operand_orig) ? value_map[operand_orig] : operand_orig; - auto cloned = std::make_unique(op, inst->GetType(), operand, ctx.NextTemp()); - value_map[inst] = cloned.get(); - return cloned; - } - - case Opcode::Load: - { - auto *load = static_cast(inst); - auto *ptr_orig = load->GetPtr(); - auto *ptr = value_map.count(ptr_orig) ? value_map[ptr_orig] : ptr_orig; - auto cloned = std::make_unique(inst->GetType(), ptr, ctx.NextTemp()); - value_map[inst] = cloned.get(); - return cloned; - } - - case Opcode::Store: - { - auto *store = static_cast(inst); - auto *val_orig = store->GetValue(); - auto *ptr_orig = store->GetPtr(); - auto *val = value_map.count(val_orig) ? value_map[val_orig] : val_orig; - auto *ptr = value_map.count(ptr_orig) ? value_map[ptr_orig] : ptr_orig; - auto cloned = std::make_unique(Type::GetVoidType(), val, ptr); - value_map[inst] = cloned.get(); - return cloned; - } - - case Opcode::GEP: - { - auto *gep = static_cast(inst); - auto *base_orig = gep->GetBasePtr(); - auto *idx_orig = gep->GetIndex(); - auto *base = value_map.count(base_orig) ? value_map[base_orig] : base_orig; - auto *idx = value_map.count(idx_orig) ? value_map[idx_orig] : idx_orig; - auto cloned = std::make_unique(inst->GetType(), base, idx, ctx.NextTemp()); - value_map[inst] = cloned.get(); - return cloned; - } - - case Opcode::Call: - { - auto *call = static_cast(inst); - auto *callee = call->GetCallee(); - std::vector args; - for (size_t i = 0; i < call->GetNumArgs(); ++i) - { - auto *arg_orig = call->GetArg(i); - auto *arg = value_map.count(arg_orig) ? value_map[arg_orig] : arg_orig; - args.push_back(arg); - } - auto cloned = std::make_unique(inst->GetType(), callee, args, ctx.NextTemp()); - value_map[inst] = cloned.get(); - return cloned; - } - - default: - return nullptr; - } - } - - void RunLoopUnrollingOnFunction(Function *func, Module *module) - { - int block_count = func->GetBlocks().size(); - if (block_count > 500) - return; - - auto loops = FindLoops(func); - if (loops.empty()) - return; - - auto &ctx = module->GetContext(); - const int unroll_factor = 2; - - for (auto &loop : loops) - { - if (!loop->preheader) - continue; - if (loop->blocks.size() != 1) - continue; - - auto *header = loop->header; - if (header != *loop->blocks.begin()) - continue; - - auto inductions = FindInductionVars(loop.get()); - if (inductions.size() != 1) - continue; - - auto &iv = inductions[0]; - if (iv.step_sign != 1) - continue; - - auto *step_const = dynamic_cast(iv.step_val); - if (!step_const) - continue; - int step_v = step_const->GetValue(); - if (step_v <= 0) - continue; - - bool has_phi_other_than_iv = false; - bool has_call = false; - int body_inst_count = 0; - - for (auto &inst : header->GetInstructions()) - { - if (inst->IsTerminator()) - continue; - auto *phi = dynamic_cast(inst.get()); - if (phi) - { - if (phi != iv.phi) - has_phi_other_than_iv = true; - continue; - } - if (inst->GetOpcode() == Opcode::Call) - has_call = true; - body_inst_count++; - } - - if (has_phi_other_than_iv) - continue; - if (has_call) - continue; - if (body_inst_count == 0 || body_inst_count > 50) - continue; - - auto *cond_br = dynamic_cast(header->GetInstructions().back().get()); - if (!cond_br) - continue; - - auto header_succs = GetSuccessors(header); - if (header_succs.size() != 2) - continue; - - bool branches_to_self = false; - for (auto *s : header_succs) - { - if (s == header) - branches_to_self = true; - } - if (!branches_to_self) - continue; - - if (kDebugLU) - { - std::cerr << "[LU] Unrolling loop " << header->GetName() - << " factor=" << unroll_factor - << " iv=" << iv.phi->GetName() - << " step=" << step_v - << " body_insts=" << body_inst_count << std::endl; - } - - std::vector body_inst_ptrs; - for (auto &inst : header->GetInstructions()) - { - if (inst->IsTerminator()) - continue; - if (dynamic_cast(inst.get())) - continue; - body_inst_ptrs.push_back(inst.get()); - } - - std::vector> owned_body; - std::unordered_map orig_to_copy0; - - for (auto *ptr : body_inst_ptrs) - { - auto owned = header->TakeInstruction(ptr); - if (owned) - { - orig_to_copy0[ptr] = ptr; - owned_body.push_back(std::move(owned)); - } - } - - for (int copy = 1; copy < unroll_factor; ++copy) - { - std::unordered_map remap; - - for (auto &inst : owned_body) - { - if (inst.get() == iv.step_inst) - { - auto *orig_step = static_cast(iv.step_inst); - Value *lhs_orig = orig_step->GetLhs(); - Value *rhs_orig = orig_step->GetRhs(); - - Value *lhs = orig_to_copy0.count(lhs_orig) ? orig_to_copy0[lhs_orig] : lhs_orig; - Value *rhs = rhs_orig; - - if (copy == 1) - { - auto new_step = std::make_unique( - Opcode::Add, iv.phi->GetType(), lhs, rhs, ctx.NextTemp()); - remap[iv.step_inst] = new_step.get(); - orig_to_copy0[iv.step_inst] = new_step.get(); - header->InsertInstructionBeforeTerminator(std::move(new_step)); - } - continue; - } - - auto cloned = CloneInstruction(inst.get(), ctx, orig_to_copy0); - if (cloned) - { - remap[inst.get()] = cloned.get(); - orig_to_copy0[inst.get()] = cloned.get(); - header->InsertInstructionBeforeTerminator(std::move(cloned)); - } - } - } - - for (auto &inst : owned_body) - { - inst->SetParent(nullptr); - header->InsertInstructionBeforeTerminator(std::move(inst)); - } - - auto old_step_owned = header->TakeInstruction(iv.step_inst); - - auto *new_step_const = ctx.GetConstInt(step_v * unroll_factor); - auto new_step = std::make_unique( - Opcode::Add, iv.phi->GetType(), iv.phi, new_step_const, ctx.NextTemp()); - auto *new_step_ptr = new_step.get(); - header->InsertInstructionBeforeTerminator(std::move(new_step)); - - for (size_t i = 0; i < iv.phi->GetNumOperands(); i += 2) - { - auto *val = iv.phi->GetOperand(i); - if (val == iv.step_inst) - { - iv.phi->SetOperand(i, new_step_ptr); - } - } - - if (kDebugLU) - { - std::cerr << "[LU] Unrolled loop " << header->GetName() - << " factor=" << unroll_factor - << " new_step=" << new_step_ptr->GetName() << std::endl; - } - } - } - - void CollectDepChain(Instruction *inst, std::set &chain, - const std::set &all_body) - { - if (!inst || chain.count(inst)) - return; - chain.insert(inst); - - for (size_t i = 0; i < inst->GetNumOperands(); ++i) - { - auto *op = inst->GetOperand(i); - if (!op) - continue; - auto *op_inst = dynamic_cast(op); - if (op_inst && all_body.count(op_inst)) - { - CollectDepChain(op_inst, chain, all_body); - } - } - } - - void RunLoopFissionOnFunction(Function *func, Module *module) - { - int block_count = func->GetBlocks().size(); - if (block_count > 500) - return; - - auto loops = FindLoops(func); - if (loops.empty()) - return; - - auto &ctx = module->GetContext(); - - for (auto &loop : loops) - { - if (!loop->preheader) - continue; - if (loop->blocks.size() != 1) - continue; - - auto *header = loop->header; - if (header != *loop->blocks.begin()) - continue; - - auto inductions = FindInductionVars(loop.get()); - if (inductions.size() != 1) - continue; - - auto &iv = inductions[0]; - if (iv.step_sign != 1) - continue; - - auto *step_const = dynamic_cast(iv.step_val); - if (!step_const) - continue; - int step_v = step_const->GetValue(); - if (step_v <= 0) - continue; - - auto *cond_br = dynamic_cast(header->GetInstructions().back().get()); - if (!cond_br) - continue; - - auto header_succs = GetSuccessors(header); - if (header_succs.size() != 2) - continue; - - bool branches_to_self = false; - BasicBlock *exit_block = nullptr; - for (auto *s : header_succs) - { - if (s == header) - branches_to_self = true; - else - exit_block = s; - } - if (!branches_to_self || !exit_block) - continue; - - std::vector store_insts; - std::set all_body; - std::vector body_order; - - for (auto &inst : header->GetInstructions()) - { - if (inst->IsTerminator()) - continue; - if (dynamic_cast(inst.get())) - continue; - all_body.insert(inst.get()); - body_order.push_back(inst.get()); - - auto *store = dynamic_cast(inst.get()); - if (store) - store_insts.push_back(store); - } - - if (store_insts.size() < 2) - continue; - - bool has_call = false; - for (auto *inst : all_body) - { - if (inst->GetOpcode() == Opcode::Call) - { - has_call = true; - break; - } - } - if (has_call) - continue; - - std::set store_ptrs; - for (auto *store : store_insts) - { - store_ptrs.insert(store->GetPtr()); - } - - std::vector> store_chains; - for (auto *store : store_insts) - { - std::set chain; - CollectDepChain(store, chain, all_body); - store_chains.push_back(std::move(chain)); - } - - std::vector group_id(store_insts.size(), -1); - int num_groups = 0; - - for (size_t i = 0; i < store_insts.size(); ++i) - { - if (group_id[i] >= 0) - continue; - - group_id[i] = num_groups; - for (size_t j = i + 1; j < store_insts.size(); ++j) - { - if (group_id[j] >= 0) - continue; - - bool has_overlap = false; - for (auto *inst : store_chains[i]) - { - if (store_chains[j].count(inst)) - { - has_overlap = true; - break; - } - } - - if (has_overlap) - { - group_id[j] = num_groups; - } - } - num_groups++; - } - - if (num_groups < 2) - continue; - - if (kDebugLF) - { - std::cerr << "[LF] Loop " << header->GetName() - << " has " << store_insts.size() << " stores in " - << num_groups << " groups" << std::endl; - } - - std::vector> group_insts(num_groups); - for (size_t i = 0; i < store_insts.size(); ++i) - { - int gid = group_id[i]; - for (auto *inst : store_chains[i]) - { - group_insts[gid].insert(inst); - } - } - - for (auto *inst : all_body) - { - bool found = false; - for (auto &group : group_insts) - { - if (group.count(inst)) - { - found = true; - break; - } - } - if (!found) - { - group_insts[0].insert(inst); - } - } - - std::vector> group_ordered(num_groups); - for (auto *inst : body_order) - { - for (int g = 0; g < num_groups; ++g) - { - if (group_insts[g].count(inst)) - { - group_ordered[g].push_back(inst); - break; - } - } - } - - std::vector first_group_insts = group_ordered[0]; - std::vector other_group_insts; - for (int g = 1; g < num_groups; ++g) - { - for (auto *inst : group_ordered[g]) - { - other_group_insts.push_back(inst); - } - } - - if (other_group_insts.empty()) - continue; - - bool first_group_stores_to_array = false; - for (auto *inst : first_group_insts) - { - auto *store = dynamic_cast(inst); - if (store) - { - auto *ptr = store->GetPtr(); - if (ptr && dynamic_cast(ptr)) - { - first_group_stores_to_array = true; - break; - } - } - } - - bool other_group_stores_to_array = false; - for (auto *inst : other_group_insts) - { - auto *store = dynamic_cast(inst); - if (store) - { - auto *ptr = store->GetPtr(); - if (ptr && dynamic_cast(ptr)) - { - other_group_stores_to_array = true; - break; - } - } - } - - if (!first_group_stores_to_array || !other_group_stores_to_array) - continue; - - if (kDebugLF) - { - std::cerr << "[LF] Fissioning loop " << header->GetName() - << " into 2 loops (first=" << first_group_insts.size() - << " insts, other=" << other_group_insts.size() << " insts)" << std::endl; - } - - auto *new_header = func->CreateBlock(header->GetName() + std::string(".fission")); - auto *new_phi = new_header->Prepend(iv.phi->GetType(), ctx.NextTemp()); - new_phi->AddOperand(iv.init_val); - new_phi->AddOperand(iv.init_block); - - std::unordered_map value_map; - value_map[iv.phi] = new_phi; - - for (auto *inst : other_group_insts) - { - auto cloned = CloneInstruction(inst, ctx, value_map); - if (cloned) - { - value_map[inst] = cloned.get(); - new_header->InsertInstructionBeforeTerminator(std::move(cloned)); - } - } - - auto *new_step_const = ctx.GetConstInt(step_v); - auto new_step = std::make_unique( - Opcode::Add, new_phi->GetType(), new_phi, new_step_const, ctx.NextTemp()); - auto *new_step_ptr = new_step.get(); - new_header->InsertInstructionBeforeTerminator(std::move(new_step)); - - new_phi->AddOperand(new_step_ptr); - new_phi->AddOperand(new_header); - - auto *cond_inst = dynamic_cast(cond_br->GetCond()); - Value *new_cond = nullptr; - if (cond_inst) - { - auto *lhs_orig = cond_inst->GetLhs(); - auto *rhs_orig = cond_inst->GetRhs(); - auto *lhs = value_map.count(lhs_orig) ? value_map[lhs_orig] : lhs_orig; - auto *rhs = value_map.count(rhs_orig) ? value_map[rhs_orig] : rhs_orig; - auto new_cmp = std::make_unique( - cond_inst->GetOpcode(), cond_inst->GetType(), lhs, rhs, ctx.NextTemp()); - new_cond = new_cmp.get(); - new_header->InsertInstructionBeforeTerminator(std::move(new_cmp)); - } - - if (!new_cond) - new_cond = cond_br->GetCond(); - - auto new_br = std::make_unique( - Type::GetVoidType(), new_cond, new_header, exit_block); - new_header->InsertInstructionBeforeTerminator(std::move(new_br)); - - for (auto *inst : other_group_insts) - { - auto owned = header->TakeInstruction(inst); - } - - auto *old_br = dynamic_cast(header->GetInstructions().back().get()); - if (old_br) - { - auto old_br_owned = header->TakeInstruction(old_br); - auto new_orig_br = std::make_unique( - Type::GetVoidType(), old_br->GetCond(), new_header, exit_block); - header->InsertInstructionBeforeTerminator(std::move(new_orig_br)); - } - - if (kDebugLF) - { - std::cerr << "[LF] Created fission loop " << new_header->GetName() - << " with " << other_group_insts.size() << " instructions" << std::endl; - } - } - } - - } + } // namespace void RunLICM(Module *module) { @@ -1536,46 +611,4 @@ namespace ir } } - void RunStrengthReduction(Module *module) - { - if (!module) - return; - - for (auto &func : module->GetFunctions()) - { - if (func && !func->IsExternal()) - { - RunStrengthReductionOnFunction(func.get(), module); - } - } - } - - void RunLoopUnrolling(Module *module) - { - if (!module) - return; - - for (auto &func : module->GetFunctions()) - { - if (func && !func->IsExternal()) - { - RunLoopUnrollingOnFunction(func.get(), module); - } - } - } - - void RunLoopFission(Module *module) - { - if (!module) - return; - - for (auto &func : module->GetFunctions()) - { - if (func && !func->IsExternal()) - { - RunLoopFissionOnFunction(func.get(), module); - } - } - } - -} +} // namespace ir diff --git a/src/ir/passes/Inline.cpp b/src/ir/passes/Inline.cpp deleted file mode 100644 index f396ec09..00000000 --- a/src/ir/passes/Inline.cpp +++ /dev/null @@ -1,621 +0,0 @@ -#include "ir/IR.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ir { - -namespace { - -constexpr bool kDebugInline = false; -constexpr int kMaxInlineSize = 200; -constexpr int kMaxMultiBlockInlineSize = 50; - -bool IsRecursive(Function* func) { - if (!func || func->IsExternal()) return true; - for (auto& bb : func->GetBlocks()) { - for (auto& inst : bb->GetInstructions()) { - if (auto* call = dynamic_cast(inst.get())) { - if (call->GetCallee() == func) return true; - } - } - } - return false; -} - -int CountInstructions(Function* func) { - int count = 0; - for (auto& bb : func->GetBlocks()) { - count += bb->GetInstructions().size(); - } - return count; -} - -Value* MapValue(Value* v, const std::unordered_map& value_map) { - auto it = value_map.find(v); - if (it != value_map.end()) return it->second; - return v; -} - -void CloneInstruction(Instruction* inst, - const std::unordered_map& value_map, - std::vector>& out) { - std::unique_ptr cloned; - - switch (inst->GetOpcode()) { - case Opcode::Add: - case Opcode::Sub: - case Opcode::Mul: - case Opcode::Div: - case Opcode::Mod: - case Opcode::Eq: - case Opcode::Ne: - case Opcode::Lt: - case Opcode::Le: - case Opcode::Gt: - case Opcode::Ge: { - auto* bin = static_cast(inst); - Value* lhs = MapValue(bin->GetLhs(), value_map); - Value* rhs = MapValue(bin->GetRhs(), value_map); - cloned = std::make_unique( - inst->GetOpcode(), inst->GetType(), lhs, rhs, - inst->GetName() + ".inl"); - break; - } - case Opcode::SIToFP: - case Opcode::FPToSI: - case Opcode::ZExt: { - auto* cast = static_cast(inst); - Value* operand = MapValue(cast->GetOperandValue(), value_map); - cloned = std::make_unique( - inst->GetOpcode(), inst->GetType(), operand, - inst->GetName() + ".inl"); - break; - } - case Opcode::Load: { - auto* load = static_cast(inst); - Value* ptr = MapValue(load->GetPtr(), value_map); - cloned = std::make_unique( - load->GetType(), ptr, inst->GetName() + ".inl"); - break; - } - case Opcode::Store: { - auto* store = static_cast(inst); - Value* val = MapValue(store->GetValue(), value_map); - Value* ptr = MapValue(store->GetPtr(), value_map); - cloned = std::make_unique(Type::GetVoidType(), val, ptr); - break; - } - case Opcode::GEP: { - auto* gep = static_cast(inst); - Value* base = MapValue(gep->GetBasePtr(), value_map); - Value* index = MapValue(gep->GetIndex(), value_map); - cloned = std::make_unique( - gep->GetType(), base, index, inst->GetName() + ".inl"); - break; - } - case Opcode::Call: { - auto* orig_call = static_cast(inst); - Function* callee_func = orig_call->GetCallee(); - std::vector args; - for (size_t i = 0; i < orig_call->GetNumArgs(); ++i) { - args.push_back(MapValue(orig_call->GetArg(i), value_map)); - } - cloned = std::make_unique( - orig_call->GetType(), callee_func, args, - inst->GetName() + ".inl"); - break; - } - case Opcode::Alloca: { - auto* alloca_inst = static_cast(inst); - if (alloca_inst->IsArrayAlloca()) { - Value* count = MapValue(alloca_inst->GetCount(), value_map); - cloned = std::make_unique( - alloca_inst->GetElementType(), - alloca_inst->GetName() + ".inl", count); - } else { - cloned = std::make_unique( - alloca_inst->GetElementType(), - alloca_inst->GetName() + ".inl"); - } - break; - } - default: - break; - } - - if (cloned) { - out.push_back(std::move(cloned)); - } -} - -bool InlineCall(CallInst* call, Function* callee, Function* caller, - BasicBlock* call_bb, Module* module) { - if (kDebugInline) { - std::cerr << "[Inline] Inlining " << callee->GetName() - << " (" << callee->GetBlocks().size() << " blocks)" - << " into " << caller->GetName() << std::endl; - } - - bool is_single_block = (callee->GetBlocks().size() == 1); - - std::unordered_map value_map; - - for (auto& gv : module->GetGlobals()) { - value_map[gv.get()] = gv.get(); - } - for (auto& other_func : module->GetFunctions()) { - value_map[other_func.get()] = other_func.get(); - } - for (auto& arg : caller->GetParams()) { - value_map[arg.get()] = arg.get(); - } - { - auto& blocks = caller->GetBlocks(); - for (size_t bi = 0; bi < blocks.size(); ++bi) { - auto& insts = blocks[bi]->GetInstructions(); - for (size_t ii = 0; ii < insts.size(); ++ii) { - value_map[insts[ii].get()] = insts[ii].get(); - } - } - } - - for (size_t i = 0; i < callee->GetParams().size(); ++i) { - auto* formal_arg = callee->GetParams()[i].get(); - auto* actual_arg = call->GetArg(i); - value_map[formal_arg] = actual_arg; - } - - auto& call_bb_insts = const_cast>&>( - call_bb->GetInstructions()); - - size_t call_idx = 0; - for (size_t i = 0; i < call_bb_insts.size(); ++i) { - if (call_bb_insts[i].get() == call) { - call_idx = i; - break; - } - } - - if (is_single_block) { - auto* callee_entry = callee->GetEntry(); - Value* return_value = nullptr; - - std::vector> cloned_insts; - std::vector> alloca_insts; - - for (auto& inst : callee_entry->GetInstructions()) { - if (inst->GetOpcode() == Opcode::Alloca) { - std::vector> tmp; - CloneInstruction(inst.get(), value_map, tmp); - if (!tmp.empty()) { - value_map[inst.get()] = tmp.back().get(); - alloca_insts.push_back(std::move(tmp.back())); - } - continue; - } - - if (inst->GetOpcode() == Opcode::Ret) { - auto* ret_inst = static_cast(inst.get()); - if (ret_inst->HasValue()) { - return_value = MapValue(ret_inst->GetValue(), value_map); - } - continue; - } - - std::vector> tmp; - CloneInstruction(inst.get(), value_map, tmp); - if (!tmp.empty()) { - value_map[inst.get()] = tmp.back().get(); - cloned_insts.push_back(std::move(tmp.back())); - } - } - - if (return_value) { - call->ReplaceAllUsesWith(return_value); - } else if (!call->GetType()->IsVoid()) { - call->ReplaceAllUsesWith(module->GetContext().GetConstInt(0)); - } - - auto* entry_bb = caller->GetEntry(); - auto& entry_insts = const_cast>&>( - entry_bb->GetInstructions()); - size_t alloca_insert_pos = 0; - for (size_t i = 0; i < entry_insts.size(); ++i) { - if (entry_insts[i]->GetOpcode() == Opcode::Alloca) { - alloca_insert_pos = i + 1; - } else { - break; - } - } - for (auto& alloca : alloca_insts) { - alloca->SetParent(entry_bb); - entry_insts.insert(entry_insts.begin() + alloca_insert_pos, std::move(alloca)); - alloca_insert_pos++; - } - - size_t insert_pos = call_idx; - for (auto& cloned : cloned_insts) { - cloned->SetParent(call_bb); - call_bb_insts.insert(call_bb_insts.begin() + insert_pos, std::move(cloned)); - insert_pos++; - } - - for (size_t i = 0; i < call_bb_insts.size(); ++i) { - if (call_bb_insts[i].get() == call) { - for (size_t oi = 0; oi < call->GetNumOperands(); ++oi) { - auto* op = call->GetOperand(oi); - if (auto* op_inst = dynamic_cast(op)) { - op_inst->RemoveUse(call, oi); - } - } - call_bb_insts.erase(call_bb_insts.begin() + i); - break; - } - } - - return true; - } - - // === Multi-block inlining === - - // 1. Create after_bb: move instructions after call from call_bb to after_bb - BasicBlock* after_bb = caller->CreateBlock(call_bb->GetName() + ".after"); - - std::vector> after_insts; - for (size_t i = call_idx + 1; i < call_bb_insts.size(); ++i) { - after_insts.push_back(std::move(call_bb_insts[i])); - } - call_bb_insts.resize(call_idx + 1); - - for (auto& inst : after_insts) { - inst->SetParent(after_bb); - after_bb->GetMutablePredecessors(); - } - auto& after_bb_insts = const_cast>&>( - after_bb->GetInstructions()); - for (auto& inst : after_insts) { - after_bb_insts.push_back(std::move(inst)); - } - - // 1b. Fix phi nodes: any phi that had call_bb as predecessor should now use after_bb - for (auto& bb : caller->GetBlocks()) { - for (auto& inst : bb->GetInstructions()) { - if (inst->GetOpcode() != Opcode::Phi) break; - auto* phi = static_cast(inst.get()); - size_t num_ops = phi->GetNumOperands(); - for (size_t i = 0; i + 1 < num_ops; i += 2) { - auto* bb_ptr = dynamic_cast(phi->GetOperand(i + 1)); - if (bb_ptr == call_bb) { - phi->SetOperand(i + 1, after_bb); - } - } - } - } - - // 2. Create cloned blocks for callee - std::unordered_map bb_map; - std::vector cloned_bbs; - for (auto& bb : callee->GetBlocks()) { - BasicBlock* cloned_bb = caller->CreateBlock(bb->GetName() + ".inl"); - bb_map[bb.get()] = cloned_bb; - cloned_bbs.push_back(cloned_bb); - } - BasicBlock* cloned_entry = bb_map[callee->GetEntry()]; - - // 2b. Reorder blocks: move cloned blocks and after_bb right after call_bb - // IMPORTANT: after_bb must come AFTER all cloned blocks, because - // after_bb may use values defined in the cloned blocks (e.g., call results - // from nested inlines). The lowering processes blocks in order, so values - // must be defined before they are used. - { - auto& blocks = const_cast>&>(caller->GetBlocks()); - std::vector move_indices; - for (auto* cb : cloned_bbs) { - for (size_t i = 0; i < blocks.size(); ++i) { - if (blocks[i].get() == cb) { move_indices.push_back(i); break; } - } - } - for (size_t i = 0; i < blocks.size(); ++i) { - if (blocks[i].get() == after_bb) { move_indices.push_back(i); break; } - } - - size_t call_bb_idx = 0; - for (size_t i = 0; i < blocks.size(); ++i) { - if (blocks[i].get() == call_bb) { call_bb_idx = i; break; } - } - - std::vector> extracted; - for (auto idx : move_indices) { - extracted.push_back(std::move(blocks[idx])); - } - - size_t insert_pos = call_bb_idx + 1; - for (auto& b : extracted) { - blocks.insert(blocks.begin() + insert_pos, std::move(b)); - insert_pos++; - } - - blocks.erase(std::remove_if(blocks.begin(), blocks.end(), - [](const std::unique_ptr& b) { return b == nullptr; }), - blocks.end()); - } - - // 4. Create alloca for return value (if non-void) - AllocaInst* ret_alloca = nullptr; - bool has_return = !call->GetType()->IsVoid(); - if (has_return) { - auto* entry_bb = caller->GetEntry(); - auto& entry_insts = const_cast>&>( - entry_bb->GetInstructions()); - auto alloca = std::make_unique(call->GetType(), "__ret.inl"); - alloca->SetParent(entry_bb); - ret_alloca = static_cast(alloca.get()); - size_t alloca_insert_pos = 0; - for (size_t i = 0; i < entry_insts.size(); ++i) { - if (entry_insts[i]->GetOpcode() == Opcode::Alloca) { - alloca_insert_pos = i + 1; - } else { - break; - } - } - entry_insts.insert(entry_insts.begin() + alloca_insert_pos, std::move(alloca)); - } - - // 5. Clone all instructions from callee blocks into cloned blocks - // Pass 1: Create cloned instructions with original operands, build value_map - std::vector> alloca_insts; - std::vector> remap_list; - - for (auto& bb : callee->GetBlocks()) { - BasicBlock* cloned_bb = bb_map[bb.get()]; - auto& cloned_insts = const_cast>&>( - cloned_bb->GetInstructions()); - - for (auto& inst : bb->GetInstructions()) { - if (inst->GetOpcode() == Opcode::Alloca) { - std::vector> tmp; - CloneInstruction(inst.get(), value_map, tmp); - if (!tmp.empty()) { - value_map[inst.get()] = tmp.back().get(); - alloca_insts.push_back(std::move(tmp.back())); - } - continue; - } - - if (inst->GetOpcode() == Opcode::Phi) { - auto* phi = static_cast(inst.get()); - auto new_phi = std::make_unique(phi->GetType(), phi->GetName() + ".inl"); - new_phi->SetParent(cloned_bb); - value_map[inst.get()] = new_phi.get(); - cloned_insts.push_back(std::move(new_phi)); - continue; - } - - if (inst->IsTerminator()) continue; - - std::vector> tmp; - CloneInstruction(inst.get(), value_map, tmp); - if (!tmp.empty()) { - tmp.back()->SetParent(cloned_bb); - value_map[inst.get()] = tmp.back().get(); - remap_list.push_back({inst.get(), tmp.back().get()}); - cloned_insts.push_back(std::move(tmp.back())); - } - } - } - - // Pass 1b: Remap operands of cloned instructions now that value_map is complete - for (auto& [orig, cloned] : remap_list) { - for (size_t i = 0; i < orig->GetNumOperands(); ++i) { - Value* orig_op = orig->GetOperand(i); - Value* mapped = MapValue(orig_op, value_map); - if (mapped != orig_op) { - cloned->SetOperand(i, mapped); - } - } - } - - // Pass 2: fill phi operands and handle terminators - for (auto& bb : callee->GetBlocks()) { - BasicBlock* cloned_bb = bb_map[bb.get()]; - auto& cloned_insts = const_cast>&>( - cloned_bb->GetInstructions()); - - for (auto& inst : bb->GetInstructions()) { - if (inst->GetOpcode() == Opcode::Phi) { - auto* orig_phi = static_cast(inst.get()); - auto* cloned_phi = static_cast(value_map[orig_phi]); - if (!cloned_phi) continue; - - for (size_t i = 0; i < orig_phi->GetNumOperands(); i += 2) { - Value* val = MapValue(orig_phi->GetOperand(i), value_map); - auto* orig_pred = static_cast(orig_phi->GetOperand(i + 1)); - auto pred_it = bb_map.find(orig_pred); - BasicBlock* pred = (pred_it != bb_map.end()) ? pred_it->second : orig_pred; - cloned_phi->AddOperand(val); - cloned_phi->AddOperand(pred); - } - continue; - } - - if (inst->GetOpcode() == Opcode::Ret) { - auto* ret_inst = static_cast(inst.get()); - if (ret_inst->HasValue() && has_return) { - Value* ret_val = MapValue(ret_inst->GetValue(), value_map); - auto store = std::make_unique( - Type::GetVoidType(), ret_val, ret_alloca); - store->SetParent(cloned_bb); - cloned_insts.push_back(std::move(store)); - } - auto br = std::make_unique(Type::GetVoidType(), after_bb); - br->SetParent(cloned_bb); - cloned_insts.push_back(std::move(br)); - continue; - } - - if (inst->GetOpcode() == Opcode::Br) { - auto* br = static_cast(inst.get()); - auto it = bb_map.find(br->GetTarget()); - BasicBlock* target = (it != bb_map.end()) ? it->second : br->GetTarget(); - auto new_br = std::make_unique(Type::GetVoidType(), target); - new_br->SetParent(cloned_bb); - cloned_insts.push_back(std::move(new_br)); - continue; - } - - if (inst->GetOpcode() == Opcode::CondBr) { - auto* cbr = static_cast(inst.get()); - Value* cond = MapValue(cbr->GetCond(), value_map); - auto true_it = bb_map.find(cbr->GetTrueTarget()); - BasicBlock* true_target = (true_it != bb_map.end()) ? true_it->second : cbr->GetTrueTarget(); - auto false_it = bb_map.find(cbr->GetFalseTarget()); - BasicBlock* false_target = (false_it != bb_map.end()) ? false_it->second : cbr->GetFalseTarget(); - auto new_cbr = std::make_unique( - Type::GetVoidType(), cond, true_target, false_target); - new_cbr->SetParent(cloned_bb); - cloned_insts.push_back(std::move(new_cbr)); - continue; - } - } - } - - // 7. Insert alloca_insts into caller entry - { - auto* entry_bb = caller->GetEntry(); - auto& entry_insts = const_cast>&>( - entry_bb->GetInstructions()); - size_t alloca_insert_pos = 0; - for (size_t i = 0; i < entry_insts.size(); ++i) { - if (entry_insts[i]->GetOpcode() == Opcode::Alloca) { - alloca_insert_pos = i + 1; - } else { - break; - } - } - for (auto& alloca : alloca_insts) { - alloca->SetParent(entry_bb); - entry_insts.insert(entry_insts.begin() + alloca_insert_pos, std::move(alloca)); - alloca_insert_pos++; - } - } - - // 8-9. Handle return value and remove call - auto call_type = call->GetType(); - - if (has_return) { - auto load_ret = std::make_unique( - call_type, ret_alloca, "__ret.load.inl"); - load_ret->SetParent(after_bb); - Value* ret_val = load_ret.get(); - after_bb_insts.insert(after_bb_insts.begin(), std::move(load_ret)); - - call->ReplaceAllUsesWith(ret_val); - } else { - call->ReplaceAllUsesWith(module->GetContext().GetConstInt(0)); - } - - // Remove the call and add branch to cloned_entry - for (size_t i = 0; i < call_bb_insts.size(); ++i) { - if (call_bb_insts[i].get() == call) { - for (size_t oi = 0; oi < call->GetNumOperands(); ++oi) { - auto* op = call->GetOperand(oi); - if (auto* op_inst = dynamic_cast(op)) { - op_inst->RemoveUse(call, oi); - } - } - call_bb_insts.erase(call_bb_insts.begin() + i); - break; - } - } - - auto br_to_entry = std::make_unique(Type::GetVoidType(), cloned_entry); - br_to_entry->SetParent(call_bb); - call_bb_insts.push_back(std::move(br_to_entry)); - - if (kDebugInline) { - std::cerr << "[Inline] Done inlining " << callee->GetName() << std::endl; - } - - return true; -} - -} // namespace - -void RunInline(Module* module) { - if (!module) return; - - std::unordered_map func_sizes; - std::unordered_set recursive_funcs; - - for (auto& func : module->GetFunctions()) { - if (func->IsExternal()) continue; - func_sizes[func->GetName()] = CountInstructions(func.get()); - if (IsRecursive(func.get())) { - recursive_funcs.insert(func->GetName()); - } - } - - struct InlineSite { - CallInst* call; - Function* caller; - BasicBlock* call_bb; - }; - - std::vector inline_sites; - - for (auto& caller : module->GetFunctions()) { - if (caller->IsExternal()) continue; - - for (auto& bb : caller->GetBlocks()) { - for (auto& inst : bb->GetInstructions()) { - auto* call = dynamic_cast(inst.get()); - if (!call) continue; - - auto* callee = call->GetCallee(); - if (!callee) continue; - if (callee->IsExternal()) continue; - if (recursive_funcs.count(callee->GetName())) continue; - - auto size_it = func_sizes.find(callee->GetName()); - int callee_size = (size_it != func_sizes.end()) ? size_it->second : 9999; - - if (callee_size > kMaxInlineSize) continue; - if (callee == caller.get()) continue; - if (callee->GetBlocks().size() > 1 && callee_size > kMaxMultiBlockInlineSize) continue; - - inline_sites.push_back({call, caller.get(), bb.get()}); - } - } - } - - for (auto& site : inline_sites) { - auto* callee = site.call->GetCallee(); - if (!callee) continue; - - bool still_valid = false; - BasicBlock* actual_bb = nullptr; - for (auto& bb : site.caller->GetBlocks()) { - for (auto& inst : bb->GetInstructions()) { - if (inst.get() == site.call) { - still_valid = true; - actual_bb = bb.get(); - break; - } - } - if (still_valid) break; - } - if (!still_valid) continue; - - InlineCall(site.call, callee, site.caller, actual_bb, module); - } -} - -} // namespace ir