[midend-GVN&SideEffect]修复GVN的部分问题和副作用分析的缺陷

This commit is contained in:
rain2133
2025-08-16 18:52:29 +08:00
parent d038884ffb
commit c4eb1c3980
3 changed files with 83 additions and 6 deletions

View File

@@ -201,7 +201,11 @@ Value *GVNContext::getValueNumber(Instruction *inst) {
} else if (auto load = dynamic_cast<LoadInst *>(inst)) {
return getValueNumber(load);
} else if (auto call = dynamic_cast<CallInst *>(inst)) {
return getValueNumber(call);
// 只为无副作用的函数调用进行GVN
if (sideEffectAnalysis && sideEffectAnalysis->isPureFunction(call->getCallee())) {
return getValueNumber(call);
}
return nullptr;
}
return nullptr;
@@ -295,6 +299,10 @@ Value *GVNContext::getValueNumber(LoadInst *inst) {
auto loadPtr = checkHashtable(load->getPointer());
if (ptr == loadPtr && inst->getType() == load->getType()) {
// 检查两次load之间是否有store指令修改了内存
if (hasInterveningStore(load, inst, ptr)) {
continue; // 如果有store指令不能复用之前的load
}
return value;
}
}
@@ -304,11 +312,7 @@ Value *GVNContext::getValueNumber(LoadInst *inst) {
}
Value *GVNContext::getValueNumber(CallInst *inst) {
// 只为无副作用的函数调用进行GVN
if (sideEffectAnalysis && !sideEffectAnalysis->isPureFunction(inst->getCallee())) {
return nullptr;
}
// 此时已经确认是无副作用的函数调用,可以安全进行GVN
for (auto [key, value] : hashtable) {
if (auto call = dynamic_cast<CallInst *>(key)) {
if (call->getCallee() == inst->getCallee() && call->getNumOperands() == inst->getNumOperands()) {
@@ -427,6 +431,65 @@ bool GVNContext::canReplace(Instruction *original, Value *replacement) {
return false;
}
bool GVNContext::hasInterveningStore(LoadInst* earlierLoad, LoadInst* laterLoad, Value* ptr) {
// 如果两个load在不同的基本块需要更复杂的分析
auto earlierBB = earlierLoad->getParent();
auto laterBB = laterLoad->getParent();
if (earlierBB != laterBB) {
// 跨基本块的情况为了安全起见暂时认为有intervening store
// 这是保守的做法,可能会错过一些优化机会,但确保正确性
return true;
}
// 同一基本块内的情况:检查指令序列
auto &insts = earlierBB->getInstructions();
// 找到两个load指令的位置
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 true; // 找不到指令保守返回true
}
// 检查两个load之间的所有指令
for (auto it = std::next(earlierIt); it != laterIt; ++it) {
auto inst = it->get();
// 检查是否是store指令
if (auto storeInst = dynamic_cast<StoreInst*>(inst)) {
auto storePtr = checkHashtable(storeInst->getPointer());
// 如果store的目标地址与load的地址相同说明内存被修改了
if (storePtr == ptr) {
if (DEBUG) {
std::cout << " Found intervening store to same address, cannot optimize load" << std::endl;
}
return true;
}
}
// TODO: 还需要检查函数调用是否可能修改内存
// 对于全局变量,任何函数调用都可能修改它
if (auto callInst = dynamic_cast<CallInst*>(inst)) {
if (sideEffectAnalysis && !sideEffectAnalysis->isPureFunction(callInst->getCallee())) {
// 如果是有副作用的函数调用且load的是全局变量则可能被修改
if (auto globalPtr = dynamic_cast<GlobalValue*>(ptr)) {
if (DEBUG) {
std::cout << " Found function call that may modify global variable, cannot optimize load" << std::endl;
}
return true;
}
}
}
}
return false; // 没有找到会修改内存的指令
}
std::string GVNContext::getCanonicalExpression(Instruction *inst) {
std::ostringstream oss;