[midend-Alias]应用别名分析结果,sccp现在能简单传播数组元素了

This commit is contained in:
rain2133
2025-08-08 02:12:32 +08:00
parent b1a46b7d58
commit a406e44df3
7 changed files with 590 additions and 38 deletions

View File

@@ -1,9 +1,9 @@
#include "DCE.h" // 包含DCE遍的头文件
#include "IR.h" // 包含IR相关的定义
#include "SysYIROptUtils.h" // 包含SysY IR优化工具类的定义
#include <cassert> // 用于断言
#include <iostream> // 用于调试输出
#include <set> // 包含set虽然DCEContext内部用unordered_set但这里保留
#include "DCE.h"
#include "SysYIROptUtils.h"
#include "SideEffectAnalysis.h"
#include <cassert>
#include <iostream>
#include <set>
namespace sysy {
@@ -17,10 +17,26 @@ void *DCE::ID = (void *)&DCE::ID;
// DCEContext 的 run 方法实现
void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
// 获取别名分析结果
if (AM) {
aliasAnalysis = AM->getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(func);
// 获取副作用分析结果
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>(func);
if (DEBUG) {
if (aliasAnalysis) {
std::cout << "DCE: Using alias analysis results" << std::endl;
}
if (sideEffectAnalysis) {
std::cout << "DCE: Using side effect analysis results" << std::endl;
}
}
}
// 清空活跃指令集合,确保每次运行都是新的状态
alive_insts.clear();
// 第一次遍历:扫描所有指令,识别天然活跃的指令并将其及其依赖标记为活跃
// 第一次遍历:扫描所有指令,识别"天然活跃"的指令并将其及其依赖标记为活跃
// 使用 func->getBasicBlocks() 获取基本块列表,保留用户风格
auto basicBlocks = func->getBasicBlocks();
for (auto &basicBlock : basicBlocks) {
@@ -51,7 +67,7 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
// 如果指令不在活跃集合中,则删除它。
// 分支和返回指令由 isAlive 处理,并会被保留。
if (alive_insts.count(currentInst) == 0) {
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
changed = true; // 标记 IR 已被修改
} else {
++instIter; // 指令活跃,移动到下一个
@@ -60,20 +76,58 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
}
}
// 判断指令是否是天然活跃的实现
// 判断指令是否是"天然活跃"的实现
// 只有具有副作用的指令(如存储、函数调用、原子操作)
// 和控制流指令(如分支、返回)是天然活跃的。
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;
// 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程
if (inst->isBranch() || inst->isReturn()) {
return true;
}
// 使用副作用分析来判断指令是否有副作用
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
return true;
}
// 特殊处理Store指令使用别名分析进行更精确的判断
if (inst->isStore()) {
auto* storeInst = static_cast<StoreInst*>(inst);
return mayHaveSideEffect(storeInst);
}
// 特殊处理Memset指令总是保留因为它修改内存
if (inst->isMemset()) {
return true;
}
// 函数调用指令:总是保留(可能有未知副作用)
if (inst->isCall()) {
return true;
}
// 其他指令算术、逻辑、Load等无副作用可以删除
return false;
}
// 检查Store指令是否可能有副作用通过别名分析
bool DCEContext::mayHaveSideEffect(StoreInst* store) {
if (!aliasAnalysis) {
// 没有别名分析结果时保守地认为所有store都有副作用
return true;
}
Value* storePtr = store->getPointer();
// 如果是对本地数组的存储且访问模式是常量,可能可以安全删除
if (aliasAnalysis->isLocalArray(storePtr)) {
// 检查是否有其他指令可能读取这个位置
// 这里需要更复杂的活性分析,暂时保守处理
return true; // 保守地保留所有本地数组的存储
}
// 对全局变量、函数参数等的存储总是有副作用
return true;
}
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
@@ -102,7 +156,6 @@ void DCEContext::addAlive(Instruction *inst) {
// DCE 遍的 runOnFunction 方法实现
bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
DCEContext ctx;
bool changed = false;
ctx.run(func, &AM, changed); // 运行 DCE 优化
@@ -120,7 +173,11 @@ bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
// 声明DCE遍的分析依赖和失效信息
void DCE::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// DCE依赖特定的分析结果,它通过遍历和副作用判断来工作。
// DCE依赖别名分析来更精确地判断Store指令的副作用
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
// DCE依赖副作用分析来判断指令是否有副作用
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
// DCE会删除指令这会影响许多分析结果。
// 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。