[midend-GVN&SideEffect]修复GVN的部分问题和副作用分析的缺陷
This commit is contained in:
@@ -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