Compare commits
11 Commits
midend-Loo
...
midend-Loo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f317010d76 | ||
|
|
8ca64610eb | ||
|
|
969a78a088 | ||
|
|
8763c0a11a | ||
|
|
d83dc7a2e7 | ||
|
|
e32585fd25 | ||
|
|
c4eb1c3980 | ||
|
|
d038884ffb | ||
|
|
467f2f6b24 | ||
|
|
fa33bf5134 | ||
|
|
a3435e7c26 |
@@ -396,9 +396,25 @@ check_initial_overflow()
|
||||
智能回退:使用已验证的标准值保证正确性
|
||||
保持通用性:对于没有预设值的除数仍然可以工作
|
||||
|
||||
## 死归纳变量消除
|
||||
|
||||
整体架构和工作流程
|
||||
当前的归纳变量消除优化分为三个清晰的阶段:
|
||||
|
||||
识别阶段:找出所有潜在的死归纳变量
|
||||
安全性分析阶段:验证每个变量消除的安全性
|
||||
消除执行阶段:实际删除安全的死归纳变量
|
||||
|
||||
|
||||
逃逸点检测 (已修复的关键安全机制)
|
||||
数组索引检测:GEP指令被正确识别为逃逸点
|
||||
循环退出条件:用于比较和条件分支的归纳变量不会被消除
|
||||
控制流指令:condBr、br、return等被特殊处理为逃逸点
|
||||
内存操作:store/load指令经过别名分析检查
|
||||
|
||||
# 后续优化可能涉及的改动
|
||||
|
||||
## 1)将所有的alloca集中到entryblock中
|
||||
## 1)将所有的alloca集中到entryblock中(已实现)
|
||||
|
||||
好处:优化友好性,方便mem2reg提升
|
||||
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分
|
||||
|
||||
@@ -350,7 +350,11 @@ private:
|
||||
std::set<Value*>& visited
|
||||
);
|
||||
bool isBasicInductionVariable(Value* val, Loop* loop);
|
||||
bool hasSimpleMemoryPattern(Loop* loop); // 简单的内存模式检查
|
||||
// ========== 循环不变量分析辅助方法 ==========
|
||||
bool isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants);
|
||||
bool isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop);
|
||||
bool isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst = nullptr);
|
||||
bool isPureFunction(Function* calledFunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
87
src/include/midend/Pass/Optimize/GVN.h
Normal file
87
src/include/midend/Pass/Optimize/GVN.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// GVN优化遍的核心逻辑封装类
|
||||
class GVNContext {
|
||||
public:
|
||||
// 运行GVN优化的主要方法
|
||||
void run(Function* func, AnalysisManager* AM, bool& changed);
|
||||
|
||||
private:
|
||||
// 新的值编号系统
|
||||
std::unordered_map<Value*, unsigned> valueToNumber; // Value -> 值编号
|
||||
std::unordered_map<unsigned, Value*> numberToValue; // 值编号 -> 代表值
|
||||
std::unordered_map<std::string, unsigned> expressionToNumber; // 表达式 -> 值编号
|
||||
unsigned nextValueNumber = 1;
|
||||
|
||||
// 已访问的基本块集合
|
||||
std::unordered_set<BasicBlock*> visited;
|
||||
|
||||
// 逆后序遍历的基本块列表
|
||||
std::vector<BasicBlock*> rpoBlocks;
|
||||
|
||||
// 需要删除的指令集合
|
||||
std::unordered_set<Instruction*> needRemove;
|
||||
|
||||
// 分析结果
|
||||
DominatorTree* domTree = nullptr;
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 计算逆后序遍历
|
||||
void computeRPO(Function* func);
|
||||
void dfs(BasicBlock* bb);
|
||||
|
||||
// 新的值编号方法
|
||||
unsigned getValueNumber(Value* value);
|
||||
unsigned assignValueNumber(Value* value);
|
||||
|
||||
// 基本块处理
|
||||
void processBasicBlock(BasicBlock* bb, bool& changed);
|
||||
|
||||
// 指令处理
|
||||
bool processInstruction(Instruction* inst);
|
||||
|
||||
// 表达式构建和查找
|
||||
std::string buildExpressionKey(Instruction* inst);
|
||||
Value* findExistingValue(const std::string& exprKey, Instruction* inst);
|
||||
|
||||
// 支配关系和安全性检查
|
||||
bool dominates(Instruction* a, Instruction* b);
|
||||
bool isMemorySafe(LoadInst* earlierLoad, LoadInst* laterLoad);
|
||||
|
||||
// 清理方法
|
||||
void eliminateRedundantInstructions(bool& changed);
|
||||
void invalidateMemoryValues(StoreInst* store);
|
||||
};
|
||||
|
||||
// GVN优化遍类
|
||||
class GVN : public OptimizationPass {
|
||||
public:
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void* ID;
|
||||
|
||||
GVN() : OptimizationPass("GVN", Granularity::Function) {}
|
||||
|
||||
// 在函数上运行优化
|
||||
bool runOnFunction(Function* func, AnalysisManager& AM) override;
|
||||
|
||||
// 返回该遍的唯一ID
|
||||
void* getPassID() const override { return ID; }
|
||||
|
||||
// 声明分析依赖
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@@ -53,6 +54,7 @@ private:
|
||||
LoopCharacteristicsResult* loopCharacteristics = nullptr;
|
||||
DominatorTree* dominatorTree = nullptr;
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
AliasAnalysisResult* aliasAnalysis = nullptr;
|
||||
|
||||
// 死归纳变量存储
|
||||
std::vector<std::unique_ptr<DeadInductionVariable>> deadIVs;
|
||||
@@ -90,12 +92,105 @@ private:
|
||||
isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查归纳变量是否只用于自身更新
|
||||
* 递归分析phi指令及其使用链是否都是死代码
|
||||
* @param phiInst phi指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否只用于自身更新
|
||||
* @return phi指令是否可以安全删除
|
||||
*/
|
||||
bool isUsedOnlyForSelfUpdate(PhiInst* phiInst, Loop* loop);
|
||||
bool isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归分析指令的使用链是否都是死代码
|
||||
* @param inst 要分析的指令
|
||||
* @param loop 所在循环
|
||||
* @param visited 已访问的指令集合(避免无限递归)
|
||||
* @param currentPath 当前递归路径(检测循环依赖)
|
||||
* @return 指令的使用链是否都是死代码
|
||||
*/
|
||||
bool isInstructionUseChainDeadRecursively(Instruction* inst, Loop* loop,
|
||||
std::set<Instruction*>& visited,
|
||||
std::set<Instruction*>& currentPath);
|
||||
|
||||
/**
|
||||
* 检查循环是否有副作用
|
||||
* @param loop 要检查的循环
|
||||
* @return 循环是否有副作用
|
||||
*/
|
||||
bool loopHasSideEffects(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否被用于循环退出条件
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否被用于循环退出条件
|
||||
*/
|
||||
bool isUsedInLoopExitCondition(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令的结果是否未被有效使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 指令结果是否未被有效使用
|
||||
*/
|
||||
bool isInstructionResultUnused(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查store指令是否存储到死地址(利用别名分析)
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否存储到死地址
|
||||
*/
|
||||
bool isStoreToDeadLocation(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否为死代码或只在循环内部使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否为死代码或只在循环内部使用
|
||||
*/
|
||||
bool isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否有效地为死代码(带递归深度限制)
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @param maxDepth 最大递归深度
|
||||
* @return 指令是否有效地为死代码
|
||||
*/
|
||||
bool isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth);
|
||||
|
||||
/**
|
||||
* 检查store指令是否有后续的load操作
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否有后续的load操作
|
||||
*/
|
||||
bool hasSubsequentLoad(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否在循环外有使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否在循环外有使用
|
||||
*/
|
||||
bool hasUsageOutsideLoop(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查store指令是否在循环外有后续的load操作
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否在循环外有后续的load操作
|
||||
*/
|
||||
bool hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归检查基本块子树中是否有对指定位置的load操作
|
||||
* @param bb 基本块
|
||||
* @param ptr 指针
|
||||
* @param visited 已访问的基本块集合
|
||||
* @return 是否有load操作
|
||||
*/
|
||||
bool hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited);
|
||||
|
||||
/**
|
||||
* 收集与归纳变量相关的所有指令
|
||||
|
||||
@@ -15,6 +15,7 @@ add_library(midend_lib STATIC
|
||||
Pass/Optimize/DCE.cpp
|
||||
Pass/Optimize/Mem2Reg.cpp
|
||||
Pass/Optimize/Reg2Mem.cpp
|
||||
Pass/Optimize/GVN.cpp
|
||||
Pass/Optimize/SysYIRCFGOpt.cpp
|
||||
Pass/Optimize/SCCP.cpp
|
||||
Pass/Optimize/LoopNormalization.cpp
|
||||
|
||||
@@ -847,7 +847,7 @@ void CondBrInst::print(std::ostream &os) const {
|
||||
|
||||
os << "%tmp_cond_" << condName << "_" << uniqueSuffix << " = icmp ne i32 ";
|
||||
printOperand(os, condition);
|
||||
os << ", 0\n br i1 %tmp_cond_" << condName << "_" << uniqueSuffix;
|
||||
os << ", 0\n br i1 %tmp_cond_" << condName << "_" << uniqueSuffix;
|
||||
|
||||
os << ", label %";
|
||||
printBlockName(os, getThenBlock());
|
||||
@@ -886,7 +886,7 @@ void MemsetInst::print(std::ostream &os) const {
|
||||
// This is done at print time to avoid modifying the IR structure
|
||||
os << "%tmp_bitcast_" << ptr->getName() << " = bitcast " << *ptr->getType() << " ";
|
||||
printOperand(os, ptr);
|
||||
os << " to i8*\n ";
|
||||
os << " to i8*\n ";
|
||||
|
||||
// Now call memset with the bitcast result
|
||||
os << "call void @llvm.memset.p0i8.i32(i8* %tmp_bitcast_" << ptr->getName() << ", i8 ";
|
||||
|
||||
@@ -776,38 +776,324 @@ void LoopCharacteristicsPass::findDerivedInductionVars(
|
||||
}
|
||||
}
|
||||
|
||||
// 递归/推进式判定
|
||||
bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants) {
|
||||
// 1. 常量
|
||||
if (auto* constval = dynamic_cast<ConstantValue*>(val)) return true;
|
||||
|
||||
// 2. 参数(函数参数)通常不在任何BasicBlock内,直接判定为不变量
|
||||
if (auto* arg = dynamic_cast<Argument*>(val)) return true;
|
||||
|
||||
// 3. 指令且定义在循环外
|
||||
if (auto* inst = dynamic_cast<Instruction*>(val)) {
|
||||
if (!loop->contains(inst->getParent()))
|
||||
return true;
|
||||
|
||||
// 4. 跳转 phi指令 副作用 不外提
|
||||
if (inst->isTerminator() || inst->isPhi() || sideEffectAnalysis->hasSideEffect(inst))
|
||||
// 检查操作数是否都是不变量
|
||||
bool LoopCharacteristicsPass::isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants) {
|
||||
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
|
||||
Value* op = inst->getOperand(i);
|
||||
if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op)) {
|
||||
return false;
|
||||
|
||||
// 5. 所有操作数都是不变量
|
||||
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
|
||||
Value* op = inst->getOperand(i);
|
||||
if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// 其它情况
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查内存位置是否在循环中被修改
|
||||
bool LoopCharacteristicsPass::isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop) {
|
||||
// 遍历循环中的所有指令,检查是否有对该内存位置的写入
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
// 1. 检查直接的Store指令
|
||||
if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
|
||||
Value* storeTar = storeInst->getPointer();
|
||||
|
||||
// 使用别名分析检查是否可能别名
|
||||
if (aliasAnalysis) {
|
||||
auto aliasType = aliasAnalysis->queryAlias(ptr, storeTar);
|
||||
if (aliasType != AliasType::NO_ALIAS) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Memory location " << ptr->getName()
|
||||
<< " may be modified by store to " << storeTar->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// 如果没有别名分析,保守处理 - 只检查精确匹配
|
||||
if (ptr == storeTar) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 检查函数调用是否可能修改该内存位置
|
||||
else if (auto* callInst = dynamic_cast<CallInst*>(inst.get())) {
|
||||
Function* calledFunc = callInst->getCallee();
|
||||
|
||||
// 如果是纯函数,不会修改内存
|
||||
if (isPureFunction(calledFunc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查函数参数中是否有该内存位置的指针
|
||||
for (size_t i = 1; i < callInst->getNumOperands(); ++i) { // 跳过函数指针
|
||||
Value* arg = callInst->getOperand(i);
|
||||
|
||||
// 检查参数是否是指针类型且可能指向该内存位置
|
||||
if (auto* ptrType = dynamic_cast<PointerType*>(arg->getType())) {
|
||||
// 使用别名分析检查
|
||||
if (aliasAnalysis) {
|
||||
auto aliasType = aliasAnalysis->queryAlias(ptr, arg);
|
||||
if (aliasType != AliasType::NO_ALIAS) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Memory location " << ptr->getName()
|
||||
<< " may be modified by function call " << calledFunc->getName()
|
||||
<< " through parameter " << arg->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// 没有别名分析,检查精确匹配
|
||||
if (ptr == arg) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Memory location " << ptr->getName()
|
||||
<< " may be modified by function call " << calledFunc->getName()
|
||||
<< " (exact match)" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LoopCharacteristicsPass::hasSimpleMemoryPattern(Loop* loop) {
|
||||
// 检查是否有简单的内存访问模式
|
||||
return true; // 暂时简化处理
|
||||
// 检查内存位置是否在循环中被读取
|
||||
bool LoopCharacteristicsPass::isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst) {
|
||||
// 遍历循环中的所有Load指令,检查是否有对该内存位置的读取
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (inst.get() == excludeInst) continue; // 排除当前指令本身
|
||||
|
||||
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
|
||||
Value* loadSrc = loadInst->getPointer();
|
||||
|
||||
// 使用别名分析检查是否可能别名
|
||||
if (aliasAnalysis) {
|
||||
auto aliasType = aliasAnalysis->queryAlias(ptr, loadSrc);
|
||||
if (aliasType != AliasType::NO_ALIAS) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// 如果没有别名分析,保守处理 - 只检查精确匹配
|
||||
if (ptr == loadSrc) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查函数调用是否为纯函数
|
||||
bool LoopCharacteristicsPass::isPureFunction(Function* calledFunc) {
|
||||
if (!calledFunc) return false;
|
||||
|
||||
// 使用副作用分析检查函数是否为纯函数
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->isPureFunction(calledFunc)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查是否为内置纯函数(如数学函数)
|
||||
std::string funcName = calledFunc->getName();
|
||||
static const std::set<std::string> pureFunctions = {
|
||||
"abs", "fabs", "sqrt", "sin", "cos", "tan", "exp", "log", "pow",
|
||||
"floor", "ceil", "round", "min", "max"
|
||||
};
|
||||
|
||||
return pureFunctions.count(funcName) > 0;
|
||||
}
|
||||
|
||||
// 递归/推进式判定 - 完善版本
|
||||
bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants) {
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Checking loop invariant for: " << val->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 1. 常量
|
||||
if (auto* constval = dynamic_cast<ConstantValue*>(val)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Constant: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. 参数(函数参数)通常不在任何BasicBlock内,直接判定为不变量
|
||||
// 在SSA形式下,参数不会被重新赋值
|
||||
if (auto* arg = dynamic_cast<Argument*>(val)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Function argument: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3. 指令且定义在循环外
|
||||
if (auto* inst = dynamic_cast<Instruction*>(val)) {
|
||||
if (!loop->contains(inst->getParent())) {
|
||||
if (DEBUG >= 2) std::cout << " -> Defined outside loop: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4. 跳转指令、phi指令不能外提
|
||||
if (inst->isTerminator() || inst->isPhi()) {
|
||||
if (DEBUG >= 2) std::cout << " -> Terminator or PHI: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. 根据指令类型进行具体分析
|
||||
switch (inst->getKind()) {
|
||||
case Instruction::Kind::kStore: {
|
||||
// Store指令:检查循环内是否有对该内存的load
|
||||
auto* storeInst = dynamic_cast<StoreInst*>(inst);
|
||||
Value* storePtr = storeInst->getPointer();
|
||||
|
||||
// 首先检查操作数是否不变
|
||||
if (!isInvariantOperands(inst, loop, invariants)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Store: operands not invariant: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有对该内存位置的load
|
||||
if (isMemoryLocationLoadedInLoop(storePtr, loop, inst)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Store: memory location loaded in loop: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) std::cout << " -> Store: safe to hoist: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Instruction::Kind::kLoad: {
|
||||
// Load指令:检查循环内是否有对该内存的store
|
||||
auto* loadInst = dynamic_cast<LoadInst*>(inst);
|
||||
Value* loadPtr = loadInst->getPointer();
|
||||
|
||||
// 首先检查指针操作数是否不变
|
||||
if (!isInvariantOperands(inst, loop, invariants)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Load: pointer not invariant: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有对该内存位置的store
|
||||
if (isMemoryLocationModifiedInLoop(loadPtr, loop)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Load: memory location modified in loop: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) std::cout << " -> Load: safe to hoist: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Instruction::Kind::kCall: {
|
||||
// Call指令:检查是否为纯函数且参数不变
|
||||
auto* callInst = dynamic_cast<CallInst*>(inst);
|
||||
Function* calledFunc = callInst->getCallee();
|
||||
|
||||
// 检查是否为纯函数
|
||||
if (!isPureFunction(calledFunc)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Call: not pure function: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查参数是否都不变
|
||||
if (!isInvariantOperands(inst, loop, invariants)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Call: arguments not invariant: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) std::cout << " -> Call: pure function with invariant args: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Instruction::Kind::kGetElementPtr: {
|
||||
// GEP指令:检查基址和索引是否都不变
|
||||
if (!isInvariantOperands(inst, loop, invariants)) {
|
||||
if (DEBUG >= 2) std::cout << " -> GEP: base or indices not invariant: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) std::cout << " -> GEP: base and indices invariant: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 一元运算指令
|
||||
case Instruction::Kind::kNeg:
|
||||
case Instruction::Kind::kNot:
|
||||
case Instruction::Kind::kFNeg:
|
||||
case Instruction::Kind::kFNot:
|
||||
case Instruction::Kind::kFtoI:
|
||||
case Instruction::Kind::kItoF:
|
||||
case Instruction::Kind::kBitItoF:
|
||||
case Instruction::Kind::kBitFtoI: {
|
||||
// 检查操作数是否不变
|
||||
if (!isInvariantOperands(inst, loop, invariants)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Unary op: operand not invariant: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) std::cout << " -> Unary op: operand invariant: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 二元运算指令
|
||||
case Instruction::Kind::kAdd:
|
||||
case Instruction::Kind::kSub:
|
||||
case Instruction::Kind::kMul:
|
||||
case Instruction::Kind::kDiv:
|
||||
case Instruction::Kind::kRem:
|
||||
case Instruction::Kind::kSll:
|
||||
case Instruction::Kind::kSrl:
|
||||
case Instruction::Kind::kSra:
|
||||
case Instruction::Kind::kAnd:
|
||||
case Instruction::Kind::kOr:
|
||||
case Instruction::Kind::kFAdd:
|
||||
case Instruction::Kind::kFSub:
|
||||
case Instruction::Kind::kFMul:
|
||||
case Instruction::Kind::kFDiv:
|
||||
case Instruction::Kind::kICmpEQ:
|
||||
case Instruction::Kind::kICmpNE:
|
||||
case Instruction::Kind::kICmpLT:
|
||||
case Instruction::Kind::kICmpGT:
|
||||
case Instruction::Kind::kICmpLE:
|
||||
case Instruction::Kind::kICmpGE:
|
||||
case Instruction::Kind::kFCmpEQ:
|
||||
case Instruction::Kind::kFCmpNE:
|
||||
case Instruction::Kind::kFCmpLT:
|
||||
case Instruction::Kind::kFCmpGT:
|
||||
case Instruction::Kind::kFCmpLE:
|
||||
case Instruction::Kind::kFCmpGE:
|
||||
case Instruction::Kind::kMulh: {
|
||||
// 检查所有操作数是否不变
|
||||
if (!isInvariantOperands(inst, loop, invariants)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Binary op: operands not invariant: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) std::cout << " -> Binary op: operands invariant: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
// 其他指令:使用副作用分析
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Other inst: has side effect: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查操作数是否都不变
|
||||
if (!isInvariantOperands(inst, loop, invariants)) {
|
||||
if (DEBUG >= 2) std::cout << " -> Other inst: operands not invariant: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) std::cout << " -> Other inst: no side effect, operands invariant: YES" << std::endl;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 其它情况
|
||||
if (DEBUG >= 2) std::cout << " -> Other value type: NO" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
@@ -26,10 +26,21 @@ const SideEffectInfo &SideEffectAnalysisResult::getInstructionSideEffect(Instruc
|
||||
}
|
||||
|
||||
const SideEffectInfo &SideEffectAnalysisResult::getFunctionSideEffect(Function *func) const {
|
||||
// 首先检查分析过的用户定义函数
|
||||
auto it = functionSideEffects.find(func);
|
||||
if (it != functionSideEffects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 如果没有找到,检查是否为已知的库函数
|
||||
if (func) {
|
||||
std::string funcName = func->getName();
|
||||
const SideEffectInfo *knownInfo = getKnownFunctionSideEffect(funcName);
|
||||
if (knownInfo) {
|
||||
return *knownInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回默认的无副作用信息
|
||||
static SideEffectInfo noEffect;
|
||||
return noEffect;
|
||||
|
||||
492
src/midend/Pass/Optimize/GVN.cpp
Normal file
492
src/midend/Pass/Optimize/GVN.cpp
Normal file
@@ -0,0 +1,492 @@
|
||||
#include "GVN.h"
|
||||
#include "Dom.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// GVN 遍的静态 ID
|
||||
void *GVN::ID = (void *)&GVN::ID;
|
||||
|
||||
// ======================================================================
|
||||
// GVN 类的实现
|
||||
// ======================================================================
|
||||
|
||||
bool GVN::runOnFunction(Function *func, AnalysisManager &AM) {
|
||||
if (func->getBasicBlocks().empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "\n=== Running GVN on function: " << func->getName() << " ===" << std::endl;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
GVNContext context;
|
||||
context.run(func, &AM, changed);
|
||||
|
||||
if (DEBUG) {
|
||||
if (changed) {
|
||||
std::cout << "GVN: Function " << func->getName() << " was modified" << std::endl;
|
||||
} else {
|
||||
std::cout << "GVN: Function " << func->getName() << " was not modified" << std::endl;
|
||||
}
|
||||
std::cout << "=== GVN completed for function: " << func->getName() << " ===" << std::endl;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void GVN::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// GVN依赖以下分析:
|
||||
// 1. 支配树分析 - 用于检查指令的支配关系,确保替换的安全性
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
|
||||
|
||||
// 2. 副作用分析 - 用于判断函数调用是否可以进行GVN
|
||||
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
|
||||
|
||||
// GVN不会使任何分析失效,因为:
|
||||
// - GVN只删除冗余计算,不改变CFG结构
|
||||
// - GVN不修改程序的语义,只是消除重复计算
|
||||
// - 支配关系保持不变
|
||||
// - 副作用分析结果保持不变
|
||||
// analysisInvalidations 保持为空
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "GVN: Declared analysis dependencies (DominatorTree, SideEffectAnalysis)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// GVNContext 类的实现 - 重构版本
|
||||
// ======================================================================
|
||||
|
||||
// 简单的表达式哈希结构
|
||||
struct ExpressionKey {
|
||||
enum Type { BINARY, UNARY, LOAD, GEP, CALL } type;
|
||||
int opcode;
|
||||
std::vector<Value*> operands;
|
||||
Type* resultType;
|
||||
|
||||
bool operator==(const ExpressionKey& other) const {
|
||||
return type == other.type && opcode == other.opcode &&
|
||||
operands == other.operands && resultType == other.resultType;
|
||||
}
|
||||
};
|
||||
|
||||
struct ExpressionKeyHash {
|
||||
size_t operator()(const ExpressionKey& key) const {
|
||||
size_t hash = std::hash<int>()(static_cast<int>(key.type)) ^
|
||||
std::hash<int>()(key.opcode);
|
||||
for (auto op : key.operands) {
|
||||
hash ^= std::hash<Value*>()(op) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
void GVNContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Starting GVN analysis for function: " << func->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 获取分析结果
|
||||
if (AM) {
|
||||
domTree = AM->getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(func);
|
||||
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
|
||||
|
||||
if (DEBUG) {
|
||||
if (domTree) {
|
||||
std::cout << " GVN: Using dominator tree analysis" << std::endl;
|
||||
} else {
|
||||
std::cout << " GVN: Warning - dominator tree analysis not available" << std::endl;
|
||||
}
|
||||
if (sideEffectAnalysis) {
|
||||
std::cout << " GVN: Using side effect analysis" << std::endl;
|
||||
} else {
|
||||
std::cout << " GVN: Warning - side effect analysis not available" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清空状态
|
||||
valueToNumber.clear();
|
||||
numberToValue.clear();
|
||||
expressionToNumber.clear();
|
||||
nextValueNumber = 1;
|
||||
visited.clear();
|
||||
rpoBlocks.clear();
|
||||
needRemove.clear();
|
||||
|
||||
// 计算逆后序遍历
|
||||
computeRPO(func);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Computed RPO with " << rpoBlocks.size() << " blocks" << std::endl;
|
||||
}
|
||||
|
||||
// 按逆后序遍历基本块进行GVN
|
||||
int blockCount = 0;
|
||||
for (auto bb : rpoBlocks) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing block " << ++blockCount << "/" << rpoBlocks.size()
|
||||
<< ": " << bb->getName() << std::endl;
|
||||
}
|
||||
|
||||
processBasicBlock(bb, changed);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Found " << needRemove.size() << " redundant instructions to remove" << std::endl;
|
||||
}
|
||||
|
||||
// 删除冗余指令
|
||||
eliminateRedundantInstructions(changed);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " GVN analysis completed for function: " << func->getName() << std::endl;
|
||||
std::cout << " Total values numbered: " << valueToNumber.size() << std::endl;
|
||||
std::cout << " Instructions eliminated: " << needRemove.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void GVNContext::computeRPO(Function *func) {
|
||||
rpoBlocks.clear();
|
||||
visited.clear();
|
||||
|
||||
auto entry = func->getEntryBlock();
|
||||
if (entry) {
|
||||
dfs(entry);
|
||||
std::reverse(rpoBlocks.begin(), rpoBlocks.end());
|
||||
}
|
||||
}
|
||||
|
||||
void GVNContext::dfs(BasicBlock *bb) {
|
||||
if (!bb || visited.count(bb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visited.insert(bb);
|
||||
|
||||
// 访问所有后继基本块
|
||||
for (auto succ : bb->getSuccessors()) {
|
||||
if (visited.find(succ) == visited.end()) {
|
||||
dfs(succ);
|
||||
}
|
||||
}
|
||||
|
||||
rpoBlocks.push_back(bb);
|
||||
}
|
||||
|
||||
unsigned GVNContext::getValueNumber(Value* value) {
|
||||
// 如果已经有值编号,直接返回
|
||||
auto it = valueToNumber.find(value);
|
||||
if (it != valueToNumber.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 为新值分配编号
|
||||
return assignValueNumber(value);
|
||||
}
|
||||
|
||||
unsigned GVNContext::assignValueNumber(Value* value) {
|
||||
unsigned number = nextValueNumber++;
|
||||
valueToNumber[value] = number;
|
||||
numberToValue[number] = value;
|
||||
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Assigned value number " << number
|
||||
<< " to " << value->getName() << std::endl;
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
void GVNContext::processBasicBlock(BasicBlock* bb, bool& changed) {
|
||||
int instCount = 0;
|
||||
for (auto &instPtr : bb->getInstructions()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing instruction " << ++instCount
|
||||
<< ": " << instPtr->getName() << std::endl;
|
||||
}
|
||||
|
||||
if (processInstruction(instPtr.get())) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GVNContext::processInstruction(Instruction* inst) {
|
||||
// 跳过分支指令和其他不可优化的指令
|
||||
if (inst->isBranch() || dynamic_cast<ReturnInst*>(inst) ||
|
||||
dynamic_cast<AllocaInst*>(inst) || dynamic_cast<StoreInst*>(inst)) {
|
||||
|
||||
// 如果是store指令,需要使相关的内存值失效
|
||||
if (auto store = dynamic_cast<StoreInst*>(inst)) {
|
||||
invalidateMemoryValues(store);
|
||||
}
|
||||
|
||||
// 为这些指令分配值编号但不尝试优化
|
||||
getValueNumber(inst);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing optimizable instruction: " << inst->getName()
|
||||
<< " (kind: " << static_cast<int>(inst->getKind()) << ")" << std::endl;
|
||||
}
|
||||
|
||||
// 构建表达式键
|
||||
std::string exprKey = buildExpressionKey(inst);
|
||||
if (exprKey.empty()) {
|
||||
// 不可优化的指令,只分配值编号
|
||||
getValueNumber(inst);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Expression key: " << exprKey << std::endl;
|
||||
}
|
||||
|
||||
// 查找已存在的等价值
|
||||
Value* existing = findExistingValue(exprKey, inst);
|
||||
if (existing && existing != inst) {
|
||||
// 检查支配关系
|
||||
if (auto existingInst = dynamic_cast<Instruction*>(existing)) {
|
||||
if (dominates(existingInst, inst)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " GVN: Replacing " << inst->getName()
|
||||
<< " with existing " << existing->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 用已存在的值替换当前指令
|
||||
inst->replaceAllUsesWith(existing);
|
||||
needRemove.insert(inst);
|
||||
|
||||
// 将当前指令的值编号指向已存在的值
|
||||
unsigned existingNumber = getValueNumber(existing);
|
||||
valueToNumber[inst] = existingNumber;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << " Found equivalent but dominance check failed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 没有找到等价值,为这个表达式分配新的值编号
|
||||
unsigned number = assignValueNumber(inst);
|
||||
expressionToNumber[exprKey] = number;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Instruction " << inst->getName() << " is unique" << std::endl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GVNContext::buildExpressionKey(Instruction* inst) {
|
||||
std::ostringstream oss;
|
||||
|
||||
if (auto binary = dynamic_cast<BinaryInst*>(inst)) {
|
||||
oss << "binary_" << static_cast<int>(binary->getKind()) << "_";
|
||||
oss << getValueNumber(binary->getLhs()) << "_" << getValueNumber(binary->getRhs());
|
||||
|
||||
// 对于可交换操作,确保操作数顺序一致
|
||||
if (binary->isCommutative()) {
|
||||
unsigned lhsNum = getValueNumber(binary->getLhs());
|
||||
unsigned rhsNum = getValueNumber(binary->getRhs());
|
||||
if (lhsNum > rhsNum) {
|
||||
oss.str("");
|
||||
oss << "binary_" << static_cast<int>(binary->getKind()) << "_";
|
||||
oss << rhsNum << "_" << lhsNum;
|
||||
}
|
||||
}
|
||||
} else if (auto unary = dynamic_cast<UnaryInst*>(inst)) {
|
||||
oss << "unary_" << static_cast<int>(unary->getKind()) << "_";
|
||||
oss << getValueNumber(unary->getOperand());
|
||||
} else if (auto gep = dynamic_cast<GetElementPtrInst*>(inst)) {
|
||||
oss << "gep_" << getValueNumber(gep->getBasePointer());
|
||||
for (unsigned i = 0; i < gep->getNumIndices(); ++i) {
|
||||
oss << "_" << getValueNumber(gep->getIndex(i));
|
||||
}
|
||||
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
||||
oss << "load_" << getValueNumber(load->getPointer());
|
||||
oss << "_" << reinterpret_cast<uintptr_t>(load->getType()); // 类型区分
|
||||
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||
// 只为无副作用的函数调用建立表达式
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->isPureFunction(call->getCallee())) {
|
||||
oss << "call_" << call->getCallee()->getName();
|
||||
for (size_t i = 1; i < call->getNumOperands(); ++i) { // 跳过函数指针
|
||||
oss << "_" << getValueNumber(call->getOperand(i));
|
||||
}
|
||||
} else {
|
||||
return ""; // 有副作用的函数调用不可优化
|
||||
}
|
||||
} else {
|
||||
return ""; // 不支持的指令类型
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
Value* GVNContext::findExistingValue(const std::string& exprKey, Instruction* inst) {
|
||||
auto it = expressionToNumber.find(exprKey);
|
||||
if (it != expressionToNumber.end()) {
|
||||
unsigned number = it->second;
|
||||
auto valueIt = numberToValue.find(number);
|
||||
if (valueIt != numberToValue.end()) {
|
||||
Value* existing = valueIt->second;
|
||||
|
||||
// 对于load指令,需要额外检查内存安全性
|
||||
if (auto loadInst = dynamic_cast<LoadInst*>(inst)) {
|
||||
if (auto existingLoad = dynamic_cast<LoadInst*>(existing)) {
|
||||
if (!isMemorySafe(existingLoad, loadInst)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GVNContext::dominates(Instruction* a, Instruction* b) {
|
||||
auto aBB = a->getParent();
|
||||
auto bBB = b->getParent();
|
||||
|
||||
// 同一基本块内的情况
|
||||
if (aBB == bBB) {
|
||||
auto &insts = aBB->getInstructions();
|
||||
auto aIt = std::find_if(insts.begin(), insts.end(),
|
||||
[a](const auto &ptr) { return ptr.get() == a; });
|
||||
auto bIt = std::find_if(insts.begin(), insts.end(),
|
||||
[b](const auto &ptr) { return ptr.get() == b; });
|
||||
|
||||
if (aIt == insts.end() || bIt == insts.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::distance(insts.begin(), aIt) < std::distance(insts.begin(), bIt);
|
||||
}
|
||||
|
||||
// 不同基本块的情况,使用支配树
|
||||
if (domTree) {
|
||||
auto dominators = domTree->getDominators(bBB);
|
||||
return dominators && dominators->count(aBB);
|
||||
}
|
||||
|
||||
return false; // 保守做法
|
||||
}
|
||||
|
||||
bool GVNContext::isMemorySafe(LoadInst* earlierLoad, LoadInst* laterLoad) {
|
||||
// 检查两个load是否访问相同的内存位置
|
||||
unsigned earlierPtr = getValueNumber(earlierLoad->getPointer());
|
||||
unsigned laterPtr = getValueNumber(laterLoad->getPointer());
|
||||
|
||||
if (earlierPtr != laterPtr) {
|
||||
return false; // 不同的内存位置
|
||||
}
|
||||
|
||||
// 检查类型是否匹配
|
||||
if (earlierLoad->getType() != laterLoad->getType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 简单情况:如果在同一个基本块且没有中间的store,则安全
|
||||
auto earlierBB = earlierLoad->getParent();
|
||||
auto laterBB = laterLoad->getParent();
|
||||
|
||||
if (earlierBB != laterBB) {
|
||||
// 跨基本块的情况需要更复杂的分析,暂时保守处理
|
||||
return false;
|
||||
}
|
||||
|
||||
// 同一基本块内检查是否有中间的store
|
||||
auto &insts = earlierBB->getInstructions();
|
||||
auto earlierIt = std::find_if(insts.begin(), insts.end(),
|
||||
[earlierLoad](const auto &ptr) { return ptr.get() == earlierLoad; });
|
||||
auto laterIt = std::find_if(insts.begin(), insts.end(),
|
||||
[laterLoad](const auto &ptr) { return ptr.get() == laterLoad; });
|
||||
|
||||
if (earlierIt == insts.end() || laterIt == insts.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确保earlierLoad真的在laterLoad之前
|
||||
if (std::distance(insts.begin(), earlierIt) >= std::distance(insts.begin(), laterIt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查中间是否有store指令修改了相同的内存位置
|
||||
for (auto it = std::next(earlierIt); it != laterIt; ++it) {
|
||||
if (auto store = dynamic_cast<StoreInst*>(it->get())) {
|
||||
unsigned storePtr = getValueNumber(store->getPointer());
|
||||
if (storePtr == earlierPtr) {
|
||||
return false; // 找到中间的store
|
||||
}
|
||||
}
|
||||
|
||||
// 检查函数调用是否可能修改内存
|
||||
if (auto call = dynamic_cast<CallInst*>(it->get())) {
|
||||
if (sideEffectAnalysis && !sideEffectAnalysis->isPureFunction(call->getCallee())) {
|
||||
// 保守处理:有副作用的函数可能修改内存
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 安全
|
||||
}
|
||||
|
||||
void GVNContext::invalidateMemoryValues(StoreInst* store) {
|
||||
unsigned storePtr = getValueNumber(store->getPointer());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Invalidating memory values affected by store" << std::endl;
|
||||
}
|
||||
|
||||
// 找到所有可能被这个store影响的load表达式
|
||||
std::vector<std::string> toRemove;
|
||||
|
||||
for (auto& [exprKey, number] : expressionToNumber) {
|
||||
if (exprKey.find("load_" + std::to_string(storePtr)) == 0) {
|
||||
toRemove.push_back(exprKey);
|
||||
if (DEBUG) {
|
||||
std::cout << " Invalidating expression: " << exprKey << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移除失效的表达式
|
||||
for (const auto& key : toRemove) {
|
||||
expressionToNumber.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void GVNContext::eliminateRedundantInstructions(bool& changed) {
|
||||
int removeCount = 0;
|
||||
for (auto inst : needRemove) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Removing redundant instruction " << ++removeCount
|
||||
<< "/" << needRemove.size() << ": " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 删除指令前先断开所有使用关系
|
||||
// inst->replaceAllUsesWith 已在 processInstruction 中调用
|
||||
SysYIROptUtils::usedelete(inst);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
@@ -43,6 +44,7 @@ void InductionVariableElimination::getAnalysisUsage(std::set<void*>& analysisDep
|
||||
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
|
||||
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
|
||||
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
|
||||
|
||||
// 会使失效的分析(归纳变量消除会修改IR结构)
|
||||
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
|
||||
@@ -93,6 +95,18 @@ bool InductionVariableEliminationContext::run(Function* F, AnalysisManager& AM)
|
||||
}
|
||||
}
|
||||
|
||||
aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
|
||||
if (!aliasAnalysis) {
|
||||
if (DEBUG) {
|
||||
std::cout << " AliasAnalysis not available, using conservative approach" << std::endl;
|
||||
}
|
||||
// 可以继续执行,但会使用更保守的策略
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << " Using AliasAnalysis for memory safety checks" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行三个阶段的优化
|
||||
|
||||
// 阶段1:识别死归纳变量
|
||||
@@ -179,9 +193,9 @@ InductionVariableEliminationContext::isDeadInductionVariable(const InductionVarI
|
||||
return nullptr; // 不是 phi 指令
|
||||
}
|
||||
|
||||
// 检查是否只用于自身更新
|
||||
if (!isUsedOnlyForSelfUpdate(phiInst, loop)) {
|
||||
return nullptr; // 有其他用途
|
||||
// 新的逻辑:递归分析整个use-def链,判断是否有真实的使用
|
||||
if (!isPhiInstructionDeadRecursively(phiInst, loop)) {
|
||||
return nullptr; // 有真实的使用,不能删除
|
||||
}
|
||||
|
||||
// 创建死归纳变量信息
|
||||
@@ -191,9 +205,333 @@ InductionVariableEliminationContext::isDeadInductionVariable(const InductionVarI
|
||||
return deadIV;
|
||||
}
|
||||
|
||||
bool InductionVariableEliminationContext::isUsedOnlyForSelfUpdate(PhiInst* phiInst, Loop* loop) {
|
||||
// 检查 phi 指令的所有使用
|
||||
for (auto use : phiInst->getUses()) {
|
||||
// 递归分析phi指令及其使用链是否都是死代码
|
||||
bool InductionVariableEliminationContext::isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 递归分析归纳变量 " << phiInst->getName() << " 的完整使用链" << std::endl;
|
||||
}
|
||||
|
||||
// 使用访问集合避免无限递归
|
||||
std::set<Instruction*> visitedInstructions;
|
||||
std::set<Instruction*> currentPath; // 用于检测循环依赖
|
||||
|
||||
// 核心逻辑:递归分析使用链,寻找任何"逃逸点"
|
||||
return isInstructionUseChainDeadRecursively(phiInst, loop, visitedInstructions, currentPath);
|
||||
}
|
||||
|
||||
// 递归分析指令的使用链是否都是死代码
|
||||
bool InductionVariableEliminationContext::isInstructionUseChainDeadRecursively(
|
||||
Instruction* inst, Loop* loop,
|
||||
std::set<Instruction*>& visited,
|
||||
std::set<Instruction*>& currentPath) {
|
||||
|
||||
if (DEBUG && visited.size() < 10) { // 限制debug输出
|
||||
std::cout << " 分析指令 " << inst->getName() << " (" << inst->getKindString() << ")" << std::endl;
|
||||
}
|
||||
|
||||
// 避免无限递归
|
||||
if (currentPath.count(inst) > 0) {
|
||||
// 发现循环依赖,这在归纳变量中是正常的,继续分析其他路径
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 发现循环依赖,继续分析其他路径" << std::endl;
|
||||
}
|
||||
return true; // 循环依赖本身不是逃逸点
|
||||
}
|
||||
|
||||
if (visited.count(inst) > 0) {
|
||||
// 已经分析过这个指令
|
||||
return true; // 假设之前的分析是正确的
|
||||
}
|
||||
|
||||
visited.insert(inst);
|
||||
currentPath.insert(inst);
|
||||
|
||||
// 1. 检查是否有副作用(逃逸点)
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 指令有副作用,是逃逸点" << std::endl;
|
||||
}
|
||||
currentPath.erase(inst);
|
||||
return false; // 有副作用的指令是逃逸点
|
||||
}
|
||||
|
||||
// 1.5. 特殊检查:控制流指令永远不是死代码
|
||||
auto instKind = inst->getKind();
|
||||
if (instKind == Instruction::Kind::kCondBr ||
|
||||
instKind == Instruction::Kind::kBr ||
|
||||
instKind == Instruction::Kind::kReturn) {
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 控制流指令,是逃逸点" << std::endl;
|
||||
}
|
||||
currentPath.erase(inst);
|
||||
return false; // 控制流指令是逃逸点
|
||||
}
|
||||
|
||||
// 2. 检查指令的所有使用
|
||||
bool allUsesAreDead = true;
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (!userInst) {
|
||||
// 被非指令使用(如函数返回值),是逃逸点
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 被非指令使用,是逃逸点" << std::endl;
|
||||
}
|
||||
allUsesAreDead = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查使用是否在循环外(逃逸点)
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 在循环外被 " << userInst->getName() << " 使用,是逃逸点" << std::endl;
|
||||
}
|
||||
allUsesAreDead = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 特殊检查:如果使用者是循环的退出条件,需要进一步分析
|
||||
// 对于用于退出条件的归纳变量,需要更谨慎的处理
|
||||
if (isUsedInLoopExitCondition(userInst, loop)) {
|
||||
// 修复逻辑:用于循环退出条件的归纳变量通常不应该被消除
|
||||
// 除非整个循环都可以被证明是完全无用的(这需要更复杂的分析)
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 被用于循环退出条件,是逃逸点(避免破坏循环语义)" << std::endl;
|
||||
}
|
||||
allUsesAreDead = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 递归分析使用者的使用链
|
||||
if (!isInstructionUseChainDeadRecursively(userInst, loop, visited, currentPath)) {
|
||||
allUsesAreDead = false;
|
||||
break; // 找到逃逸点,不需要继续分析
|
||||
}
|
||||
}
|
||||
|
||||
currentPath.erase(inst);
|
||||
|
||||
if (allUsesAreDead && DEBUG && visited.size() < 10) {
|
||||
std::cout << " 指令 " << inst->getName() << " 的所有使用都是死代码" << std::endl;
|
||||
}
|
||||
|
||||
return allUsesAreDead;
|
||||
}
|
||||
|
||||
// 检查循环是否有副作用
|
||||
bool InductionVariableEliminationContext::loopHasSideEffects(Loop* loop) {
|
||||
// 遍历循环中的所有指令,检查是否有副作用
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
Instruction* instPtr = inst.get();
|
||||
|
||||
// 使用副作用分析(如果可用)
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(instPtr)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环中发现有副作用的指令: " << instPtr->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果没有副作用分析,使用保守的判断
|
||||
if (!sideEffectAnalysis) {
|
||||
auto kind = instPtr->getKind();
|
||||
// 这些指令通常有副作用
|
||||
if (kind == Instruction::Kind::kCall ||
|
||||
kind == Instruction::Kind::kStore ||
|
||||
kind == Instruction::Kind::kReturn) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环中发现潜在有副作用的指令: " << instPtr->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重要修复:检查是否为嵌套循环的外层循环
|
||||
// 如果当前循环包含其他循环,那么它有潜在的副作用
|
||||
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
|
||||
Loop* otherLoop = loop_ptr.get();
|
||||
if(loopAnalysis->getLowestCommonAncestor(otherLoop, loop) == loop) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环 " << loop->getName() << " 是其他循环的外层循环,视为有副作用" << std::endl;
|
||||
}
|
||||
return true; // 外层循环被视为有副作用
|
||||
}
|
||||
// if (otherLoop != loop && loop->contains(otherLoop->getHeader())) {
|
||||
// if (DEBUG) {
|
||||
// std::cout << " 循环 " << loop->getName() << " 包含子循环 " << otherLoop->getName() << ",视为有副作用" << std::endl;
|
||||
// }
|
||||
// return true; // 包含子循环的外层循环被视为有副作用
|
||||
// }
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环 " << loop->getName() << " 无副作用" << std::endl;
|
||||
}
|
||||
return false; // 循环无副作用
|
||||
}
|
||||
|
||||
// 检查指令是否被用于循环退出条件
|
||||
bool InductionVariableEliminationContext::isUsedInLoopExitCondition(Instruction* inst, Loop* loop) {
|
||||
// 检查指令是否被循环的退出条件使用
|
||||
for (BasicBlock* exitingBB : loop->getExitingBlocks()) {
|
||||
auto terminatorIt = exitingBB->terminator();
|
||||
if (terminatorIt != exitingBB->end()) {
|
||||
Instruction* terminator = terminatorIt->get();
|
||||
if (terminator) {
|
||||
// 检查终结指令的操作数
|
||||
for (size_t i = 0; i < terminator->getNumOperands(); ++i) {
|
||||
if (terminator->getOperand(i) == inst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 用于循环退出条件" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 对于条件分支,还需要检查条件指令的操作数
|
||||
if (terminator->getKind() == Instruction::Kind::kCondBr) {
|
||||
auto* condBr = dynamic_cast<CondBrInst*>(terminator);
|
||||
if (condBr) {
|
||||
Value* condition = condBr->getCondition();
|
||||
if (condition == inst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 是循环条件" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 递归检查条件指令的操作数(比如比较指令)
|
||||
auto* condInst = dynamic_cast<Instruction*>(condition);
|
||||
if (condInst) {
|
||||
for (size_t i = 0; i < condInst->getNumOperands(); ++i) {
|
||||
if (condInst->getOperand(i) == inst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 用于循环条件的操作数" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 检查指令的结果是否未被有效使用
|
||||
bool InductionVariableEliminationContext::isInstructionResultUnused(Instruction* inst, Loop* loop) {
|
||||
// 检查指令的所有使用
|
||||
if (inst->getUses().empty()) {
|
||||
return true; // 没有使用,肯定是未使用
|
||||
}
|
||||
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (!userInst) {
|
||||
return false; // 被非指令使用,认为是有效使用
|
||||
}
|
||||
|
||||
// 如果在循环外被使用,认为是有效使用
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 递归检查使用这个结果的指令是否也是死代码
|
||||
// 为了避免无限递归,限制递归深度
|
||||
if (!isInstructionEffectivelyDead(userInst, loop, 3)) {
|
||||
return false; // 存在有效使用
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 所有使用都是无效的
|
||||
}
|
||||
|
||||
// 检查store指令是否存储到死地址(利用别名分析)
|
||||
bool InductionVariableEliminationContext::isStoreToDeadLocation(StoreInst* store, Loop* loop) {
|
||||
if (!aliasAnalysis) {
|
||||
return false; // 没有别名分析,保守返回false
|
||||
}
|
||||
|
||||
Value* storePtr = store->getPointer();
|
||||
|
||||
// 检查是否存储到局部临时变量且该变量在循环外不被读取
|
||||
const MemoryLocation* memLoc = aliasAnalysis->getMemoryLocation(storePtr);
|
||||
if (!memLoc) {
|
||||
return false; // 无法确定内存位置
|
||||
}
|
||||
|
||||
// 如果是局部数组且只在循环内被访问
|
||||
if (memLoc->isLocalArray) {
|
||||
// 检查该内存位置是否在循环外被读取
|
||||
for (auto* accessInst : memLoc->accessInsts) {
|
||||
if (accessInst->getKind() == Instruction::Kind::kLoad) {
|
||||
if (!loop->contains(accessInst->getParent())) {
|
||||
return false; // 在循环外被读取,不是死存储
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " 存储到局部数组且仅在循环内访问" << std::endl;
|
||||
}
|
||||
return true; // 存储到仅循环内访问的局部数组
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查指令是否有效死代码(带递归深度限制)
|
||||
bool InductionVariableEliminationContext::isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth) {
|
||||
if (maxDepth <= 0) {
|
||||
return false; // 达到递归深度限制,保守返回false
|
||||
}
|
||||
|
||||
// 利用副作用分析
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
|
||||
return false; // 有副作用的指令不是死代码
|
||||
}
|
||||
|
||||
// 检查特殊指令类型
|
||||
switch (inst->getKind()) {
|
||||
case Instruction::Kind::kStore:
|
||||
// Store指令可能是死存储
|
||||
return isStoreToDeadLocation(dynamic_cast<StoreInst*>(inst), loop);
|
||||
|
||||
case Instruction::Kind::kCall:
|
||||
// 函数调用通常有副作用
|
||||
if (sideEffectAnalysis) {
|
||||
return !sideEffectAnalysis->hasSideEffect(inst);
|
||||
}
|
||||
return false; // 保守地认为函数调用有效果
|
||||
|
||||
case Instruction::Kind::kReturn:
|
||||
case Instruction::Kind::kBr:
|
||||
case Instruction::Kind::kCondBr:
|
||||
// 控制流指令不是死代码
|
||||
return false;
|
||||
|
||||
default:
|
||||
// 其他指令检查其使用是否有效
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查指令的使用
|
||||
if (inst->getUses().empty()) {
|
||||
return true; // 没有使用的纯指令是死代码
|
||||
}
|
||||
|
||||
// 递归检查所有使用
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
@@ -201,35 +539,180 @@ bool InductionVariableEliminationContext::isUsedOnlyForSelfUpdate(PhiInst* phiIn
|
||||
return false; // 被非指令使用
|
||||
}
|
||||
|
||||
// 检查使用是否在循环内
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
return false; // 在循环外被使用
|
||||
}
|
||||
|
||||
// 检查是否为自身的更新指令
|
||||
bool isSelfUpdate = false;
|
||||
|
||||
// 检查是否为加法/减法指令(常见的归纳变量更新模式)
|
||||
if (userInst->getKind() == Instruction::Kind::kAdd ||
|
||||
userInst->getKind() == Instruction::Kind::kSub) {
|
||||
auto* binInst = dynamic_cast<BinaryInst*>(userInst);
|
||||
if (binInst && (binInst->getOperand(0) == phiInst || binInst->getOperand(1) == phiInst)) {
|
||||
// 检查这个指令的结果是否流回到 phi
|
||||
for (auto& [incomingBB, incomingVal] : phiInst->getIncomingValues()) {
|
||||
if (loop->contains(incomingBB) && incomingVal == binInst) {
|
||||
isSelfUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSelfUpdate) {
|
||||
return false; // 有非自更新的使用
|
||||
// 递归检查使用者
|
||||
if (!isInstructionEffectivelyDead(userInst, loop, maxDepth - 1)) {
|
||||
return false; // 存在有效使用
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 只用于自身更新
|
||||
return true; // 所有使用都是死代码
|
||||
}
|
||||
|
||||
// 原有的函数保持兼容,但现在使用增强的死代码分析
|
||||
bool InductionVariableEliminationContext::isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop) {
|
||||
return isInstructionEffectivelyDead(inst, loop, 5);
|
||||
}
|
||||
|
||||
// 检查store指令是否有后续的load操作
|
||||
bool InductionVariableEliminationContext::hasSubsequentLoad(StoreInst* store, Loop* loop) {
|
||||
if (!aliasAnalysis) {
|
||||
// 没有别名分析,保守地假设有后续读取
|
||||
return true;
|
||||
}
|
||||
|
||||
Value* storePtr = store->getPointer();
|
||||
const MemoryLocation* storeLoc = aliasAnalysis->getMemoryLocation(storePtr);
|
||||
|
||||
if (!storeLoc) {
|
||||
// 无法确定内存位置,保守处理
|
||||
return true;
|
||||
}
|
||||
|
||||
// 在循环中和循环后查找对同一位置的load操作
|
||||
std::vector<BasicBlock*> blocksToCheck;
|
||||
|
||||
// 添加循环内的所有基本块
|
||||
for (auto* bb : loop->getBlocks()) {
|
||||
blocksToCheck.push_back(bb);
|
||||
}
|
||||
|
||||
// 添加循环的退出块
|
||||
auto exitBlocks = loop->getExitBlocks();
|
||||
for (auto* exitBB : exitBlocks) {
|
||||
blocksToCheck.push_back(exitBB);
|
||||
}
|
||||
|
||||
// 搜索load操作
|
||||
for (auto* bb : blocksToCheck) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (inst->getKind() == Instruction::Kind::kLoad) {
|
||||
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
|
||||
Value* loadPtr = loadInst->getPointer();
|
||||
const MemoryLocation* loadLoc = aliasAnalysis->getMemoryLocation(loadPtr);
|
||||
|
||||
if (loadLoc && aliasAnalysis->queryAlias(storePtr, loadPtr) != AliasType::NO_ALIAS) {
|
||||
// 找到可能读取同一位置的load操作
|
||||
if (DEBUG) {
|
||||
std::cout << " 找到后续load操作: " << loadInst->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否通过函数调用间接访问
|
||||
for (auto* bb : blocksToCheck) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (inst->getKind() == Instruction::Kind::kCall) {
|
||||
CallInst* callInst = static_cast<CallInst*>(inst.get());
|
||||
if (callInst && sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
|
||||
// 函数调用可能间接读取内存
|
||||
if (DEBUG) {
|
||||
std::cout << " 函数调用可能读取内存: " << callInst->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " 未找到后续load操作" << std::endl;
|
||||
}
|
||||
return false; // 没有找到后续读取
|
||||
}
|
||||
|
||||
// 检查指令是否在循环外有使用
|
||||
bool InductionVariableEliminationContext::hasUsageOutsideLoop(Instruction* inst, Loop* loop) {
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (!userInst) {
|
||||
// 被非指令使用,可能在循环外
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
// 在循环外被使用
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 在循环外被 "
|
||||
<< userInst->getName() << " 使用" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // 没有循环外使用
|
||||
}
|
||||
|
||||
// 检查store指令是否在循环外有后续的load操作
|
||||
bool InductionVariableEliminationContext::hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop) {
|
||||
if (!aliasAnalysis) {
|
||||
// 没有别名分析,保守地假设有后续读取
|
||||
return true;
|
||||
}
|
||||
|
||||
Value* storePtr = store->getPointer();
|
||||
|
||||
// 检查循环的退出块及其后继
|
||||
auto exitBlocks = loop->getExitBlocks();
|
||||
std::set<BasicBlock*> visitedBlocks;
|
||||
|
||||
for (auto* exitBB : exitBlocks) {
|
||||
if (hasLoadInSubtree(exitBB, storePtr, visitedBlocks)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 找到循环外的后续load操作" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // 没有找到循环外的后续读取
|
||||
}
|
||||
|
||||
// 递归检查基本块子树中是否有对指定位置的load操作
|
||||
bool InductionVariableEliminationContext::hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited) {
|
||||
if (visited.count(bb) > 0) {
|
||||
return false; // 已经访问过,避免无限循环
|
||||
}
|
||||
visited.insert(bb);
|
||||
|
||||
// 检查当前基本块中的指令
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (inst->getKind() == Instruction::Kind::kLoad) {
|
||||
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
|
||||
if (aliasAnalysis && aliasAnalysis->queryAlias(ptr, loadInst->getPointer()) != AliasType::NO_ALIAS) {
|
||||
return true; // 找到了对相同或别名位置的load
|
||||
}
|
||||
} else if (inst->getKind() == Instruction::Kind::kCall) {
|
||||
// 函数调用可能间接读取内存
|
||||
CallInst* callInst = static_cast<CallInst*>(inst.get());
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
|
||||
return true; // 保守地认为函数调用可能读取内存
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 递归检查后继基本块(限制深度以避免过度搜索)
|
||||
static int searchDepth = 0;
|
||||
if (searchDepth < 10) { // 限制搜索深度
|
||||
searchDepth++;
|
||||
for (auto* succ : bb->getSuccessors()) {
|
||||
if (hasLoadInSubtree(succ, ptr, visited)) {
|
||||
searchDepth--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
searchDepth--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Instruction*> InductionVariableEliminationContext::collectRelatedInstructions(
|
||||
|
||||
@@ -18,62 +18,214 @@ bool LICMContext::hoistInstructions() {
|
||||
// 1. 先收集所有可外提指令
|
||||
std::unordered_set<Instruction *> workSet(chars->invariantInsts.begin(), chars->invariantInsts.end());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Found " << workSet.size() << " candidate invariant instructions to hoist:" << std::endl;
|
||||
for (auto *inst : workSet) {
|
||||
std::cout << " - " << inst->getName() << " (kind: " << static_cast<int>(inst->getKind())
|
||||
<< ", in BB: " << inst->getParent()->getName() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 计算每个指令被依赖的次数(入度)
|
||||
std::unordered_map<Instruction *, int> indegree;
|
||||
std::unordered_map<Instruction *, std::vector<Instruction *>> dependencies; // 记录依赖关系
|
||||
std::unordered_map<Instruction *, std::vector<Instruction *>> dependents; // 记录被依赖关系
|
||||
|
||||
for (auto *inst : workSet) {
|
||||
indegree[inst] = 0;
|
||||
dependencies[inst] = {};
|
||||
dependents[inst] = {};
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Analyzing dependencies between invariant instructions..." << std::endl;
|
||||
}
|
||||
|
||||
for (auto *inst : workSet) {
|
||||
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
|
||||
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
|
||||
if (workSet.count(dep)) {
|
||||
indegree[inst]++;
|
||||
dependencies[inst].push_back(dep);
|
||||
dependents[dep].push_back(inst);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Dependency: " << inst->getName() << " depends on " << dep->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Initial indegree analysis:" << std::endl;
|
||||
for (auto &[inst, deg] : indegree) {
|
||||
std::cout << " " << inst->getName() << ": indegree=" << deg;
|
||||
if (deg > 0) {
|
||||
std::cout << ", depends on: ";
|
||||
for (auto *dep : dependencies[inst]) {
|
||||
std::cout << dep->getName() << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Kahn拓扑排序
|
||||
std::vector<Instruction *> sorted;
|
||||
std::queue<Instruction *> q;
|
||||
for (auto &[inst, deg] : indegree) {
|
||||
if (deg == 0)
|
||||
q.push(inst);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Starting topological sort..." << std::endl;
|
||||
}
|
||||
|
||||
for (auto &[inst, deg] : indegree) {
|
||||
if (deg == 0) {
|
||||
q.push(inst);
|
||||
if (DEBUG) {
|
||||
std::cout << " Initial zero-indegree instruction: " << inst->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sortStep = 0;
|
||||
while (!q.empty()) {
|
||||
auto *inst = q.front();
|
||||
q.pop();
|
||||
sorted.push_back(inst);
|
||||
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
|
||||
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
|
||||
if (workSet.count(dep)) {
|
||||
indegree[dep]--;
|
||||
if (indegree[dep] == 0)
|
||||
q.push(dep);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Step " << (++sortStep) << ": Processing " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Reducing indegree of dependents of " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 正确的拓扑排序:当处理一个指令时,应该减少其所有使用者(dependents)的入度
|
||||
for (auto *dependent : dependents[inst]) {
|
||||
indegree[dependent]--;
|
||||
if (DEBUG) {
|
||||
std::cout << " Reducing indegree of " << dependent->getName() << " to " << indegree[dependent] << std::endl;
|
||||
}
|
||||
if (indegree[dependent] == 0) {
|
||||
q.push(dependent);
|
||||
if (DEBUG) {
|
||||
std::cout << " Adding " << dependent->getName() << " to queue (indegree=0)" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否全部排序,若未全部排序,说明有环(理论上不会)
|
||||
// 检查是否全部排序,若未全部排序,打印错误信息
|
||||
// 这可能是因为存在循环依赖或其他问题导致无法完成拓扑排序
|
||||
if (sorted.size() != workSet.size()) {
|
||||
if (DEBUG)
|
||||
std::cerr << "LICM: Topological sort failed, possible dependency cycle." << std::endl;
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Topological sort failed! Sorted " << sorted.size()
|
||||
<< " instructions out of " << workSet.size() << " total." << std::endl;
|
||||
|
||||
// 找出未被排序的指令(形成循环依赖的指令)
|
||||
std::unordered_set<Instruction *> remaining;
|
||||
for (auto *inst : workSet) {
|
||||
bool found = false;
|
||||
for (auto *sortedInst : sorted) {
|
||||
if (inst == sortedInst) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
remaining.insert(inst);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "LICM: Instructions involved in dependency cycle:" << std::endl;
|
||||
for (auto *inst : remaining) {
|
||||
std::cout << " - " << inst->getName() << " (indegree=" << indegree[inst] << ")" << std::endl;
|
||||
std::cout << " Dependencies within cycle: ";
|
||||
for (auto *dep : dependencies[inst]) {
|
||||
if (remaining.count(dep)) {
|
||||
std::cout << dep->getName() << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << " Dependents within cycle: ";
|
||||
for (auto *dependent : dependents[inst]) {
|
||||
if (remaining.count(dependent)) {
|
||||
std::cout << dependent->getName() << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// 尝试找出一个具体的循环路径
|
||||
std::cout << "LICM: Attempting to trace a dependency cycle:" << std::endl;
|
||||
if (!remaining.empty()) {
|
||||
auto *start = *remaining.begin();
|
||||
std::unordered_set<Instruction *> visited;
|
||||
std::vector<Instruction *> path;
|
||||
|
||||
std::function<bool(Instruction *)> findCycle = [&](Instruction *current) -> bool {
|
||||
if (visited.count(current)) {
|
||||
// 找到环
|
||||
auto it = std::find(path.begin(), path.end(), current);
|
||||
if (it != path.end()) {
|
||||
std::cout << " Cycle found: ";
|
||||
for (auto cycleIt = it; cycleIt != path.end(); ++cycleIt) {
|
||||
std::cout << (*cycleIt)->getName() << " -> ";
|
||||
}
|
||||
std::cout << current->getName() << std::endl;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
visited.insert(current);
|
||||
path.push_back(current);
|
||||
|
||||
for (auto *dep : dependencies[current]) {
|
||||
if (remaining.count(dep)) {
|
||||
if (findCycle(dep)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path.pop_back();
|
||||
return false;
|
||||
};
|
||||
|
||||
findCycle(start);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 按拓扑序外提
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Successfully completed topological sort. Hoisting instructions in order:" << std::endl;
|
||||
}
|
||||
|
||||
for (auto *inst : sorted) {
|
||||
if (!inst)
|
||||
continue;
|
||||
BasicBlock *parent = inst->getParent();
|
||||
if (parent && loop->contains(parent)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Hoisting " << inst->getName() << " from " << parent->getName()
|
||||
<< " to preheader " << preheader->getName() << std::endl;
|
||||
}
|
||||
auto sourcePos = parent->findInstIterator(inst);
|
||||
auto targetPos = preheader->terminator();
|
||||
parent->moveInst(sourcePos, targetPos, preheader);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG && changed) {
|
||||
std::cout << "LICM: Successfully hoisted " << sorted.size() << " invariant instructions" << std::endl;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
// ---- LICM Pass Implementation ----
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "DCE.h"
|
||||
#include "Mem2Reg.h"
|
||||
#include "Reg2Mem.h"
|
||||
#include "GVN.h"
|
||||
#include "SCCP.h"
|
||||
#include "BuildCFG.h"
|
||||
#include "LargeArrayToGlobal.h"
|
||||
@@ -59,6 +60,8 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
// 注册优化遍
|
||||
registerOptimizationPass<BuildCFG>();
|
||||
registerOptimizationPass<LargeArrayToGlobalPass>();
|
||||
|
||||
registerOptimizationPass<GVN>();
|
||||
|
||||
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
||||
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
||||
@@ -129,6 +132,15 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&GVN::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After GVN Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&SCCP::ID);
|
||||
this->run();
|
||||
@@ -140,13 +152,30 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&LoopNormalizationPass::ID);
|
||||
this->addPass(&LICM::ID);
|
||||
this->addPass(&LoopStrengthReduction::ID);
|
||||
this->addPass(&InductionVariableElimination::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After Loop Normalization, LICM, and Strength Reduction Optimizations ===\n";
|
||||
std::cout << "=== IR After Loop Normalization, Induction Variable Elimination ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&LICM::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After LICM ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&LoopStrengthReduction::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After Loop Normalization, and Strength Reduction Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user