114 lines
4.8 KiB
C++
114 lines
4.8 KiB
C++
#pragma once
|
||
|
||
#include "Pass.h" // 包含Pass的基类定义
|
||
#include "IR.h" // 包含IR相关的定义,如Instruction, Function, BasicBlock, AllocaInst, LoadInst, StoreInst, PhiInst等
|
||
#include "Dom.h" // 假设支配树分析的头文件,提供 DominatorTreeAnalysisResult
|
||
#include <vector>
|
||
#include <unordered_map>
|
||
#include <unordered_set>
|
||
#include <queue>
|
||
#include <stack> // 用于变量重命名阶段的SSA值栈
|
||
|
||
namespace sysy {
|
||
|
||
// 前向声明分析结果类,确保在需要时可以引用
|
||
class DominatorTree;
|
||
|
||
// Mem2RegContext 类,封装 mem2reg 遍的核心逻辑和状态
|
||
// 这样可以避免静态变量在多线程或多次运行时的冲突,并保持代码的模块化
|
||
class Mem2RegContext {
|
||
public:
|
||
|
||
Mem2RegContext(IRBuilder *builder) : builder(builder) {}
|
||
// 运行 mem2reg 优化的主要方法
|
||
// func: 当前要优化的函数
|
||
// tp: 分析管理器,用于获取支配树等分析结果
|
||
void run(Function* func, AnalysisManager* tp);
|
||
|
||
private:
|
||
IRBuilder *builder; // IR 构建器,用于插入指令
|
||
// 存储所有需要被提升的 AllocaInst
|
||
std::vector<AllocaInst*> promotableAllocas;
|
||
|
||
// 存储每个 AllocaInst 对应的 Phi 指令列表
|
||
// 键是 AllocaInst,值是该 AllocaInst 在各个基本块中插入的 Phi 指令的列表
|
||
// (实际上,一个 AllocaInst 在一个基本块中只会有一个 Phi)
|
||
std::unordered_map<AllocaInst*, std::unordered_map<BasicBlock*, PhiInst*>> allocaToPhiMap;
|
||
|
||
// 存储每个 AllocaInst 对应的当前活跃 SSA 值栈
|
||
// 用于在变量重命名阶段追踪每个 AllocaInst 在不同控制流路径上的最新值
|
||
std::unordered_map<AllocaInst*, std::stack<Value*>> allocaToValueStackMap;
|
||
|
||
// 辅助映射,存储每个 AllocaInst 的所有 store 指令
|
||
std::unordered_map<AllocaInst*, std::unordered_set<StoreInst*>> allocaToStoresMap;
|
||
|
||
// 辅助映射,存储每个 AllocaInst 对应的定义基本块(包含 store 指令的块)
|
||
std::unordered_map<AllocaInst*, std::unordered_set<BasicBlock*>> allocaToDefBlocksMap;
|
||
|
||
// 支配树分析结果,用于 Phi 插入和变量重命名
|
||
DominatorTree* dt;
|
||
|
||
// --------------------------------------------------------------------
|
||
// 阶段1: 识别可提升的 AllocaInst
|
||
// --------------------------------------------------------------------
|
||
|
||
// 判断一个 AllocaInst 是否可以被提升到寄存器
|
||
// alloca: 要检查的 AllocaInst
|
||
// 返回值: 如果可以提升,则为 true,否则为 false
|
||
bool isPromotableAlloca(AllocaInst* alloca);
|
||
|
||
// 收集所有对给定 AllocaInst 进行存储的 StoreInst
|
||
// alloca: 目标 AllocaInst
|
||
void collectStores(AllocaInst* alloca);
|
||
|
||
// --------------------------------------------------------------------
|
||
// 阶段2: 插入 Phi 指令 (Phi Insertion)
|
||
// --------------------------------------------------------------------
|
||
|
||
// 为给定的 AllocaInst 插入必要的 Phi 指令
|
||
// alloca: 目标 AllocaInst
|
||
// defBlocks: 包含对该 AllocaInst 进行 store 操作的基本块集合
|
||
void insertPhis(AllocaInst* alloca, const std::unordered_set<BasicBlock*>& defBlocks);
|
||
|
||
// --------------------------------------------------------------------
|
||
// 阶段3: 变量重命名 (Variable Renaming)
|
||
// --------------------------------------------------------------------
|
||
|
||
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
|
||
void renameVariables(BasicBlock* currentBB);
|
||
|
||
// --------------------------------------------------------------------
|
||
// 阶段4: 清理
|
||
// --------------------------------------------------------------------
|
||
|
||
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst
|
||
void cleanup();
|
||
};
|
||
|
||
// Mem2Reg 优化遍类,继承自 OptimizationPass
|
||
// 粒度为 Function,表示它在每个函数上独立运行
|
||
class Mem2Reg : public OptimizationPass {
|
||
private:
|
||
IRBuilder *builder;
|
||
|
||
public:
|
||
// 构造函数
|
||
Mem2Reg(IRBuilder *builder) : OptimizationPass("Mem2Reg", Granularity::Function), builder(builder) {}
|
||
|
||
// 静态成员,作为该遍的唯一ID
|
||
static void *ID;
|
||
|
||
// 运行在函数上的优化逻辑
|
||
// F: 当前要优化的函数
|
||
// AM: 分析管理器,用于获取支配树等分析结果,或使分析结果失效
|
||
// 返回值: 如果IR被修改,则为true,否则为false
|
||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||
|
||
// 声明该遍的分析依赖和失效信息
|
||
// analysisDependencies: 该遍运行前需要哪些分析结果
|
||
// analysisInvalidations: 该遍运行后会使哪些分析结果失效
|
||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||
void *getPassID() const override { return &ID; }
|
||
};
|
||
|
||
} // namespace sysy
|