[midend-GVN&SideEffect]修复GVN的部分问题和副作用分析的缺陷
This commit is contained in:
@ -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);
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user