|
|
|
|
@ -1,7 +1,7 @@
|
|
|
|
|
// 保守函数内联:
|
|
|
|
|
// - 自底向上迭代内联,每次只内联无调用(leaf)的单基本块函数
|
|
|
|
|
// - 内联前先将 if-else-return 函数转为 mul select + ret(单 BB)
|
|
|
|
|
// - 内联后消除外层函数的 call,使其可能变为新 leaf,迭代至收敛
|
|
|
|
|
// - 每个函数内反复扫描直到清空所有可内联 call,4 轮即可收敛
|
|
|
|
|
|
|
|
|
|
#include "ir/IR.h"
|
|
|
|
|
|
|
|
|
|
@ -26,8 +26,6 @@ bool IsInlineable(Function* func) {
|
|
|
|
|
|
|
|
|
|
for (const auto& inst : insts) {
|
|
|
|
|
if (inst->GetOpcode() == Opcode::Call) return false;
|
|
|
|
|
// 只内联纯算术/逻辑函数,不内联含内存操作的函数
|
|
|
|
|
// Load/Store/GEP 的函数内联可能导致全局变量副作用顺序问题
|
|
|
|
|
if (inst->GetOpcode() == Opcode::Load ||
|
|
|
|
|
inst->GetOpcode() == Opcode::Store ||
|
|
|
|
|
inst->GetOpcode() == Opcode::GEP)
|
|
|
|
|
@ -57,7 +55,8 @@ std::unique_ptr<Instruction> CloneInst(
|
|
|
|
|
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: {
|
|
|
|
|
case Opcode::Le: case Opcode::Gt: case Opcode::Ge:
|
|
|
|
|
case Opcode::And: case Opcode::Or: {
|
|
|
|
|
auto* bin = static_cast<BinaryInst*>(inst);
|
|
|
|
|
return std::make_unique<BinaryInst>(op, inst->GetType(),
|
|
|
|
|
map(bin->GetLhs()),
|
|
|
|
|
@ -114,13 +113,11 @@ bool InlineCall(CallInst* call, Function* callee, Context& ctx) {
|
|
|
|
|
|
|
|
|
|
if (callee == caller) return false;
|
|
|
|
|
|
|
|
|
|
// 1. 构建值映射:被调用者参数 -> 调用实参
|
|
|
|
|
std::unordered_map<Value*, Value*> value_map;
|
|
|
|
|
const auto& params = callee->GetParams();
|
|
|
|
|
for (size_t i = 0; i < params.size(); ++i)
|
|
|
|
|
value_map[params[i].get()] = call->GetArg(i);
|
|
|
|
|
|
|
|
|
|
// 2. 克隆被调用者指令(Ret 除外),用 InsertBefore 插入到 call 之前
|
|
|
|
|
Value* ret_val = nullptr;
|
|
|
|
|
const auto& callee_insts = callee->GetEntry()->GetInstructions();
|
|
|
|
|
for (const auto& inst : callee_insts) {
|
|
|
|
|
@ -138,17 +135,89 @@ bool InlineCall(CallInst* call, Function* callee, Context& ctx) {
|
|
|
|
|
bb->InsertBefore(call, std::move(cloned));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 替换 call 的使用并删除
|
|
|
|
|
if (ret_val) call->ReplaceAllUsesWith(ret_val);
|
|
|
|
|
call->ClearOperands(); // 清理操作数的 use 记录,防止悬空指针
|
|
|
|
|
call->ClearOperands();
|
|
|
|
|
bb->TakeInstruction(call);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将 if-else-return 函数转为单 BB mul select
|
|
|
|
|
// BB0(cmp+condbr) → BB1(ret tv), BB2(ret fv)
|
|
|
|
|
// → BB0: zext+sub+mul+add+ret (即 fv + (tv-fv)*zext(cmp))
|
|
|
|
|
static bool TryConvertIfElseToSelect(Function* func, Context& ctx) {
|
|
|
|
|
auto& blocks = func->GetBlocks();
|
|
|
|
|
if (blocks.size() != 3) return false;
|
|
|
|
|
|
|
|
|
|
BasicBlock* entry = func->GetEntry();
|
|
|
|
|
auto& entry_insts = entry->GetInstructions();
|
|
|
|
|
if (entry_insts.empty()) return false;
|
|
|
|
|
|
|
|
|
|
auto* br = dynamic_cast<CondBranchInst*>(entry_insts.back().get());
|
|
|
|
|
if (!br) return false;
|
|
|
|
|
auto* true_bb = br->GetTrueTarget();
|
|
|
|
|
auto* false_bb = br->GetFalseTarget();
|
|
|
|
|
|
|
|
|
|
// 检查两个目标 BB 没有副作用(允许 Load 从 entry alloca 加载)
|
|
|
|
|
auto get_ret_val = [entry](BasicBlock* bb) -> Value* {
|
|
|
|
|
for (const auto& inst : bb->GetInstructions()) {
|
|
|
|
|
auto op = inst->GetOpcode();
|
|
|
|
|
if (op == Opcode::Store || op == Opcode::Call ||
|
|
|
|
|
op == Opcode::GEP || op == Opcode::Alloca)
|
|
|
|
|
return nullptr;
|
|
|
|
|
if (op == Opcode::Load) {
|
|
|
|
|
// 允许 Load(Mem2Reg 跨 BB 的残余),只要不是数组/全局访问
|
|
|
|
|
auto* load = static_cast<LoadInst*>(inst.get());
|
|
|
|
|
auto* ptr = load->GetPtr();
|
|
|
|
|
if (!dynamic_cast<AllocaInst*>(ptr))
|
|
|
|
|
return nullptr;
|
|
|
|
|
// 单标量 alloca 可以接受
|
|
|
|
|
}
|
|
|
|
|
if (op == Opcode::Ret) {
|
|
|
|
|
auto* ret = static_cast<ReturnInst*>(inst.get());
|
|
|
|
|
return ret->HasValue() ? ret->GetValue() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Value* true_val = get_ret_val(true_bb);
|
|
|
|
|
Value* false_val = get_ret_val(false_bb);
|
|
|
|
|
if (!true_val || !false_val) return false;
|
|
|
|
|
|
|
|
|
|
Value* cmp_val = br->GetCond();
|
|
|
|
|
|
|
|
|
|
// 移除 CondBr
|
|
|
|
|
entry->TakeInstruction(br);
|
|
|
|
|
|
|
|
|
|
// 算术 select: fv + (tv - fv) * zext(cmp)
|
|
|
|
|
// zext(cmp: i1 → i32) = 0 or 1
|
|
|
|
|
// sub tv, fv → tv - fv
|
|
|
|
|
// mul (tv-fv), zext → (tv-fv) * cond
|
|
|
|
|
// add fv, masked → fv + (tv-fv)*cond = cond ? tv : fv
|
|
|
|
|
auto* zext = entry->Append<CastInst>(Opcode::ZExt,
|
|
|
|
|
Type::GetInt32Type(), cmp_val, ctx.NextTemp());
|
|
|
|
|
auto* diff = entry->Append<BinaryInst>(Opcode::Sub, Type::GetInt32Type(),
|
|
|
|
|
true_val, false_val, ctx.NextTemp());
|
|
|
|
|
auto* masked = entry->Append<BinaryInst>(Opcode::Mul, Type::GetInt32Type(),
|
|
|
|
|
diff, zext, ctx.NextTemp());
|
|
|
|
|
auto* result = entry->Append<BinaryInst>(Opcode::Add, Type::GetInt32Type(),
|
|
|
|
|
false_val, masked, ctx.NextTemp());
|
|
|
|
|
|
|
|
|
|
// 替换为 ret(true_bb/false_bb 变为不可达,后续 CFG 优化清理)
|
|
|
|
|
entry->Append<ReturnInst>(Type::GetVoidType(), result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
void RunInline(Module& module) {
|
|
|
|
|
// 先将 if-else-return 函数转为单 BB,使其可被内联
|
|
|
|
|
for (const auto& func : module.GetFunctions()) {
|
|
|
|
|
if (!func->IsExternal())
|
|
|
|
|
TryConvertIfElseToSelect(func.get(), module.GetContext());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int inlined = 0;
|
|
|
|
|
bool changed = true;
|
|
|
|
|
int round = 0;
|
|
|
|
|
@ -164,7 +233,6 @@ void RunInline(Module& module) {
|
|
|
|
|
}
|
|
|
|
|
if (inlineable.empty()) break;
|
|
|
|
|
|
|
|
|
|
// 每个函数内部反复扫描,直到没有可内联的 call 为止
|
|
|
|
|
for (const auto& func : module.GetFunctions()) {
|
|
|
|
|
if (func->IsExternal()) continue;
|
|
|
|
|
|
|
|
|
|
@ -183,7 +251,7 @@ void RunInline(Module& module) {
|
|
|
|
|
++inlined;
|
|
|
|
|
func_changed = true;
|
|
|
|
|
changed = true;
|
|
|
|
|
break; // 指令列表已修改,重新扫描当前函数
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (func_changed) break;
|
|
|
|
|
}
|
|
|
|
|
|