[midend-tco]添加TCO尾递归优化

This commit is contained in:
2025-08-18 23:46:00 +08:00
parent ad74e435ba
commit 937833117e
5 changed files with 196 additions and 3 deletions

View File

@ -634,6 +634,22 @@ void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
}
}
}
// 8. 消除无用移动指令: mv a, a -> (删除)
else if (mi1->getOpcode() == RVOpcodes::MV &&
mi1->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
auto *dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *src = static_cast<RegOperand *>(mi1->getOperands()[1].get());
// 检查源和目标寄存器是否相同
if (areRegsEqual(dst, src)) {
// 删除这条无用指令
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
// 根据是否发生变化调整遍历索引
if (!changed) {

View File

@ -0,0 +1,39 @@
#pragma once
#include "Pass.h"
#include "Dom.h"
#include "Loop.h"
namespace sysy {
/**
* @class TailCallOpt
* @brief 优化尾调用的中端优化通道。
*
* 该类实现了一个针对函数级别的尾调用优化的优化通道OptimizationPass
* 通过分析和转换 IR中间表示将可优化的尾调用转换为更高效的形式
* 以减少函数调用的开销,提升程序性能。
*
* @note 需要传入 IRBuilder 指针用于 IR 构建和修改。
*
* @method runOnFunction
* 对指定函数进行尾调用优化。
*
* @method getPassID
* 获取当前优化通道的唯一标识符。
*
* @method getAnalysisUsage
* 指定该优化通道所依赖和失效的分析集合。
*/
class TailCallOpt : public OptimizationPass {
private:
IRBuilder* builder;
public:
TailCallOpt(IRBuilder* builder) : OptimizationPass("TailCallOpt", Granularity::Function), builder(builder) {}
static void *ID;
bool runOnFunction(Function *F, AnalysisManager &AM) override;
void *getPassID() const override { return &ID; }
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
};
} // namespace sysy

View File

@ -25,6 +25,7 @@ add_library(midend_lib STATIC
Pass/Optimize/GlobalStrengthReduction.cpp
Pass/Optimize/BuildCFG.cpp
Pass/Optimize/LargeArrayToGlobal.cpp
Pass/Optimize/TailCallOpt.cpp
)
# 包含中端模块所需的头文件路径

View File

@ -0,0 +1,125 @@
#include "TailCallOpt.h"
#include "IR.h"
#include "IRBuilder.h"
#include "SysYIROptUtils.h"
#include <vector>
// #include <iostream>
#include <algorithm>
namespace sysy {
void *TailCallOpt::ID = (void *)&TailCallOpt::ID;
void TailCallOpt::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
analysisInvalidations.insert(&LoopAnalysisPass::ID);
}
bool TailCallOpt::runOnFunction(Function *F, AnalysisManager &AM) {
std::vector<CallInst *> tailCallInsts;
// 遍历函数的所有基本块
for (auto &bb_ptr : F->getBasicBlocks()) {
auto BB = bb_ptr.get();
if (BB->getInstructions().empty()) continue; // 跳过空基本块
auto term_iter = BB->terminator();
if (term_iter == BB->getInstructions().end()) continue; // 没有终结指令则跳过
auto term = (*term_iter).get();
if (!term || !term->isReturn()) continue; // 不是返回指令则跳过
auto retInst = static_cast<ReturnInst *>(term);
Instruction *prevInst = nullptr;
if (BB->getInstructions().size() > 1) {
auto it = term_iter;
--it; // 获取返回指令前的指令
prevInst = (*it).get();
}
if (!prevInst || !prevInst->isCall()) continue; // 前一条不是调用指令则跳过
auto callInst = static_cast<CallInst *>(prevInst);
// 检查是否为尾递归调用:被调用函数与当前函数相同且返回值与调用结果匹配
if (callInst->getCallee() == F) {
// 对于尾递归,返回值应为调用结果或为 void 类型
if (retInst->getReturnValue() == callInst ||
(retInst->getReturnValue() == nullptr && callInst->getType()->isVoid())) {
tailCallInsts.push_back(callInst);
}
}
}
if (tailCallInsts.empty()) {
return false;
}
// 创建一个新的入口基本块,作为循环的前置块
auto original_entry = F->getEntryBlock();
auto new_entry = F->addBasicBlock("tco.entry");
auto loop_header = F->addBasicBlock("tco.loop_header");
// 将原入口块中的所有指令移动到循环头块
loop_header->getInstructions().splice(loop_header->end(), original_entry->getInstructions());
original_entry->setName("tco.pre_header");
// 为函数参数创建 phi 节点
builder->setPosition(loop_header, loop_header->begin());
std::vector<PhiInst *> phis;
auto original_args = F->getArguments();
for (auto &arg : original_args) {
auto phi = builder->createPhiInst(arg->getType(), {}, {}, "tco.phi."+arg->getName());
phis.push_back(phi);
}
// 用 phi 节点替换所有原始参数的使用
for (size_t i = 0; i < original_args.size(); ++i) {
original_args[i]->replaceAllUsesWith(phis[i]);
}
// 设置 phi 节点的输入值
for (size_t i = 0; i < phis.size(); ++i) {
phis[i]->addIncoming(original_args[i], new_entry);
}
// 连接各个基本块
builder->setPosition(original_entry, original_entry->end());
builder->createUncondBrInst(new_entry);
original_entry->addSuccessor(new_entry);
builder->setPosition(new_entry, new_entry->end());
builder->createUncondBrInst(loop_header);
new_entry->addSuccessor(loop_header);
loop_header->addPredecessor(new_entry);
// 处理每一个尾递归调用
for (auto callInst : tailCallInsts) {
auto tail_call_block = callInst->getParent();
// 收集尾递归调用的参数
auto args_range = callInst->getArguments();
std::vector<Value*> args;
std::transform(args_range.begin(), args_range.end(), std::back_inserter(args),
[](auto& use_ptr){ return use_ptr->getValue(); });
// 用新的参数值更新 phi 节点
for (size_t i = 0; i < phis.size(); ++i) {
phis[i]->addIncoming(args[i], tail_call_block);
}
// 移除原有的调用和返回指令
auto term_iter = tail_call_block->terminator();
SysYIROptUtils::usedelete(term_iter);
auto call_iter = tail_call_block->findInstIterator(callInst);
SysYIROptUtils::usedelete(call_iter);
// 添加跳转回循环头块的分支指令
builder->setPosition(tail_call_block, tail_call_block->end());
builder->createUncondBrInst(loop_header);
tail_call_block->addSuccessor(loop_header);
loop_header->addPredecessor(tail_call_block);
}
return true;
}
} // namespace sysy

View File

@ -19,6 +19,7 @@
#include "LoopStrengthReduction.h"
#include "InductionVariableElimination.h"
#include "GlobalStrengthReduction.h"
#include "TailCallOpt.h"
#include "Pass.h"
#include <iostream>
#include <queue>
@ -81,6 +82,7 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
registerOptimizationPass<GlobalStrengthReduction>(builderIR);
registerOptimizationPass<Reg2Mem>(builderIR);
registerOptimizationPass<TailCallOpt>(builderIR);
registerOptimizationPass<SCCP>(builderIR);
@ -139,6 +141,16 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
this->addPass(&GVN::ID);
this->run();
this->clearPasses();
this->addPass(&TailCallOpt::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After TailCallOpt ===\n";
SysYPrinter printer(moduleIR);
printer.printIR();
}
if(DEBUG) {
std::cout << "=== IR After GVN Optimizations ===\n";
printPasses();
@ -192,9 +204,9 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
printPasses();
}
// this->clearPasses();
// this->addPass(&Reg2Mem::ID);
// this->run();
this->clearPasses();
this->addPass(&Reg2Mem::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Reg2Mem Optimizations ===\n";