From c4eb1c39808730d2fd5034e0540a37bef0712de0 Mon Sep 17 00:00:00 2001 From: rain2133 <1370973498@qq.com> Date: Sat, 16 Aug 2025 18:52:29 +0800 Subject: [PATCH] =?UTF-8?q?[midend-GVN&SideEffect]=E4=BF=AE=E5=A4=8DGVN?= =?UTF-8?q?=E7=9A=84=E9=83=A8=E5=88=86=E9=97=AE=E9=A2=98=E5=92=8C=E5=89=AF?= =?UTF-8?q?=E4=BD=9C=E7=94=A8=E5=88=86=E6=9E=90=E7=9A=84=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/include/midend/Pass/Optimize/GVN.h | 3 + .../Pass/Analysis/SideEffectAnalysis.cpp | 11 +++ src/midend/Pass/Optimize/GVN.cpp | 75 +++++++++++++++++-- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/include/midend/Pass/Optimize/GVN.h b/src/include/midend/Pass/Optimize/GVN.h index 3358e48..ce11769 100644 --- a/src/include/midend/Pass/Optimize/GVN.h +++ b/src/include/midend/Pass/Optimize/GVN.h @@ -56,6 +56,9 @@ private: // 检查是否可以安全地用一个值替换另一个值 bool canReplace(Instruction* original, Value* replacement); + // 检查两个load指令之间是否有store指令修改了相同的内存位置 + bool hasInterveningStore(LoadInst* earlierLoad, LoadInst* laterLoad, Value* ptr); + // 生成表达式的标准化字符串 std::string getCanonicalExpression(Instruction* inst); }; diff --git a/src/midend/Pass/Analysis/SideEffectAnalysis.cpp b/src/midend/Pass/Analysis/SideEffectAnalysis.cpp index 805f98b..3887add 100644 --- a/src/midend/Pass/Analysis/SideEffectAnalysis.cpp +++ b/src/midend/Pass/Analysis/SideEffectAnalysis.cpp @@ -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; diff --git a/src/midend/Pass/Optimize/GVN.cpp b/src/midend/Pass/Optimize/GVN.cpp index a06ec5f..76b0ffb 100644 --- a/src/midend/Pass/Optimize/GVN.cpp +++ b/src/midend/Pass/Optimize/GVN.cpp @@ -201,7 +201,11 @@ Value *GVNContext::getValueNumber(Instruction *inst) { } else if (auto load = dynamic_cast(inst)) { return getValueNumber(load); } else if (auto call = dynamic_cast(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(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(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(inst)) { + if (sideEffectAnalysis && !sideEffectAnalysis->isPureFunction(callInst->getCallee())) { + // 如果是有副作用的函数调用,且load的是全局变量,则可能被修改 + if (auto globalPtr = dynamic_cast(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;