[midend]重构了src目录
This commit is contained in:
202
src/midend/Pass/Analysis/Dom.cpp
Normal file
202
src/midend/Pass/Analysis/Dom.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
#include "Dom.h"
|
||||
#include <limits> // for std::numeric_limits
|
||||
#include <queue>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 初始化 支配树静态 ID
|
||||
void *DominatorTreeAnalysisPass::ID = (void *)&DominatorTreeAnalysisPass::ID;
|
||||
// ==============================================================
|
||||
// DominatorTree 结果类的实现
|
||||
// ==============================================================
|
||||
|
||||
DominatorTree::DominatorTree(Function *F) : AssociatedFunction(F) {
|
||||
// 构造时可以不计算,在分析遍运行里计算并填充
|
||||
}
|
||||
|
||||
const std::set<BasicBlock *> *DominatorTree::getDominators(BasicBlock *BB) const {
|
||||
auto it = Dominators.find(BB);
|
||||
if (it != Dominators.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BasicBlock *DominatorTree::getImmediateDominator(BasicBlock *BB) const {
|
||||
auto it = IDoms.find(BB);
|
||||
if (it != IDoms.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::set<BasicBlock *> *DominatorTree::getDominanceFrontier(BasicBlock *BB) const {
|
||||
auto it = DominanceFrontiers.find(BB);
|
||||
if (it != DominanceFrontiers.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::set<BasicBlock*>* DominatorTree::getDominatorTreeChildren(BasicBlock* BB) const {
|
||||
auto it = DominatorTreeChildren.find(BB);
|
||||
if (it != DominatorTreeChildren.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominators(Function *F) {
|
||||
// 经典的迭代算法计算支配者集合
|
||||
// TODO: 可以替换为更高效的算法,如 Lengauer-Tarjan 算法
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock) {
|
||||
Dominators[bb].insert(bb);
|
||||
} else {
|
||||
for (const auto &all_bb_ptr : F->getBasicBlocks()) {
|
||||
Dominators[bb].insert(all_bb_ptr.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock)
|
||||
continue;
|
||||
|
||||
std::set<BasicBlock *> newDom;
|
||||
bool firstPred = true;
|
||||
for (BasicBlock *pred : bb->getPredecessors()) {
|
||||
if (Dominators.count(pred)) {
|
||||
if (firstPred) {
|
||||
newDom = Dominators[pred];
|
||||
firstPred = false;
|
||||
} else {
|
||||
std::set<BasicBlock *> intersection;
|
||||
std::set_intersection(newDom.begin(), newDom.end(), Dominators[pred].begin(), Dominators[pred].end(),
|
||||
std::inserter(intersection, intersection.begin()));
|
||||
newDom = intersection;
|
||||
}
|
||||
}
|
||||
}
|
||||
newDom.insert(bb);
|
||||
|
||||
if (newDom != Dominators[bb]) {
|
||||
Dominators[bb] = newDom;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DominatorTree::computeIDoms(Function *F) {
|
||||
// 采用与之前类似的简化实现。TODO:Lengauer-Tarjan等算法。
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
IDoms[entryBlock] = nullptr;
|
||||
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock)
|
||||
continue;
|
||||
|
||||
BasicBlock *currentIDom = nullptr;
|
||||
const std::set<BasicBlock *> *domsOfBB = getDominators(bb);
|
||||
if (!domsOfBB)
|
||||
continue;
|
||||
|
||||
for (BasicBlock *D : *domsOfBB) {
|
||||
if (D == bb)
|
||||
continue;
|
||||
|
||||
bool isCandidateIDom = true;
|
||||
for (BasicBlock *candidate : *domsOfBB) {
|
||||
if (candidate == bb || candidate == D)
|
||||
continue;
|
||||
const std::set<BasicBlock *> *domsOfCandidate = getDominators(candidate);
|
||||
if (domsOfCandidate && domsOfCandidate->count(D) == 0 && domsOfBB->count(candidate)) {
|
||||
isCandidateIDom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCandidateIDom) {
|
||||
currentIDom = D;
|
||||
break;
|
||||
}
|
||||
}
|
||||
IDoms[bb] = currentIDom;
|
||||
}
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominanceFrontiers(Function *F) {
|
||||
// 经典的支配边界计算算法
|
||||
for (const auto &bb_ptr_X : F->getBasicBlocks()) {
|
||||
BasicBlock *X = bb_ptr_X.get();
|
||||
DominanceFrontiers[X].clear();
|
||||
|
||||
for (BasicBlock *Y : X->getSuccessors()) {
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<BasicBlock *> *domsOfX = getDominators(X);
|
||||
if (!domsOfX)
|
||||
continue;
|
||||
for (const auto &bb_ptr_Z : F->getBasicBlocks()) {
|
||||
BasicBlock *Z = bb_ptr_Z.get();
|
||||
if (Z == X)
|
||||
continue;
|
||||
const std::set<BasicBlock *> *domsOfZ = getDominators(Z);
|
||||
if (domsOfZ && domsOfZ->count(X) && Z != X) {
|
||||
|
||||
for (BasicBlock *Y : Z->getSuccessors()) {
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominatorTreeChildren(Function *F) {
|
||||
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *B = bb_ptr.get();
|
||||
auto it = getImmediateDominator(B);
|
||||
if (it != nullptr) {
|
||||
BasicBlock *A = it;
|
||||
if (A) {
|
||||
DominatorTreeChildren[A].insert(B);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// DominatorTreeAnalysisPass 的实现
|
||||
// ==============================================================
|
||||
|
||||
|
||||
bool DominatorTreeAnalysisPass::runOnFunction(Function* F, AnalysisManager &AM) {
|
||||
CurrentDominatorTree = std::make_unique<DominatorTree>(F);
|
||||
CurrentDominatorTree->computeDominators(F);
|
||||
CurrentDominatorTree->computeIDoms(F);
|
||||
CurrentDominatorTree->computeDominanceFrontiers(F);
|
||||
CurrentDominatorTree->computeDominatorTreeChildren(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> DominatorTreeAnalysisPass::getResult() {
|
||||
// 返回计算好的 DominatorTree 实例,所有权转移给 AnalysisManager
|
||||
return std::move(CurrentDominatorTree);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
160
src/midend/Pass/Analysis/Liveness.cpp
Normal file
160
src/midend/Pass/Analysis/Liveness.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#include "Liveness.h"
|
||||
#include <algorithm> // For std::set_union, std::set_difference
|
||||
#include <iostream>
|
||||
#include <queue> // Potentially for worklist, though not strictly needed for the iterative approach below
|
||||
#include <set> // For std::set
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 初始化静态 ID
|
||||
void *LivenessAnalysisPass::ID = (void *)&LivenessAnalysisPass::ID;
|
||||
// ==============================================================
|
||||
// LivenessAnalysisResult 结果类的实现
|
||||
// ==============================================================
|
||||
|
||||
const std::set<Value *> *LivenessAnalysisResult::getLiveIn(BasicBlock *BB) const {
|
||||
auto it = liveInSets.find(BB);
|
||||
if (it != liveInSets.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
// 返回一个空集合,表示未找到或不存在
|
||||
static const std::set<Value *> emptySet;
|
||||
return &emptySet;
|
||||
}
|
||||
|
||||
const std::set<Value *> *LivenessAnalysisResult::getLiveOut(BasicBlock *BB) const {
|
||||
auto it = liveOutSets.find(BB);
|
||||
if (it != liveOutSets.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
static const std::set<Value *> emptySet;
|
||||
return &emptySet;
|
||||
}
|
||||
|
||||
void LivenessAnalysisResult::computeDefUse(BasicBlock *BB, std::set<Value *> &def, std::set<Value *> &use) {
|
||||
def.clear(); // 将持有在 BB 中定义的值
|
||||
use.clear(); // 将持有在 BB 中使用但在其定义之前的值
|
||||
|
||||
// 临时集合,用于跟踪当前基本块中已经定义过的变量
|
||||
std::set<Value *> defined_in_block_so_far;
|
||||
|
||||
// 按照指令在块中的顺序遍历
|
||||
for (const auto &inst_ptr : BB->getInstructions()) {
|
||||
Instruction *inst = inst_ptr.get();
|
||||
|
||||
// 1. 处理指令的操作数 (Use) - 在定义之前的使用
|
||||
for (const auto &use_ptr : inst->getOperands()) { // 修正迭代器类型
|
||||
Value *operand = use_ptr->getValue(); // 从 shared_ptr<Use> 获取 Value*
|
||||
|
||||
// 过滤掉常量和全局变量,因为它们通常不被视为活跃变量
|
||||
ConstantValue *constValue = dynamic_cast<ConstantValue *>(operand);
|
||||
GlobalValue *globalValue = dynamic_cast<GlobalValue *>(operand);
|
||||
if (constValue || globalValue) {
|
||||
continue; // 跳过常量和全局变量
|
||||
}
|
||||
|
||||
// 如果操作数是一个变量(Instruction 或 Argument),并且它在此基本块的当前点之前尚未被定义
|
||||
if (defined_in_block_so_far.find(operand) == defined_in_block_so_far.end()) {
|
||||
use.insert(operand);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理指令自身产生的定义 (Def)
|
||||
if (inst->isDefine()) { // 使用 isDefine() 方法
|
||||
// 指令自身定义了一个值。将其添加到块的 def 集合,
|
||||
// 并添加到当前块中已定义的值的临时集合。
|
||||
def.insert(inst); // inst 本身就是被定义的值(例如,虚拟寄存器)
|
||||
defined_in_block_so_far.insert(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LivenessAnalysisResult::computeLiveness(Function *F) {
|
||||
// 每次计算前清空旧结果
|
||||
liveInSets.clear(); // 直接清空 map,不再使用 F 作为键
|
||||
liveOutSets.clear(); // 直接清空 map
|
||||
|
||||
// 初始化所有基本块的 LiveIn 和 LiveOut 集合为空
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
liveInSets[bb] = {}; // 直接以 bb 为键
|
||||
liveOutSets[bb] = {}; // 直接以 bb 为键
|
||||
}
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
|
||||
// TODO : 目前为逆序遍历基本块,考虑反向拓扑序遍历基本块
|
||||
|
||||
// 逆序遍历基本块
|
||||
// std::list<std::unique_ptr<BasicBlock>> basicBlocks(F->getBasicBlocks().begin(), F->getBasicBlocks().end());
|
||||
// std::reverse(basicBlocks.begin(), basicBlocks.end());
|
||||
// 然后遍历 basicBlocks
|
||||
// 创建一个 BasicBlock* 的列表来存储指针,避免拷贝 unique_ptr
|
||||
// Option 1: Using std::vector<BasicBlock*> (preferred for performance with reverse)
|
||||
std::vector<BasicBlock*> basicBlocksPointers;
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
basicBlocksPointers.push_back(bb_ptr.get());
|
||||
}
|
||||
std::reverse(basicBlocksPointers.begin(), basicBlocksPointers.end());
|
||||
|
||||
for (auto bb_iter = basicBlocksPointers.begin(); bb_iter != basicBlocksPointers.end(); ++bb_iter) {
|
||||
BasicBlock *bb = *bb_iter; // 获取 BasicBlock 指针
|
||||
if (!bb)
|
||||
continue; // 避免空指针
|
||||
|
||||
std::set<Value *> oldLiveIn = liveInSets[bb];
|
||||
std::set<Value *> oldLiveOut = liveOutSets[bb];
|
||||
|
||||
// 1. 计算 LiveOut(BB) = Union(LiveIn(Succ) for Succ in Successors(BB))
|
||||
std::set<Value *> newLiveOut;
|
||||
for (BasicBlock *succ : bb->getSuccessors()) {
|
||||
const std::set<Value *> *succLiveIn = getLiveIn(succ); // 获取后继的 LiveIn
|
||||
if (succLiveIn) {
|
||||
newLiveOut.insert(succLiveIn->begin(), succLiveIn->end());
|
||||
}
|
||||
}
|
||||
liveOutSets[bb] = newLiveOut;
|
||||
|
||||
// 2. 计算 LiveIn(BB) = Use(BB) Union (LiveOut(BB) - Def(BB))
|
||||
std::set<Value *> defSet, useSet;
|
||||
computeDefUse(bb, defSet, useSet); // 计算当前块的 Def 和 Use
|
||||
|
||||
std::set<Value *> liveOutMinusDef;
|
||||
std::set_difference(newLiveOut.begin(), newLiveOut.end(), defSet.begin(), defSet.end(),
|
||||
std::inserter(liveOutMinusDef, liveOutMinusDef.begin()));
|
||||
|
||||
std::set<Value *> newLiveIn = useSet;
|
||||
newLiveIn.insert(liveOutMinusDef.begin(), liveOutMinusDef.end());
|
||||
liveInSets[bb] = newLiveIn;
|
||||
|
||||
// 检查是否发生变化
|
||||
if (oldLiveIn != newLiveIn || oldLiveOut != newLiveOut) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// LivenessAnalysisPass 的实现
|
||||
// ==============================================================
|
||||
|
||||
bool LivenessAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
// 每次运行创建一个新的 LivenessAnalysisResult 对象来存储结果
|
||||
CurrentLivenessResult = std::make_unique<LivenessAnalysisResult>(F);
|
||||
|
||||
// 调用 LivenessAnalysisResult 内部的方法来计算分析结果
|
||||
CurrentLivenessResult->computeLiveness(F);
|
||||
|
||||
// 分析遍通常不修改 IR,所以返回 false
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> LivenessAnalysisPass::getResult() {
|
||||
// 返回计算好的 LivenessAnalysisResult 实例,所有权转移给 AnalysisManager
|
||||
return std::move(CurrentLivenessResult);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
140
src/midend/Pass/Optimize/DCE.cpp
Normal file
140
src/midend/Pass/Optimize/DCE.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "DCE.h" // 包含DCE遍的头文件
|
||||
#include "IR.h" // 包含IR相关的定义
|
||||
#include "SysYIROptUtils.h" // 包含SysY IR优化工具类的定义
|
||||
#include <cassert> // 用于断言
|
||||
#include <iostream> // 用于调试输出
|
||||
#include <set> // 包含set,虽然DCEContext内部用unordered_set,但这里保留
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// DCE 遍的静态 ID
|
||||
void *DCE::ID = (void *)&DCE::ID;
|
||||
|
||||
// ======================================================================
|
||||
// DCEContext 类的实现
|
||||
// 封装了 DCE 遍的核心逻辑和状态,确保每次函数优化运行时状态独立
|
||||
// ======================================================================
|
||||
|
||||
// DCEContext 的 run 方法实现
|
||||
void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
// 清空活跃指令集合,确保每次运行都是新的状态
|
||||
alive_insts.clear();
|
||||
|
||||
// 第一次遍历:扫描所有指令,识别“天然活跃”的指令并将其及其依赖标记为活跃
|
||||
// 使用 func->getBasicBlocks() 获取基本块列表,保留用户风格
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
// 确保基本块有效
|
||||
if (!basicBlock)
|
||||
continue;
|
||||
// 使用 basicBlock->getInstructions() 获取指令列表,保留用户风格
|
||||
for (auto &inst : basicBlock->getInstructions()) {
|
||||
// 确保指令有效
|
||||
if (!inst)
|
||||
continue;
|
||||
// 调用 DCEContext 自身的 isAlive 和 addAlive 方法
|
||||
if (isAlive(inst.get())) {
|
||||
addAlive(inst.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第二次遍历:删除所有未被标记为活跃的指令。
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (!basicBlock)
|
||||
continue;
|
||||
// 使用传统的迭代器循环,并手动管理迭代器,
|
||||
// 以便在删除元素后正确前进。保留用户风格
|
||||
for (auto instIter = basicBlock->getInstructions().begin(); instIter != basicBlock->getInstructions().end();) {
|
||||
auto &inst = *instIter;
|
||||
Instruction *currentInst = inst.get();
|
||||
// 如果指令不在活跃集合中,则删除它。
|
||||
// 分支和返回指令由 isAlive 处理,并会被保留。
|
||||
if (alive_insts.count(currentInst) == 0) {
|
||||
// 删除指令,保留用户风格的 SysYIROptUtils::usedelete 和 erase
|
||||
changed = true; // 标记 IR 已被修改
|
||||
SysYIROptUtils::usedelete(currentInst);
|
||||
instIter = basicBlock->getInstructions().erase(instIter); // 删除后返回下一个迭代器
|
||||
} else {
|
||||
++instIter; // 指令活跃,移动到下一个
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断指令是否是“天然活跃”的实现
|
||||
// 只有具有副作用的指令(如存储、函数调用、原子操作)
|
||||
// 和控制流指令(如分支、返回)是天然活跃的。
|
||||
bool DCEContext::isAlive(Instruction *inst) {
|
||||
// TODO: 后续程序并发考虑原子操作
|
||||
// 其结果不被其他指令使用的指令(例如 StoreInst, BranchInst, ReturnInst)。
|
||||
// dynamic_cast<ir::CallInst>(inst) 检查是否是函数调用指令,
|
||||
// 函数调用通常有副作用。
|
||||
// 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程。
|
||||
// 保留用户提供的 isAlive 逻辑
|
||||
bool isBranchOrReturn = inst->isBranch() || inst->isReturn();
|
||||
bool isCall = inst->isCall();
|
||||
bool isStoreOrMemset = inst->isStore() || inst->isMemset();
|
||||
return isBranchOrReturn || isCall || isStoreOrMemset;
|
||||
}
|
||||
|
||||
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
|
||||
void DCEContext::addAlive(Instruction *inst) {
|
||||
// 如果指令已经存在于活跃集合中,则无需重复处理
|
||||
if (alive_insts.count(inst) > 0) {
|
||||
return;
|
||||
}
|
||||
// 将当前指令标记为活跃
|
||||
alive_insts.insert(inst);
|
||||
// 遍历当前指令的所有操作数
|
||||
// 保留用户提供的 getOperands() 和 getValue()
|
||||
for (auto operand : inst->getOperands()) {
|
||||
// 如果操作数是一个指令(即它是一个值的定义),
|
||||
// 并且它还没有被标记为活跃
|
||||
if (auto opInst = dynamic_cast<Instruction *>(operand->getValue())) {
|
||||
addAlive(opInst); // 递归地将操作数指令标记为活跃
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// DCE Pass 类的实现
|
||||
// 主要负责与 PassManager 交互,创建 DCEContext 实例并运行优化
|
||||
// ======================================================================
|
||||
|
||||
// DCE 遍的 runOnFunction 方法实现
|
||||
bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
|
||||
|
||||
DCEContext ctx;
|
||||
bool changed = false;
|
||||
ctx.run(func, &AM, changed); // 运行 DCE 优化
|
||||
|
||||
// 如果 IR 被修改,则使相关的分析结果失效
|
||||
if (changed) {
|
||||
// DCE 会删除指令,这会影响数据流分析,尤其是活跃性分析。
|
||||
// 如果删除导致基本块变空,也可能间接影响 CFG 和支配树。
|
||||
// AM.invalidateAnalysis(&LivenessAnalysisPass::ID, func); // 活跃性分析失效
|
||||
// AM.invalidateAnalysis(&DominatorTreeAnalysisPass::ID, func); // 支配树分析可能失效
|
||||
// 其他所有依赖于数据流或 IR 结构的分析都可能失效。
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 声明DCE遍的分析依赖和失效信息
|
||||
void DCE::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// DCE不依赖特定的分析结果,它通过遍历和副作用判断来工作。
|
||||
|
||||
// DCE会删除指令,这会影响许多分析结果。
|
||||
// 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。
|
||||
// 假设存在LivenessAnalysisPass和DominatorTreeAnalysisPass
|
||||
// analysisInvalidations.insert(&LivenessAnalysisPass::ID);
|
||||
// analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
|
||||
// 任何改变IR结构的优化,都可能导致通用分析(如活跃性、支配树、循环信息)失效。
|
||||
// 最保守的做法是使所有函数粒度的分析失效,或者只声明你明确知道会受影响的分析。
|
||||
// 考虑到这个DCE仅删除指令,如果它不删除基本块,CFG可能不变,但数据流分析会失效。
|
||||
// 对于更激进的DCE(如ADCE),CFG也会改变。
|
||||
// 这里我们假设它主要影响数据流分析,并且可能间接影响CFG相关分析。
|
||||
// 如果有SideEffectInfo,它也可能被修改,但通常SideEffectInfo是静态的,不因DCE而变。
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
388
src/midend/Pass/Optimize/Mem2Reg.cpp
Normal file
388
src/midend/Pass/Optimize/Mem2Reg.cpp
Normal file
@@ -0,0 +1,388 @@
|
||||
#include "Mem2Reg.h" // 包含 Mem2Reg 遍的头文件
|
||||
#include "Dom.h" // 包含支配树分析的头文件
|
||||
#include "Liveness.h"
|
||||
#include "IR.h" // 包含 IR 相关的定义
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert> // 用于断言
|
||||
#include <iostream> // 用于调试输出
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void *Mem2Reg::ID = (void *)&Mem2Reg::ID;
|
||||
|
||||
void Mem2RegContext::run(Function *func, AnalysisManager *AM) {
|
||||
if (func->getBasicBlocks().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清空所有状态,确保每次运行都是新的状态
|
||||
promotableAllocas.clear();
|
||||
allocaToPhiMap.clear();
|
||||
allocaToValueStackMap.clear();
|
||||
allocaToStoresMap.clear();
|
||||
allocaToDefBlocksMap.clear();
|
||||
|
||||
// 获取支配树分析结果
|
||||
dt = AM->getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(func);
|
||||
assert(dt && "DominatorTreeAnalysisResult not available for Mem2Reg!");
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 阶段1: 识别可提升的 AllocaInst 并收集其 Store 指令
|
||||
// --------------------------------------------------------------------
|
||||
// 遍历函数入口块?中的所有指令,寻找 AllocaInst
|
||||
// 必须是要入口块的吗
|
||||
for (auto &inst : func->getEntryBlock()->getInstructions_Range()) {
|
||||
Value *allocainst = inst.get();
|
||||
if (auto alloca = dynamic_cast<AllocaInst *>(allocainst)) {
|
||||
if (isPromotableAlloca(alloca)) {
|
||||
promotableAllocas.push_back(alloca);
|
||||
collectStores(alloca); // 收集所有对该 alloca 的 store
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 阶段2: 插入 Phi 指令
|
||||
// --------------------------------------------------------------------
|
||||
for (auto alloca : promotableAllocas) {
|
||||
// 为每个可提升的 alloca 插入 Phi 指令
|
||||
insertPhis(alloca, allocaToDefBlocksMap[alloca]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 阶段3: 变量重命名
|
||||
// --------------------------------------------------------------------
|
||||
// 为每个可提升的 alloca 初始化其值栈
|
||||
for (auto alloca : promotableAllocas) {
|
||||
// 初始值通常是 undef 或 null,取决于 IR 类型系统
|
||||
UndefinedValue *undefValue = UndefinedValue::get(alloca->getType()->as<PointerType>()->getBaseType());
|
||||
allocaToValueStackMap[alloca].push(undefValue); // 压入一个初始的“未定义”值
|
||||
}
|
||||
|
||||
// 从入口基本块开始,对支配树进行 DFS 遍历,进行变量重命名
|
||||
renameVariables(nullptr, func->getEntryBlock()); // 第一个参数 alloca 在这里不使用,因为是递归入口点
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 阶段4: 清理
|
||||
// --------------------------------------------------------------------
|
||||
cleanup();
|
||||
}
|
||||
|
||||
// 判断一个 AllocaInst 是否可以被提升到寄存器
|
||||
bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) {
|
||||
// 1. 必须是标量类型(非数组、非结构体)sysy不支持结构体
|
||||
if (alloca->getType()->as<PointerType>()->getBaseType()->isArray()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 其所有用途都必须是 LoadInst 或 StoreInst
|
||||
// (或 GetElementPtrInst,但 GEP 的结果也必须只被 Load/Store 使用)
|
||||
for (auto use : alloca->getUses()) {
|
||||
auto user = use->getUser();
|
||||
if (!user)
|
||||
return false; // 用户无效
|
||||
|
||||
if (dynamic_cast<LoadInst *>(user)) {
|
||||
// OK
|
||||
} else if (dynamic_cast<StoreInst *>(user)) {
|
||||
// OK
|
||||
} else if (auto gep = dynamic_cast<GetElementPtrInst *>(user)) {
|
||||
// 如果是 GetElementPtrInst (GEP)
|
||||
// 需要判断这个 GEP 是否代表了数组元素的访问,而非简单的指针操作
|
||||
// LLVM 的 mem2reg 通常不提升用于数组元素访问的 alloca。
|
||||
// 启发式判断:
|
||||
// 如果 GEP 有多个索引(例如 `getelementptr i32, i32* %ptr, i32 0, i32 %idx`),
|
||||
// 或者第一个索引(对于指针类型)不是常量 0,则很可能是数组访问。
|
||||
// 对于 `alloca i32* %a.param` (对应 `int a[]` 参数),其 `allocatedType()` 是 `i32*`。
|
||||
// 访问 `a[i]` 会生成类似 `getelementptr i32, i32* %a.param, i32 %i` 的 GEP。
|
||||
// 这种 GEP 有两个操作数:基指针和索引。
|
||||
|
||||
// 检查 GEP 的操作数数量和索引值
|
||||
// GEP 的操作数通常是:<base_pointer>, <index_1>, <index_2>, ...
|
||||
// 对于一个 `i32*` 类型的 `alloca`,如果它被 GEP 使用,那么 GEP 的第一个索引通常是 `0`
|
||||
// (表示解引用指针本身),后续索引才是数组元素的索引。
|
||||
// 如果 GEP 的操作数数量大于 2 (即 `base_ptr` 和 `index_0` 之外还有其他索引),
|
||||
// 或者 `index_0` 不是常量 0,则它可能是一个复杂的数组访问。
|
||||
// 假设 `gep->getNumOperands()` 和 `gep->getOperand(idx)->getValue()`
|
||||
// 假设 `ConstantInt` 类用于表示常量整数值
|
||||
if (gep->getNumOperands() > 2) { // 如果有超过一个索引(除了基指针的第一个隐式索引)
|
||||
// std::cerr << "Mem2Reg: Not promotable (GEP with multiple indices): " << alloca->name() << std::endl;
|
||||
return false; // 复杂 GEP,通常表示数组或结构体字段访问
|
||||
}
|
||||
if (gep->getNumOperands() == 2) { // 只有基指针和一个索引
|
||||
Value *firstIndexVal = gep->getOperand(1); // 获取第一个索引值
|
||||
if (auto constInt = dynamic_cast<ConstantInteger *>(firstIndexVal)) {
|
||||
if (constInt->getInt() != 0) {
|
||||
// std::cerr << "Mem2Reg: Not promotable (GEP with non-zero first index): " << alloca->name() << std::endl;
|
||||
return false; // 索引不是0,表示访问数组的非第一个元素
|
||||
}
|
||||
} else {
|
||||
// std::cerr << "Mem2Reg: Not promotable (GEP with non-constant first index): " << alloca->name() <<
|
||||
// std::endl;
|
||||
return false; // 索引不是常量,表示动态数组访问
|
||||
}
|
||||
}
|
||||
|
||||
// 此外,GEP 的结果也必须只被 LoadInst 或 StoreInst 使用
|
||||
for (auto gep_use : gep->getUses()) {
|
||||
auto gep_user = gep_use->getUser();
|
||||
if (!gep_user) {
|
||||
// std::cerr << "Mem2Reg: Not promotable (GEP result null user): " << alloca->name() << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (!dynamic_cast<LoadInst *>(gep_user) && !dynamic_cast<StoreInst *>(gep_user)) {
|
||||
// std::cerr << "Mem2Reg: Not promotable (GEP result used by non-load/store): " << alloca->name() <<
|
||||
// std::endl;
|
||||
return false; // GEP 结果被其他指令使用,地址逃逸或复杂用途
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 其他类型的用户,如 CallInst (如果地址逃逸),则不能提升
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 3. 不能是 volatile 内存访问 (假设 AllocaInst 有 isVolatile() 方法)
|
||||
// if (alloca->isVolatile()) return false; // 如果有这样的属性
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 收集所有对给定 AllocaInst 进行存储的 StoreInst
|
||||
void Mem2RegContext::collectStores(AllocaInst *alloca) {
|
||||
// 遍历 alloca 的所有用途
|
||||
for (auto use : alloca->getUses()) {
|
||||
auto user = use->getUser();
|
||||
if (!user)
|
||||
continue;
|
||||
|
||||
if (auto storeInst = dynamic_cast<StoreInst *>(user)) {
|
||||
allocaToStoresMap[alloca].insert(storeInst);
|
||||
allocaToDefBlocksMap[alloca].insert(storeInst->getParent());
|
||||
} else if (auto gep = dynamic_cast<GetElementPtrInst *>(user)) {
|
||||
// 如果是 GEP,递归收集其下游的 store
|
||||
for (auto gep_use : gep->getUses()) {
|
||||
if (auto gep_store = dynamic_cast<StoreInst *>(gep_use->getUser())) {
|
||||
allocaToStoresMap[alloca].insert(gep_store);
|
||||
allocaToDefBlocksMap[alloca].insert(gep_store->getParent());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 为给定的 AllocaInst 插入必要的 Phi 指令
|
||||
void Mem2RegContext::insertPhis(AllocaInst *alloca, const std::unordered_set<BasicBlock *> &defBlocks) {
|
||||
std::queue<BasicBlock *> workQueue;
|
||||
std::unordered_set<BasicBlock *> phiHasBeenInserted; // 记录已插入 Phi 的基本块
|
||||
|
||||
// 将所有定义块加入工作队列
|
||||
for (auto bb : defBlocks) {
|
||||
workQueue.push(bb);
|
||||
}
|
||||
|
||||
while (!workQueue.empty()) {
|
||||
BasicBlock *currentDefBlock = workQueue.front();
|
||||
workQueue.pop();
|
||||
|
||||
// 遍历当前定义块的支配边界 (Dominance Frontier)
|
||||
const std::set<BasicBlock *> *frontierBlocks = dt->getDominanceFrontier(currentDefBlock);
|
||||
for (auto frontierBlock : *frontierBlocks) {
|
||||
// 如果该支配边界块还没有为当前 alloca 插入 Phi 指令
|
||||
if (phiHasBeenInserted.find(frontierBlock) == phiHasBeenInserted.end()) {
|
||||
// 在支配边界块的开头插入一个新的 Phi 指令
|
||||
// Phi 指令的类型与 alloca 的类型指向的类型相同
|
||||
|
||||
builder->setPosition(frontierBlock, frontierBlock->begin()); // 设置插入位置为基本块开头
|
||||
PhiInst *phiInst = builder->createPhiInst(alloca->getAllocatedType(), {}, {}, "");
|
||||
|
||||
allocaToPhiMap[alloca][frontierBlock] = phiInst; // 记录 Phi 指令
|
||||
|
||||
phiHasBeenInserted.insert(frontierBlock); // 标记已插入 Phi
|
||||
|
||||
// 如果这个支配边界块本身也是一个定义块(即使没有 store,但插入了 Phi),
|
||||
// 那么它的支配边界也可能需要插入 Phi
|
||||
// 例如一个xx型的cfg,如果在第一个交叉处插入phi节点,那么第二个交叉处可能也需要插入phi
|
||||
workQueue.push(frontierBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
|
||||
void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *currentBB) {
|
||||
// 维护一个局部栈,用于存储当前基本块中为 Phi 和 Store 创建的 SSA 值,以便在退出时弹出
|
||||
std::stack<Value *> localStackPushed;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 处理当前基本块的指令
|
||||
// --------------------------------------------------------------------
|
||||
for (auto instIter = currentBB->getInstructions().begin(); instIter != currentBB->getInstructions().end();) {
|
||||
Instruction *inst = instIter->get();
|
||||
bool instDeleted = false;
|
||||
|
||||
// 处理 Phi 指令 (如果是当前 alloca 的 Phi)
|
||||
if (auto phiInst = dynamic_cast<PhiInst *>(inst)) {
|
||||
// 检查这个 Phi 是否是为某个可提升的 alloca 插入的
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (allocaToPhiMap[alloca].count(currentBB) && allocaToPhiMap[alloca][currentBB] == phiInst) {
|
||||
// 为 Phi 指令的输出创建一个新的 SSA 值,并压入值栈
|
||||
allocaToValueStackMap[alloca].push(phiInst);
|
||||
localStackPushed.push(phiInst); // 记录以便弹出
|
||||
break; // 找到对应的 alloca,处理下一个指令
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理 LoadInst
|
||||
else if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
|
||||
// 检查这个 LoadInst 是否是为某个可提升的 alloca
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (loadInst->getPointer() == alloca) {
|
||||
// loadInst->getPointer() 返回 AllocaInst*
|
||||
// 将 LoadInst 的所有用途替换为当前 alloca 值栈顶部的 SSA 值
|
||||
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca during load replacement!");
|
||||
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
|
||||
// instIter = currentBB->force_delete_inst(loadInst); // 删除 LoadInst
|
||||
SysYIROptUtils::usedelete(loadInst); // 仅删除 use 关系
|
||||
instIter = currentBB->getInstructions().erase(instIter); // 删除 LoadInst
|
||||
instDeleted = true;
|
||||
// std::cerr << "Mem2Reg: Replaced load " << loadInst->name() << " with SSA value." << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理 StoreInst
|
||||
else if (auto storeInst = dynamic_cast<StoreInst *>(inst)) {
|
||||
// 检查这个 StoreInst 是否是为某个可提升的 alloca
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (storeInst->getPointer() == alloca) {
|
||||
// 假设 storeInst->getPointer() 返回 AllocaInst*
|
||||
// 将 StoreInst 存储的值作为新的 SSA 值,压入值栈
|
||||
allocaToValueStackMap[alloca].push(storeInst->getValue());
|
||||
localStackPushed.push(storeInst->getValue()); // 记录以便弹出
|
||||
SysYIROptUtils::usedelete(storeInst);
|
||||
instIter = currentBB->getInstructions().erase(instIter); // 删除 StoreInst
|
||||
instDeleted = true;
|
||||
// std::cerr << "Mem2Reg: Replaced store to " << storeInst->ptr()->name() << " with SSA value." << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!instDeleted) {
|
||||
++instIter; // 如果指令没有被删除,移动到下一个
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 处理后继基本块的 Phi 指令参数
|
||||
// --------------------------------------------------------------------
|
||||
for (auto successorBB : currentBB->getSuccessors()) {
|
||||
if (!successorBB)
|
||||
continue;
|
||||
for (auto alloca : promotableAllocas) {
|
||||
// 如果后继基本块包含为当前 alloca 插入的 Phi 指令
|
||||
if (allocaToPhiMap[alloca].count(successorBB)) {
|
||||
auto phiInst = allocaToPhiMap[alloca][successorBB];
|
||||
// 为 Phi 指令添加来自当前基本块的参数
|
||||
// 参数值是当前 alloca 值栈顶部的 SSA 值
|
||||
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca when setting phi operand!");
|
||||
phiInst->addIncoming(allocaToValueStackMap[alloca].top(), currentBB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 递归访问支配树的子节点
|
||||
// --------------------------------------------------------------------
|
||||
const std::set<BasicBlock *> *dominatedBlocks = dt->getDominatorTreeChildren(currentBB);
|
||||
if(dominatedBlocks){
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
if (dominatedBB) {
|
||||
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName() << std::endl;
|
||||
renameVariables(currentAlloca, dominatedBB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 退出基本块时,弹出在此块中压入值栈的 SSA 值
|
||||
// --------------------------------------------------------------------
|
||||
while (!localStackPushed.empty()) {
|
||||
Value *val = localStackPushed.top();
|
||||
localStackPushed.pop();
|
||||
// 找到是哪个 alloca 对应的栈
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (!allocaToValueStackMap[alloca].empty() && allocaToValueStackMap[alloca].top() == val) {
|
||||
allocaToValueStackMap[alloca].pop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst
|
||||
void Mem2RegContext::cleanup() {
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (alloca && alloca->getParent()) {
|
||||
// 删除 alloca 指令本身
|
||||
SysYIROptUtils::usedelete(alloca);
|
||||
alloca->getParent()->removeInst(alloca); // 从基本块中删除 alloca
|
||||
|
||||
// std::cerr << "Mem2Reg: Deleted alloca " << alloca->name() << std::endl;
|
||||
}
|
||||
}
|
||||
// LoadInst 和 StoreInst 已经在 renameVariables 阶段被删除了
|
||||
}
|
||||
|
||||
// Mem2Reg 遍的 runOnFunction 方法实现
|
||||
bool Mem2Reg::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
// 记录初始的指令数量,用于判断优化是否发生了改变
|
||||
size_t initial_inst_count = 0;
|
||||
for (auto &bb : F->getBasicBlocks()) {
|
||||
initial_inst_count += bb->getInstructions().size();
|
||||
}
|
||||
|
||||
Mem2RegContext ctx(builder);
|
||||
ctx.run(F, &AM); // 运行 Mem2Reg 优化
|
||||
|
||||
// 运行优化后,再次计算指令数量
|
||||
size_t final_inst_count = 0;
|
||||
for (auto &bb : F->getBasicBlocks()) {
|
||||
final_inst_count += bb->getInstructions().size();
|
||||
}
|
||||
|
||||
// 如果指令数量发生变化(通常是减少,因为 load/store 被删除,phi 被添加),说明 IR 被修改了
|
||||
// TODO:不保险,后续修改为更精确的判断
|
||||
// 直接在添加和删除指令时维护changed值
|
||||
bool changed = (initial_inst_count != final_inst_count);
|
||||
|
||||
// 如果 IR 被修改,则使相关的分析结果失效
|
||||
if (changed) {
|
||||
// Mem2Reg 会显著改变 IR 结构,特别是数据流和控制流(通过 Phi)。
|
||||
// 这会使几乎所有数据流分析和部分控制流分析失效。
|
||||
// AM.invalidateAnalysis(&DominatorTreeAnalysisPass::ID, F); // 支配树可能间接改变(如果基本块被删除)
|
||||
// AM.invalidateAnalysis(&LivenessAnalysisPass::ID, F); // 活跃性分析肯定失效
|
||||
// AM.invalidateAnalysis(&LoopInfoAnalysisPass::ID, F); // 循环信息可能失效
|
||||
// AM.invalidateAnalysis(&SideEffectInfoAnalysisPass::ID); // 副作用分析可能失效(如果 Alloca/Load/Store
|
||||
// 被替换为寄存器)
|
||||
// ... 其他数据流分析,如到达定义、可用表达式等,也应失效
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 声明Mem2Reg遍的分析依赖和失效信息
|
||||
void Mem2Reg::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// Mem2Reg 强烈依赖于支配树分析来插入 Phi 指令
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 假设 DominatorTreeAnalysisPass 的 ID
|
||||
|
||||
// Mem2Reg 会删除 Alloca/Load/Store 指令,插入 Phi 指令,这会大幅改变 IR 结构。
|
||||
// 因此,它会使许多分析结果失效。
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
|
||||
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析肯定失效
|
||||
// analysisInvalidations.insert(&LoopInfoAnalysisPass::ID); // 循环信息可能失效
|
||||
// analysisInvalidations.insert(&SideEffectInfoAnalysisPass::ID); // 副作用分析可能失效
|
||||
// 其他所有依赖于数据流或 IR 结构的分析都可能失效。
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
289
src/midend/Pass/Optimize/Reg2Mem.cpp
Normal file
289
src/midend/Pass/Optimize/Reg2Mem.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
#include "Reg2Mem.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
|
||||
extern int DEBUG; // 全局调试标志
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void *Reg2Mem::ID = (void *)&Reg2Mem::ID;
|
||||
|
||||
void Reg2MemContext::run(Function *func) {
|
||||
if (func->getBasicBlocks().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清空状态,确保每次运行都是新的
|
||||
valueToAllocaMap.clear();
|
||||
|
||||
// 阶段1: 识别并为 SSA Value 分配 AllocaInst
|
||||
allocateMemoryForSSAValues(func);
|
||||
|
||||
// 阶段2: 将 Phi 指令转换为 Load/Store 逻辑 (此阶段需要先于通用 Load/Store 插入)
|
||||
// 这样做是因为 Phi 指令的特殊性,它需要在前驱块的末尾插入 Store
|
||||
// 如果先处理通用 Load/Store,可能无法正确处理 Phi 的复杂性
|
||||
rewritePhis(func); // Phi 指令可能在 rewritePhis 中被删除或标记删除
|
||||
|
||||
// 阶段3: 将其他 SSA Value 的使用替换为 Load/Store
|
||||
insertLoadsAndStores(func);
|
||||
|
||||
// 阶段4: 清理(删除不再需要的 Phi 指令)
|
||||
cleanup(func);
|
||||
}
|
||||
|
||||
bool Reg2MemContext::isPromotableToMemory(Value *val) {
|
||||
// 参数和指令结果是 SSA 值
|
||||
if(DEBUG){
|
||||
// if(val->getName() == ""){
|
||||
// assert(false && "Value name should not be empty in Reg2MemContext::isPromotableToMemory");
|
||||
// }
|
||||
// std::cout << "Checking if value is promotable to memory: " << val->getName() << std::endl;
|
||||
}
|
||||
// if (dynamic_cast<Argument *>(val) || dynamic_cast<Instruction *>(val)) {
|
||||
// // 如果值已经是指针类型,则通常不为其分配额外的内存,因为它已经是一个地址。
|
||||
// // (除非我们想将其值也存储起来,这通常不用于 Reg2Mem)
|
||||
// // // Reg2Mem 关注的是将非指针值从寄存器语义转换为内存语义。
|
||||
// if (val->getType()->isPointer()) {
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// 1. 如果是 Argument,则可以提升到内存
|
||||
if (dynamic_cast<Argument *>(val)) {
|
||||
// 参数类型(i32, i32* 等)都可以为其分配内存
|
||||
// 因为它们在 Mem2Reg 逆操作中,被认为是从寄存器分配到内存
|
||||
return true;
|
||||
}
|
||||
if (dynamic_cast<PhiInst *>(val)) {
|
||||
// Phi 指令的结果也是一个 SSA 值,需要将其转换为 Load/Store
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
|
||||
// AllocaInst 必须在函数的入口基本块中
|
||||
BasicBlock *entryBlock = func->getEntryBlock();
|
||||
if (!entryBlock) {
|
||||
return; // 函数可能没有入口块 (例如声明)
|
||||
}
|
||||
|
||||
// 1. 为函数参数分配内存
|
||||
builder->setPosition(entryBlock, entryBlock->begin()); // 确保在入口块的开始位置插入
|
||||
for (auto arg : func->getArguments()) {
|
||||
// 默认情况下,将所有参数是提升到内存
|
||||
if (isPromotableToMemory(arg)) {
|
||||
// 参数的类型就是 AllocaInst 需要分配的类型
|
||||
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), {}, arg->getName() + ".reg2mem");
|
||||
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
|
||||
valueToAllocaMap[arg] = alloca;
|
||||
|
||||
// 确保 alloca 位于入口块的顶部,但在所有参数的 store 指令之前
|
||||
// 通常 alloca 都在 entry block 的最开始
|
||||
// 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
|
||||
// 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 为指令结果分配内存
|
||||
// 遍历所有基本块和指令,找出所有需要分配 Alloca 的指令结果
|
||||
for (auto &bb : func->getBasicBlocks()) {
|
||||
for (auto &inst : bb->getInstructions_Range()) {
|
||||
// SysYPrinter::printInst(inst.get());
|
||||
// 只有有结果的指令才可能需要分配内存
|
||||
// (例如 BinaryInst, CallInst, LoadInst, PhiInst 等)
|
||||
// StoreInst, BranchInst, ReturnInst 等没有结果的指令不需要
|
||||
|
||||
if (dynamic_cast<AllocaInst*>(inst.get()) || inst.get()->getType()->isVoid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isPromotableToMemory(inst.get())) {
|
||||
// 为指令的结果分配内存
|
||||
// AllocaInst 应该在入口块,而不是当前指令所在块
|
||||
// 这里我们只是创建,并稍后调整其位置
|
||||
// 通常的做法是在循环结束后统一将 alloca 放到 entryBlock 的顶部
|
||||
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(inst.get()->getType()), {}, inst.get()->getName() + ".reg2mem");
|
||||
valueToAllocaMap[inst.get()] = alloca;
|
||||
}
|
||||
}
|
||||
}
|
||||
Instruction *firstNonAlloca = nullptr;
|
||||
for (auto instIter = entryBlock->getInstructions().begin(); instIter != entryBlock->getInstructions().end(); instIter++) {
|
||||
if (!dynamic_cast<AllocaInst*>(instIter->get())) {
|
||||
firstNonAlloca = instIter->get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstNonAlloca) {
|
||||
builder->setPosition(entryBlock, entryBlock->findInstIterator(firstNonAlloca));
|
||||
} else { // 如果 entryBlock 只有 AllocaInst 或为空,则设置到 terminator 前
|
||||
builder->setPosition(entryBlock, entryBlock->terminator());
|
||||
}
|
||||
|
||||
// 插入所有参数的初始 Store 指令
|
||||
for (auto arg : func->getArguments()) {
|
||||
if (valueToAllocaMap.count(arg)) { // 检查是否为其分配了 alloca
|
||||
builder->createStoreInst(arg, valueToAllocaMap[arg]);
|
||||
}
|
||||
}
|
||||
|
||||
builder->setPosition(entryBlock, entryBlock->terminator());
|
||||
}
|
||||
|
||||
void Reg2MemContext::rewritePhis(Function *func) {
|
||||
std::vector<PhiInst *> phisToErase; // 收集要删除的 Phi
|
||||
|
||||
// 遍历所有基本块和其中的指令,查找 Phi 指令
|
||||
for (auto &bb : func->getBasicBlocks()) {
|
||||
// auto insts = bb->getInstructions(); // 复制一份,因为要修改
|
||||
for (auto instIter = bb->getInstructions().begin(); instIter != bb->getInstructions().end(); instIter++) {
|
||||
Instruction *inst = instIter->get();
|
||||
if (auto phiInst = dynamic_cast<PhiInst *>(inst)) {
|
||||
// 检查 Phi 指令是否是需要处理的 SSA 值
|
||||
if (valueToAllocaMap.count(phiInst)) {
|
||||
AllocaInst *alloca = valueToAllocaMap[phiInst];
|
||||
|
||||
// 1. 为 Phi 指令的每个入边,在前驱块的末尾插入 Store 指令
|
||||
// PhiInst 假设有 getIncomingValues() 和 getIncomingBlocks()
|
||||
for (unsigned i = 0; i < phiInst->getNumIncomingValues(); ++i) { // 假设 PhiInst 是通过操作数来管理入边的
|
||||
Value *incomingValue = phiInst->getValue(i); // 获取入值
|
||||
BasicBlock *incomingBlock = phiInst->getBlock(i); // 获取对应的入块
|
||||
|
||||
// 在入块的跳转指令之前插入 StoreInst
|
||||
// 需要找到 incomingBlock 的终结指令 (Terminator Instruction)
|
||||
// 并将 StoreInst 插入到它前面
|
||||
if (incomingBlock->terminator()->get()->isTerminator()) {
|
||||
builder->setPosition(incomingBlock, incomingBlock->terminator());
|
||||
} else {
|
||||
// 如果没有终结指令,插入到末尾
|
||||
builder->setPosition(incomingBlock, incomingBlock->end());
|
||||
}
|
||||
builder->createStoreInst(incomingValue, alloca);
|
||||
}
|
||||
|
||||
// 2. 在当前 Phi 所在基本块的开头,插入 Load 指令
|
||||
// 将 Load 指令插入到 Phi 指令之后,因为 Phi 指令即将被删除
|
||||
builder->setPosition(bb.get(), bb.get()->findInstIterator(phiInst));
|
||||
LoadInst *newLoad = builder->createLoadInst(alloca);
|
||||
|
||||
// 3. 将 Phi 指令的所有用途替换为新的 Load 指令
|
||||
phiInst->replaceAllUsesWith(newLoad);
|
||||
|
||||
// 标记 Phi 指令待删除
|
||||
phisToErase.push_back(phiInst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实际删除 Phi 指令
|
||||
for (auto phi : phisToErase) {
|
||||
if (phi && phi->getParent()) {
|
||||
SysYIROptUtils::usedelete(phi); // 清理 use-def 链
|
||||
phi->getParent()->removeInst(phi); // 从基本块中删除
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Reg2MemContext::insertLoadsAndStores(Function *func) {
|
||||
// 收集所有需要替换的 uses,避免在迭代时修改 use 链表
|
||||
std::vector<std::pair<Use *, LoadInst *>> usesToReplace;
|
||||
std::vector<Instruction *> instsToStore; // 收集需要插入 Store 的指令
|
||||
|
||||
// 遍历所有基本块和指令
|
||||
for (auto &bb : func->getBasicBlocks()) {
|
||||
for (auto instIter = bb->getInstructions().begin(); instIter != bb->getInstructions().end(); instIter++) {
|
||||
Instruction *inst = instIter->get();
|
||||
|
||||
// 如果指令有结果且我们为其分配了 alloca (Phi 已在 rewritePhis 处理)
|
||||
// 并且其类型不是 void
|
||||
if (!inst->getType()->isVoid() && valueToAllocaMap.count(inst)) {
|
||||
// 在指令之后插入 Store 指令
|
||||
// StoreInst 应该插入到当前指令之后
|
||||
builder->setPosition(bb.get(), bb.get()->findInstIterator(inst));
|
||||
builder->createStoreInst(inst, valueToAllocaMap[inst]);
|
||||
}
|
||||
|
||||
// 处理指令的操作数:如果操作数是一个 SSA 值,且为其分配了 alloca
|
||||
// (并且这个操作数不是 Phi Inst 的 incoming value,因为 Phi 的 incoming value 已经在 rewritePhis 中处理了)
|
||||
// 注意:Phi Inst 的操作数是特殊的,它们表示来自不同前驱块的值。
|
||||
// 这里的处理主要是针对非 Phi 指令的操作数。
|
||||
for (auto use = inst->getUses().begin(); use != inst->getUses().end(); ++use) {
|
||||
// 如果当前 use 的 Value 是一个 Instruction 或 Argument
|
||||
Value *operand = use->get()->getValue();
|
||||
if (isPromotableToMemory(operand) && valueToAllocaMap.count(operand)) {
|
||||
// 确保这个 operand 不是一个即将被删除的 Phi 指令
|
||||
// (在 rewritePhis 阶段,Phi 已经被处理并可能被标记删除)
|
||||
// 或者检查 use 的 user 不是 PhiInst
|
||||
if (dynamic_cast<PhiInst *>(inst)) {
|
||||
continue; // Phi 的操作数已在 rewritePhis 中处理
|
||||
}
|
||||
|
||||
AllocaInst *alloca = valueToAllocaMap[operand];
|
||||
|
||||
// 在使用点之前插入 Load 指令
|
||||
// LoadInst 应该插入到使用它的指令之前
|
||||
builder->setPosition(bb.get(), bb.get()->findInstIterator(inst));
|
||||
LoadInst *newLoad = builder->createLoadInst(alloca);
|
||||
|
||||
// 记录要替换的 use
|
||||
usesToReplace.push_back({use->get(), newLoad});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行所有替换操作
|
||||
for (auto &pair : usesToReplace) {
|
||||
pair.first->setValue(pair.second); // 替换 use 的 Value
|
||||
}
|
||||
}
|
||||
|
||||
void Reg2MemContext::cleanup(Function *func) {
|
||||
// 此时,所有原始的 Phi 指令应该已经被删除。
|
||||
// 如果有其他需要删除的临时指令,可以在这里处理。
|
||||
// 通常,Reg2Mem 的清理比 Mem2Reg 简单,因为主要是在插入指令。
|
||||
// 这里可以作为一个占位符,以防未来有其他清理需求。
|
||||
}
|
||||
|
||||
bool Reg2Mem::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
// 记录初始指令数量
|
||||
size_t initial_inst_count = 0;
|
||||
for (auto &bb : F->getBasicBlocks()) {
|
||||
initial_inst_count += bb->getInstructions().size();
|
||||
}
|
||||
|
||||
Reg2MemContext ctx(builder); // 假设 builder 是一个全局或可访问的 IRBuilder 实例
|
||||
ctx.run(F);
|
||||
|
||||
// 记录最终指令数量
|
||||
size_t final_inst_count = 0;
|
||||
for (auto &bb : F->getBasicBlocks()) {
|
||||
final_inst_count += bb->getInstructions().size();
|
||||
}
|
||||
// TODO: 添加更精确的变化检测逻辑,例如在run函数中维护changed状态
|
||||
bool changed = (initial_inst_count != final_inst_count); // 粗略判断是否改变
|
||||
|
||||
if (changed) {
|
||||
// Reg2Mem 会显著改变 IR 结构,特别是数据流。
|
||||
// 它会插入大量的 Load/Store 指令,改变 Value 的来源。
|
||||
// 这会使几乎所有数据流分析失效。
|
||||
// 例如:
|
||||
// AM.invalidateAnalysis(&DominatorTreeAnalysisPass::ID, F); // 如果基本块结构改变,可能失效
|
||||
// AM.invalidateAnalysis(&LivenessAnalysisPass::ID, F); // 活跃性分析肯定失效
|
||||
// AM.invalidateAnalysis(&DCEPass::ID, F); // 可能产生新的死代码
|
||||
// ... 其他所有数据流分析
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void Reg2Mem::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// Reg2Mem 通常不需要特定的分析作为依赖,因为它主要是一个转换。
|
||||
// 但它会使许多分析失效。
|
||||
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 例如
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
600
src/midend/Pass/Optimize/SysYIRCFGOpt.cpp
Normal file
600
src/midend/Pass/Optimize/SysYIRCFGOpt.cpp
Normal file
@@ -0,0 +1,600 @@
|
||||
#include "SysYIRCFGOpt.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <queue> // 引入队列,SysYDelNoPreBLock需要
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义静态ID
|
||||
void *SysYDelInstAfterBrPass::ID = (void *)&SysYDelInstAfterBrPass::ID;
|
||||
void *SysYDelEmptyBlockPass::ID = (void *)&SysYDelEmptyBlockPass::ID;
|
||||
void *SysYDelNoPreBLockPass::ID = (void *)&SysYDelNoPreBLockPass::ID;
|
||||
void *SysYBlockMergePass::ID = (void *)&SysYBlockMergePass::ID;
|
||||
void *SysYAddReturnPass::ID = (void *)&SysYAddReturnPass::ID;
|
||||
void *SysYCondBr2BrPass::ID = (void *)&SysYCondBr2BrPass::ID;
|
||||
|
||||
|
||||
// ======================================================================
|
||||
// SysYCFGOptUtils: 辅助工具类,包含实际的CFG优化逻辑
|
||||
// ======================================================================
|
||||
|
||||
// 删除br后的无用指令
|
||||
bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
bool Branch = false;
|
||||
auto &instructions = basicBlock->getInstructions();
|
||||
auto Branchiter = instructions.end();
|
||||
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
|
||||
if ((*iter)->isTerminator()){
|
||||
Branch = true;
|
||||
Branchiter = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Branchiter != instructions.end()) ++Branchiter;
|
||||
while (Branchiter != instructions.end()) {
|
||||
changed = true;
|
||||
Branchiter = instructions.erase(Branchiter);
|
||||
}
|
||||
|
||||
if (Branch) { // 更新前驱后继关系
|
||||
auto thelastinstinst = basicBlock->getInstructions().end();
|
||||
--thelastinstinst;
|
||||
auto &Successors = basicBlock->getSuccessors();
|
||||
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
|
||||
(*iterSucc)->removePredecessor(basicBlock.get());
|
||||
basicBlock->removeSuccessor(*iterSucc);
|
||||
}
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
BasicBlock* branchBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(0));
|
||||
basicBlock->addSuccessor(branchBlock);
|
||||
branchBlock->addPredecessor(basicBlock.get());
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
BasicBlock* thenBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(1));
|
||||
BasicBlock* elseBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(2));
|
||||
basicBlock->addSuccessor(thenBlock);
|
||||
basicBlock->addSuccessor(elseBlock);
|
||||
thenBlock->addPredecessor(basicBlock.get());
|
||||
elseBlock->addPredecessor(basicBlock.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 合并基本块
|
||||
bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
for (auto blockiter = func->getBasicBlocks().begin();
|
||||
blockiter != func->getBasicBlocks().end();) {
|
||||
if (blockiter->get()->getNumSuccessors() == 1) {
|
||||
// 如果当前块只有一个后继块
|
||||
// 且后继块只有一个前驱块
|
||||
// 则将当前块和后继块合并
|
||||
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
|
||||
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
|
||||
BasicBlock* block = blockiter->get();
|
||||
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
|
||||
// auto nextarguments = nextBlock->getArguments();
|
||||
// 删除br指令
|
||||
if (block->getNumInstructions() != 0) {
|
||||
auto thelastinstinst = block->end();
|
||||
(--thelastinstinst);
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
||||
thelastinstinst = block->getInstructions().erase(thelastinstinst);
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
||||
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
||||
thelastinstinst = block->getInstructions().erase(thelastinstinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将后继块的指令移动到当前块
|
||||
// 并将后继块的父指针改为当前块
|
||||
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
||||
institer->get()->setParent(block);
|
||||
block->getInstructions().emplace_back(institer->release());
|
||||
institer = nextBlock->getInstructions().erase(institer);
|
||||
}
|
||||
// 更新前驱后继关系,类似树节点操作
|
||||
block->removeSuccessor(nextBlock);
|
||||
nextBlock->removePredecessor(block);
|
||||
std::list<BasicBlock *> succshoulddel;
|
||||
for (auto &succ : nextBlock->getSuccessors()) {
|
||||
block->addSuccessor(succ);
|
||||
succ->replacePredecessor(nextBlock, block);
|
||||
succshoulddel.push_back(succ);
|
||||
}
|
||||
for (auto del : succshoulddel) {
|
||||
nextBlock->removeSuccessor(del);
|
||||
}
|
||||
|
||||
func->removeBasicBlock(nextBlock);
|
||||
changed = true;
|
||||
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 删除无前驱块,兼容SSA后的处理
|
||||
bool SysYCFGOptUtils::SysYDelNoPreBLock(Function *func) {
|
||||
|
||||
bool changed = false;
|
||||
|
||||
for (auto &block : func->getBasicBlocks()) {
|
||||
block->setreachableFalse();
|
||||
}
|
||||
// 对函数基本块做一个拓扑排序,排查不可达基本块
|
||||
auto entryBlock = func->getEntryBlock();
|
||||
entryBlock->setreachableTrue();
|
||||
std::queue<BasicBlock *> blockqueue;
|
||||
blockqueue.push(entryBlock);
|
||||
while (!blockqueue.empty()) {
|
||||
auto block = blockqueue.front();
|
||||
blockqueue.pop();
|
||||
for (auto &succ : block->getSuccessors()) {
|
||||
if (!succ->getreachable()) {
|
||||
succ->setreachableTrue();
|
||||
blockqueue.push(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除不可达基本块指令
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end(); blockIter++) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto instIter = blockIter->get()->getInstructions().begin();
|
||||
instIter != blockIter->get()->getInstructions().end();) {
|
||||
SysYIROptUtils::usedelete(instIter->get());
|
||||
instIter = blockIter->get()->getInstructions().erase(instIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto succblock : blockIter->get()->getSuccessors()) {
|
||||
for (auto &phiinst : succblock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法正确地删除对应于被删除基本块的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(blockIter->get());
|
||||
}
|
||||
}
|
||||
// 删除不可达基本块,注意迭代器不可达问题
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
blockIter++;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 删除空块
|
||||
bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
|
||||
bool changed = false;
|
||||
|
||||
// 收集不可达基本块
|
||||
// 这里的不可达基本块是指没有实际指令的基本块
|
||||
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时,也会被视作不可达
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
std::map<sysy::BasicBlock *, BasicBlock *> EmptyBlocks;
|
||||
// 空块儿和后继的基本块的映射
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (basicBlock->getNumInstructions() == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
else{
|
||||
// 如果只有phi指令和一个uncondbr。(phi)*(uncondbr)?
|
||||
// 判断除了最后一个指令之外是不是只有phi指令
|
||||
bool onlyPhi = true;
|
||||
for (auto &inst : basicBlock->getInstructions()) {
|
||||
if (!inst->isPhi() && !inst->isUnconditional()) {
|
||||
onlyPhi = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(onlyPhi && basicBlock->getNumSuccessors() == 1) // 确保有后继且只有一个
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
// 更新基本块信息,增加必要指令
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
// 把空块转换成只有跳转指令的不可达块 (这段逻辑在优化遍中可能需要调整,这里是原样保留)
|
||||
// 通常,DelEmptyBlock 应该在BlockMerge之后运行,如果存在完全空块,它会尝试填充一个Br指令。
|
||||
// 但是,它主要目的是重定向跳转。
|
||||
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (basicBlock->getNumSuccessors() > 1) {
|
||||
// 如果一个空块有多个后继,说明CFG结构有问题或者需要特殊处理,这里简单assert
|
||||
assert(false && "Empty block with multiple successors found during SysYDelEmptyBlock");
|
||||
}
|
||||
// 这里的逻辑有点问题,如果一个块是空的,且只有一个后继,应该直接跳转到后继。
|
||||
// 如果这个块最终被删除了,那么其前驱也需要重定向。
|
||||
// 这个循环的目的是重定向现有的跳转指令,而不是创建新的。
|
||||
// 所以下面的逻辑才是核心。
|
||||
// pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
// pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
continue;
|
||||
}
|
||||
|
||||
auto thelastinst = basicBlock->getInstructions().end();
|
||||
--thelastinst;
|
||||
|
||||
// 根据br指令传递的后继块信息,跳过空块链
|
||||
if (thelastinst->get()->isUnconditional()) {
|
||||
BasicBlock* OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
// 如果空块链表为多个块
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
|
||||
}
|
||||
|
||||
// 如果有重定向发生
|
||||
if (thelastBlockOld != nullptr) {
|
||||
basicBlock->removeSuccessor(OldBrBlock);
|
||||
OldBrBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (thelastinst->get()->getKind() == Instruction::kCondBr) {
|
||||
auto OldThenBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
auto OldElseBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
bool thenChanged = false;
|
||||
bool elseChanged = false;
|
||||
|
||||
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
thelastinst->get()->replaceOperand(
|
||||
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
|
||||
thenChanged = true;
|
||||
}
|
||||
|
||||
if (thenChanged) {
|
||||
basicBlock->removeSuccessor(OldThenBlock);
|
||||
OldThenBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
SysYIROptUtils::usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
thelastinst->get()->replaceOperand(
|
||||
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
|
||||
elseChanged = true;
|
||||
}
|
||||
|
||||
if (elseChanged) {
|
||||
basicBlock->removeSuccessor(OldElseBlock);
|
||||
OldElseBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
SysYIROptUtils::usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 如果有重定向发生
|
||||
// 需要更新后继块的前驱关系
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 如果不是终止指令,但有后继 (例如,末尾没有显式终止指令的块)
|
||||
// 这段逻辑可能需要更严谨的CFG检查来确保正确性
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
// 这里的逻辑似乎是想为没有terminator的块添加一个,但通常这应该在CFG构建阶段完成。
|
||||
// 如果这里仍然执行,确保它符合预期。
|
||||
// pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
// pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
// auto thelastinst = basicBlock->getInstructions().end();
|
||||
// (--thelastinst);
|
||||
// auto OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
// sysy::BasicBlock *thelastBlockOld = nullptr;
|
||||
// while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||
// EmptyBlocks.end()) {
|
||||
// thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
|
||||
// thelastinst->get()->replaceOperand(
|
||||
// 0, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))]);
|
||||
// }
|
||||
|
||||
// basicBlock->removeSuccessor(OldBrBlock);
|
||||
// OldBrBlock->removePredecessor(basicBlock.get());
|
||||
// basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
// dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
// changed = true; // 标记IR被修改
|
||||
// if (thelastBlockOld != nullptr) {
|
||||
// int indexphi = 0;
|
||||
// for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||
// if (pred == thelastBlockOld) {
|
||||
// break;
|
||||
// }
|
||||
// indexphi++;
|
||||
// }
|
||||
|
||||
// for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
// if (InstInNew->isPhi()) {
|
||||
// dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 真正的删除空块
|
||||
for (auto iter = func->getBasicBlocks().begin(); iter != func->getBasicBlocks().end();) {
|
||||
|
||||
if (EmptyBlocks.count(iter->get())) {
|
||||
// EntryBlock跳过
|
||||
if (iter->get() == func->getEntryBlock()) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto instIter = iter->get()->getInstructions().begin();
|
||||
instIter != iter->get()->getInstructions().end();) {
|
||||
SysYIROptUtils::usedelete(instIter->get()); // 仅删除 use 关系
|
||||
// 显式地从基本块中删除指令并更新迭代器
|
||||
instIter = iter->get()->getInstructions().erase(instIter);
|
||||
}
|
||||
// 删除不可达基本块的phi指令的操作数
|
||||
for (auto &succ : iter->get()->getSuccessors()) {
|
||||
for (auto &instinsucc : succ->getInstructions()) {
|
||||
if (instinsucc->isPhi()) {
|
||||
// iter->get() 就是当前被删除的空基本块,它作为前驱连接到这里的Phi指令
|
||||
dynamic_cast<PhiInst *>(instinsucc.get())->delBlk(iter->get());
|
||||
} else {
|
||||
// Phi 指令通常在基本块的开头,如果不是 Phi 指令就停止检查
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func->removeBasicBlock((iter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
|
||||
bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
|
||||
bool changed = false;
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &block : basicBlocks) {
|
||||
if (block->getNumSuccessors() == 0) {
|
||||
// 如果基本块没有后继块,则添加一个返回指令
|
||||
if (block->getNumInstructions() == 0) {
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
pBuilder->createReturnInst();
|
||||
changed = true; // 标记IR被修改
|
||||
} else {
|
||||
auto thelastinst = block->getInstructions().end();
|
||||
--thelastinst;
|
||||
if (thelastinst->get()->getKind() != Instruction::kReturn) {
|
||||
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
|
||||
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
// TODO: 如果int float函数缺少返回值是否需要报错
|
||||
if (func->getReturnType()->isInt()) {
|
||||
pBuilder->createReturnInst(ConstantInteger::get(0));
|
||||
} else if (func->getReturnType()->isFloat()) {
|
||||
pBuilder->createReturnInst(ConstantFloating::get(0.0F));
|
||||
} else {
|
||||
pBuilder->createReturnInst();
|
||||
}
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 条件分支转换为无条件分支
|
||||
// 主要针对已知条件值的分支转换为无条件分支
|
||||
// 例如 if (cond) { ... } else { ... } 中的 cond 已经
|
||||
// 确定为 true 或 false 的情况
|
||||
bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
||||
bool changed = false;
|
||||
|
||||
for (auto &basicblock : func->getBasicBlocks()) {
|
||||
if (basicblock->getNumInstructions() == 0)
|
||||
continue;
|
||||
|
||||
auto thelast = basicblock->getInstructions().end();
|
||||
--thelast;
|
||||
|
||||
if (thelast->get()->isConditional()){
|
||||
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(thelast->get()->getOperand(0));
|
||||
std::string opname;
|
||||
int constint = 0;
|
||||
float constfloat = 0.0F;
|
||||
bool constint_Use = false;
|
||||
bool constfloat_Use = false;
|
||||
if (constOperand != nullptr) {
|
||||
if (constOperand->isFloat()) {
|
||||
constfloat = constOperand->getFloat();
|
||||
constfloat_Use = true;
|
||||
} else {
|
||||
constint = constOperand->getInt();
|
||||
constint_Use = true;
|
||||
}
|
||||
}
|
||||
// 如果可以计算
|
||||
if (constfloat_Use || constint_Use) {
|
||||
changed = true;
|
||||
|
||||
auto thenBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(1));
|
||||
auto elseBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(2));
|
||||
SysYIROptUtils::usedelete(thelast->get());
|
||||
thelast = basicblock->getInstructions().erase(thelast);
|
||||
if ((constfloat_Use && constfloat == 1.0F) || (constint_Use && constint == 1)) {
|
||||
// cond为true或非0
|
||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
||||
pBuilder->createUncondBrInst(thenBlock, {});
|
||||
|
||||
// 更新CFG关系
|
||||
basicblock->removeSuccessor(elseBlock);
|
||||
elseBlock->removePredecessor(basicblock.get());
|
||||
|
||||
// 删除elseBlock的phi指令中对应的basicblock.get()的传入值
|
||||
for (auto &phiinst : elseBlock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(basicblock.get());
|
||||
}
|
||||
|
||||
} else { // cond为false或0
|
||||
|
||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
||||
pBuilder->createUncondBrInst(elseBlock, {});
|
||||
|
||||
// 更新CFG关系
|
||||
basicblock->removeSuccessor(thenBlock);
|
||||
thenBlock->removePredecessor(basicblock.get());
|
||||
|
||||
// 删除thenBlock的phi指令中对应的basicblock.get()的传入值
|
||||
for (auto &phiinst : thenBlock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(basicblock.get());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// 独立的CFG优化遍的实现
|
||||
// ======================================================================
|
||||
|
||||
bool SysYDelInstAfterBrPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
return SysYCFGOptUtils::SysYDelInstAfterBr(F);
|
||||
}
|
||||
|
||||
bool SysYDelEmptyBlockPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
return SysYCFGOptUtils::SysYDelEmptyBlock(F, pBuilder);
|
||||
}
|
||||
|
||||
bool SysYDelNoPreBLockPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
return SysYCFGOptUtils::SysYDelNoPreBLock(F);
|
||||
}
|
||||
|
||||
bool SysYBlockMergePass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
return SysYCFGOptUtils::SysYBlockMerge(F);
|
||||
}
|
||||
|
||||
bool SysYAddReturnPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
return SysYCFGOptUtils::SysYAddReturn(F, pBuilder);
|
||||
}
|
||||
|
||||
bool SysYCondBr2BrPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
return SysYCFGOptUtils::SysYCondBr2Br(F, pBuilder);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
223
src/midend/Pass/Pass.cpp
Normal file
223
src/midend/Pass/Pass.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
#include "Dom.h"
|
||||
#include "Liveness.h"
|
||||
#include "SysYIRCFGOpt.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
#include "DCE.h"
|
||||
#include "Mem2Reg.h"
|
||||
#include "Reg2Mem.h"
|
||||
#include "Pass.h"
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
extern int DEBUG; // 全局调试标志
|
||||
namespace sysy {
|
||||
|
||||
// ======================================================================
|
||||
// 封装优化流程的函数:包含Pass注册和迭代运行逻辑
|
||||
// ======================================================================
|
||||
|
||||
void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR, int optLevel) {
|
||||
if (DEBUG) std::cout << "--- Starting Middle-End Optimizations (Level -O" << optLevel << ") ---\n";
|
||||
|
||||
/*
|
||||
中端开发框架基本流程:
|
||||
1) 分析pass
|
||||
1. 实现分析pass并引入Pass.cpp
|
||||
2. 注册分析pass
|
||||
2) 优化pass
|
||||
1. 实现优化pass并引入Pass.cpp
|
||||
2. 注册优化pass
|
||||
3. 添加优化passid
|
||||
*/
|
||||
// 注册分析遍
|
||||
registerAnalysisPass<sysy::DominatorTreeAnalysisPass>();
|
||||
registerAnalysisPass<sysy::LivenessAnalysisPass>();
|
||||
|
||||
// 注册优化遍
|
||||
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
||||
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
||||
registerOptimizationPass<SysYBlockMergePass>();
|
||||
|
||||
registerOptimizationPass<SysYDelEmptyBlockPass>(builderIR);
|
||||
registerOptimizationPass<SysYCondBr2BrPass>(builderIR);
|
||||
registerOptimizationPass<SysYAddReturnPass>(builderIR);
|
||||
|
||||
registerOptimizationPass<DCE>();
|
||||
registerOptimizationPass<Mem2Reg>(builderIR);
|
||||
registerOptimizationPass<Reg2Mem>(builderIR);
|
||||
|
||||
if (optLevel >= 1) {
|
||||
//经过设计安排优化遍的执行顺序以及执行逻辑
|
||||
if (DEBUG) std::cout << "Applying -O1 optimizations.\n";
|
||||
if (DEBUG) std::cout << "--- Running custom optimization sequence ---\n";
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&SysYDelInstAfterBrPass::ID);
|
||||
this->addPass(&SysYDelNoPreBLockPass::ID);
|
||||
this->addPass(&SysYBlockMergePass::ID);
|
||||
this->addPass(&SysYDelEmptyBlockPass::ID);
|
||||
this->addPass(&SysYCondBr2BrPass::ID);
|
||||
this->addPass(&SysYAddReturnPass::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After CFGOpt Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&DCE::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After DCE Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&Mem2Reg::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After Mem2Reg Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&Reg2Mem::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
if (DEBUG) std::cout << "--- Custom optimization sequence finished ---\n";
|
||||
}
|
||||
|
||||
// 2. 创建遍管理器
|
||||
// 3. 根据优化级别添加不同的优化遍
|
||||
// TODO : 根据 optLevel 添加不同的优化遍
|
||||
// 讨论 是不动点迭代进行优化遍还是手动客制化优化遍的顺序?
|
||||
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "=== Final IR After Middle-End Optimizations (Level -O" << optLevel << ") ===\n";
|
||||
SysYPrinter printer(moduleIR);
|
||||
printer.printIR();
|
||||
}
|
||||
}
|
||||
|
||||
void PassManager::clearPasses() {
|
||||
passes.clear();
|
||||
}
|
||||
|
||||
void PassManager::addPass(void *passID) {
|
||||
|
||||
PassRegistry ®istry = PassRegistry::getPassRegistry();
|
||||
std::unique_ptr<Pass> P = registry.createPass(passID);
|
||||
if (!P) {
|
||||
// Error: Pass not found or failed to create
|
||||
return;
|
||||
}
|
||||
|
||||
passes.push_back(std::move(P));
|
||||
}
|
||||
|
||||
// 运行所有注册的遍
|
||||
bool PassManager::run() {
|
||||
bool changed = false;
|
||||
for (const auto &p : passes) {
|
||||
bool passChanged = false; // 记录当前遍是否修改了 IR
|
||||
|
||||
// 处理优化遍的分析依赖和失效
|
||||
if (p->getPassKind() == Pass::PassKind::Optimization) {
|
||||
OptimizationPass *optPass = static_cast<OptimizationPass *>(p.get());
|
||||
std::set<void *> analysisDependencies;
|
||||
std::set<void *> analysisInvalidations;
|
||||
optPass->getAnalysisUsage(analysisDependencies, analysisInvalidations);
|
||||
|
||||
// PassManager 不显式运行分析依赖。
|
||||
// 而是优化遍在 runOnFunction 内部通过 AnalysisManager.getAnalysisResult 按需请求。
|
||||
}
|
||||
|
||||
if (p->getGranularity() == Pass::Granularity::Module) {
|
||||
passChanged = p->runOnModule(pmodule, analysisManager);
|
||||
} else if (p->getGranularity() == Pass::Granularity::Function) {
|
||||
for (auto &funcPair : pmodule->getFunctions()) {
|
||||
Function *F = funcPair.second.get();
|
||||
passChanged = p->runOnFunction(F, analysisManager) || passChanged;
|
||||
|
||||
if (passChanged && p->getPassKind() == Pass::PassKind::Optimization) {
|
||||
OptimizationPass *optPass = static_cast<OptimizationPass *>(p.get());
|
||||
std::set<void *> analysisDependencies;
|
||||
std::set<void *> analysisInvalidations;
|
||||
optPass->getAnalysisUsage(analysisDependencies, analysisInvalidations);
|
||||
for (void *invalidationID : analysisInvalidations) {
|
||||
analysisManager.invalidateAnalysis(invalidationID, F);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (p->getGranularity() == Pass::Granularity::BasicBlock) {
|
||||
for (auto &funcPair : pmodule->getFunctions()) {
|
||||
Function *F = funcPair.second.get();
|
||||
for (auto &bbPtr : funcPair.second->getBasicBlocks()) {
|
||||
passChanged = p->runOnBasicBlock(bbPtr.get(), analysisManager) || passChanged;
|
||||
|
||||
if (passChanged && p->getPassKind() == Pass::PassKind::Optimization) {
|
||||
OptimizationPass *optPass = static_cast<OptimizationPass *>(p.get());
|
||||
std::set<void *> analysisDependencies;
|
||||
std::set<void *> analysisInvalidations;
|
||||
optPass->getAnalysisUsage(analysisDependencies, analysisInvalidations);
|
||||
for (void *invalidationID : analysisInvalidations) {
|
||||
analysisManager.invalidateAnalysis(invalidationID, F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
changed = changed || passChanged;
|
||||
}
|
||||
return changed;
|
||||
|
||||
}
|
||||
|
||||
void PassManager::printPasses() const {
|
||||
std::cout << "Registered Passes:\n";
|
||||
for (const auto &p : passes) {
|
||||
std::cout << " - " << p->getName() << " (Granularity: "
|
||||
<< static_cast<int>(p->getGranularity())
|
||||
<< ", Kind: " << static_cast<int>(p->getPassKind()) << ")\n";
|
||||
}
|
||||
std::cout << "Total Passes: " << passes.size() << "\n";
|
||||
if (pmodule) {
|
||||
SysYPrinter printer(pmodule);
|
||||
std::cout << "Module IR:\n";
|
||||
printer.printIR();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename AnalysisPassType> void registerAnalysisPass() {
|
||||
PassRegistry::getPassRegistry().registerPass(&AnalysisPassType::ID,
|
||||
[]() { return std::make_unique<AnalysisPassType>(); });
|
||||
}
|
||||
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type>
|
||||
void registerOptimizationPass(IRBuilder* builder) {
|
||||
PassRegistry::getPassRegistry().registerPass(&OptimizationPassType::ID,
|
||||
[builder]() { return std::make_unique<OptimizationPassType>(builder); });
|
||||
}
|
||||
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
!std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type>
|
||||
void registerOptimizationPass() {
|
||||
PassRegistry::getPassRegistry().registerPass(&OptimizationPassType::ID,
|
||||
[]() { return std::make_unique<OptimizationPassType>(); });
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
Reference in New Issue
Block a user