[midend-m2r]恢复原有mem2reg

This commit is contained in:
2025-08-19 17:44:54 +08:00
parent 3c49183280
commit d465fb02a5
2 changed files with 126 additions and 162 deletions

View File

@@ -7,8 +7,6 @@
#include "SysYIROptUtils.h"
#include <cassert> // 用于断言
#include <iostream> // 用于调试输出
#include <queue> // 用于工作队列
#include <unordered_set> // 用于已访问集合
namespace sysy {
@@ -102,31 +100,29 @@ bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) {
// 这种 GEP 有两个操作数:基指针和索引。
// 检查 GEP 的操作数数量和索引值
// GEP 的操作数包括:基指针 + 索引列表
// getNumOperands() == 1 表示只有基指针,没有索引(不应该出现)
// getNumOperands() == 2 表示基指针 + 1个索引
// getNumOperands() > 2 表示基指针 + 多个索引(复杂访问)
if (gep->getNumOperands() < 2) {
// 没有索引的GEP是无效的
return false;
// GEP 的操作数通常是:<base_pointer>, <index_1>, <index_2>, ...
// 对于一个 `i32*` 类型的 `alloca`,如果它被 GEP 使用,那么 GEP 的第一个索引通常是 `0`
// (表示解引用指针本身),后续索引才是数组元素的索引。
// 如果 GEP 的操作数数量大于 2 (即 `base_ptr` 和 `index_0` 之外还有其他索引)
// 或者 `index_0` 不是常量 0则它可能是一个复杂的数组访问。
// 假设 `gep->getNumOperands()` 和 `gep->getOperand(idx)->getValue()`
// 假设 `ConstantInt` 类用于表示常量整数值
if (gep->getNumOperands() > 2) { // 如果有超过一个索引(除了基指针的第一个隐式索引)
// std::cerr << "Mem2Reg: Not promotable (GEP with multiple indices): " << alloca->name() << std::endl;
return false; // 复杂 GEP通常表示数组或结构体字段访问
}
if (gep->getNumOperands() > 2) {
// 多个索引,表示复杂的数组或结构体访问
return false;
}
// 只有一个索引的情况检查索引是否为常量0
Value *firstIndexVal = gep->getOperand(1);
if (gep->getNumOperands() == 2) { // 只有基指针和一个索引
Value *firstIndexVal = gep->getOperand(1); // 获取第一个索引值
if (auto constInt = dynamic_cast<ConstantInteger *>(firstIndexVal)) {
if (constInt->getInt() != 0) {
// 索引不是0表示访问数组元素
return false;
// std::cerr << "Mem2Reg: Not promotable (GEP with non-zero first index): " << alloca->name() << std::endl;
return false; // 索引不是0表示访问数组的非第一个元素
}
} else {
// 索引不是常量,表示动态数组访问
return false;
// std::cerr << "Mem2Reg: Not promotable (GEP with non-constant first index): " << alloca->name() <<
// std::endl;
return false; // 索引不是常量,表示动态数组访问
}
}
// 此外GEP 的结果也必须只被 LoadInst 或 StoreInst 使用
@@ -155,35 +151,23 @@ bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) {
// 收集所有对给定 AllocaInst 进行存储的 StoreInst
void Mem2RegContext::collectStores(AllocaInst *alloca) {
// 使用工作队列处理所有可能的用户包括嵌套的GEP
std::queue<Value*> workQueue;
std::unordered_set<Value*> visited;
// 初始化工作队列
workQueue.push(alloca);
visited.insert(alloca);
while (!workQueue.empty()) {
Value* current = workQueue.front();
workQueue.pop();
// 遍历当前值的所有用户
for (auto use : current->getUses()) {
// 遍历 alloca 的所有用途
for (auto use : alloca->getUses()) {
auto user = use->getUser();
if (!user || visited.count(user))
if (!user)
continue;
visited.insert(user);
if (auto storeInst = dynamic_cast<StoreInst *>(user)) {
// 找到一个store指令
allocaToStoresMap[alloca].insert(storeInst);
allocaToDefBlocksMap[alloca].insert(storeInst->getParent());
} else if (auto gep = dynamic_cast<GetElementPtrInst *>(user)) {
// 找到一个GEP指令将其加入工作队列继续处理
workQueue.push(gep);
// 如果是 GEP递归收集其下游的 store
for (auto gep_use : gep->getUses()) {
if (auto gep_store = dynamic_cast<StoreInst *>(gep_use->getUser())) {
allocaToStoresMap[alloca].insert(gep_store);
allocaToDefBlocksMap[alloca].insert(gep_store->getParent());
}
}
// 其他类型的用户不处理
}
}
}
@@ -227,70 +211,56 @@ void Mem2RegContext::insertPhis(AllocaInst *alloca, const std::unordered_set<Bas
}
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
// 移除了 AllocaInst *currentAlloca 参数,因为这个函数是为整个基本块处理所有可提升的 Alloca
void Mem2RegContext::renameVariables(BasicBlock *currentBB) {
// 记录每个 alloca 在此基本块开始时的栈深度,用于退出时精确回溯
// 1. 在函数开始时,记录每个 promotableAlloca 的当前栈深度。
// 这将用于在函数返回时精确地回溯栈状态。
std::map<AllocaInst *, size_t> originalStackSizes;
for (auto alloca : promotableAllocas) {
originalStackSizes[alloca] = allocaToValueStackMap[alloca].size();
}
// --------------------------------------------------------------------
// 第一步:处理当前基本块开头的 PHI 指令,为它们分配新的 SSA 值
// --------------------------------------------------------------------
for (auto alloca : promotableAllocas) {
if (allocaToPhiMap[alloca].count(currentBB)) {
PhiInst *phiInst = allocaToPhiMap[alloca][currentBB];
// 将 PHI 指令本身作为新的 SSA 值压入栈顶
allocaToValueStackMap[alloca].push(phiInst);
if (DEBUG) {
std::cout << "Mem2Reg: Pushed PHI " << (phiInst->getName().empty() ? "anonymous" : phiInst->getName())
<< " for alloca " << alloca->getName() << ". Stack size: " << allocaToValueStackMap[alloca].size() << std::endl;
}
}
}
// --------------------------------------------------------------------
// 第二步处理当前基本块中的非PHI指令替换 load/store 指令
// 处理当前基本块的指令
// --------------------------------------------------------------------
for (auto instIter = currentBB->getInstructions().begin(); instIter != currentBB->getInstructions().end();) {
Instruction *inst = instIter->get();
bool instDeleted = false;
// 跳过PHI指令它们已在第一步处理
if (dynamic_cast<PhiInst *>(inst)) {
++instIter;
continue;
}
// 处理 LoadInst
if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
// 处理 Phi 指令 (如果是当前 alloca 的 Phi)
if (auto phiInst = dynamic_cast<PhiInst *>(inst)) {
// 检查这个 Phi 是否是为某个可提升的 alloca 插入的
for (auto alloca : promotableAllocas) {
if (allocaToPhiMap[alloca].count(currentBB) && allocaToPhiMap[alloca][currentBB] == phiInst) {
// 为 Phi 指令的输出创建一个新的 SSA 值,并压入值栈
allocaToValueStackMap[alloca].push(phiInst);
if (DEBUG) {
std::cout << "Mem2Reg: Pushed Phi " << (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " for alloca " << alloca->getName()
<< ". Stack size: " << allocaToValueStackMap[alloca].size() << std::endl;
}
break; // 找到对应的 alloca处理下一个指令
}
}
}
// 处理 LoadInst
else if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
for (auto alloca : promotableAllocas) {
// 检查 LoadInst 的指针是否直接是 alloca或者是指向 alloca 的 GEP
Value *ptrOperand = loadInst->getPointer();
// 优化只做一次dynamic_cast
auto gepPtr = dynamic_cast<GetElementPtrInst *>(ptrOperand);
if (ptrOperand == alloca ||
(gepPtr && gepPtr->getOperand(0) == alloca)) { // GEP的第一个操作数是基指针
if (allocaToValueStackMap[alloca].empty()) {
// 栈为空时使用未定义值而非崩溃
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca during load replacement!");
if (DEBUG) {
std::cerr << "Warning: Value stack empty for alloca " << alloca->getName()
<< " during load replacement. Using undefined value." << std::endl;
}
Value *undefValue = UndefinedValue::get(alloca->getType()->as<PointerType>()->getBaseType());
loadInst->replaceAllUsesWith(undefValue);
} else {
Value *currentValue = allocaToValueStackMap[alloca].top();
if (DEBUG) {
std::cout << "Mem2Reg: Replacing load with SSA value "
<< (currentValue->getName().empty() ? "anonymous" : currentValue->getName())
std::cout << "Mem2Reg: Replacing load "
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
<< (allocaToValueStackMap[alloca].top()->getName().empty()
? "anonymous"
: allocaToValueStackMap[alloca].top()->getName())
<< " for alloca " << alloca->getName() << std::endl;
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
<< "] size: " << allocaToValueStackMap[alloca].size() << std::endl;
}
loadInst->replaceAllUsesWith(currentValue);
}
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
instIter = SysYIROptUtils::usedelete(instIter);
instDeleted = true;
break;
@@ -300,104 +270,98 @@ void Mem2RegContext::renameVariables(BasicBlock *currentBB) {
// 处理 StoreInst
else if (auto storeInst = dynamic_cast<StoreInst *>(inst)) {
for (auto alloca : promotableAllocas) {
// 检查 StoreInst 的指针是否直接是 alloca或者是指向 alloca 的 GEP
Value *ptrOperand = storeInst->getPointer();
// 优化只做一次dynamic_cast
auto gepPtr = dynamic_cast<GetElementPtrInst *>(ptrOperand);
if (ptrOperand == alloca ||
(gepPtr && gepPtr->getOperand(0) == alloca)) { // GEP的第一个操作数是基指针
Value *storedValue = storeInst->getValue();
allocaToValueStackMap[alloca].push(storedValue);
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
if (DEBUG) {
std::cout << "Mem2Reg: Replacing store with SSA value "
<< (storedValue->getName().empty() ? "anonymous" : storedValue->getName())
<< " for alloca " << alloca->getName()
<< ". Stack size: " << allocaToValueStackMap[alloca].size() << std::endl;
std::cout << "Mem2Reg: Replacing store to "
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
<< (storeInst->getValue()->getName().empty() ? "anonymous" : storeInst->getValue()->getName())
<< " for alloca " << alloca->getName() << std::endl;
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
<< "] size before push: " << allocaToValueStackMap[alloca].size() << std::endl;
}
allocaToValueStackMap[alloca].push(storeInst->getValue());
instIter = SysYIROptUtils::usedelete(instIter);
instDeleted = true;
if (DEBUG) {
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
<< "] size after push: " << allocaToValueStackMap[alloca].size() << std::endl;
}
break;
}
}
}
if (!instDeleted) {
++instIter;
++instIter; // 如果指令没有被删除,移动到下一个
}
}
// --------------------------------------------------------------------
// 第三步:为后继基本块的 PHI 指令填充参数
// 处理后继基本块的 Phi 指令参数
// --------------------------------------------------------------------
for (auto successorBB : currentBB->getSuccessors()) {
if (!successorBB) continue;
if (!successorBB)
continue;
for (auto alloca : promotableAllocas) {
// 如果后继基本块包含为当前 alloca 插入的 Phi 指令
if (allocaToPhiMap[alloca].count(successorBB)) {
PhiInst *phiInst = allocaToPhiMap[alloca][successorBB];
if (!allocaToValueStackMap[alloca].empty()) {
Value *currentValue = allocaToValueStackMap[alloca].top();
phiInst->addIncoming(currentValue, currentBB);
auto phiInst = allocaToPhiMap[alloca][successorBB];
// 为 Phi 指令添加来自当前基本块的参数
// 参数值是当前 alloca 值栈顶部的 SSA 值
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca when setting phi operand!");
phiInst->addIncoming(allocaToValueStackMap[alloca].top(), currentBB);
if (DEBUG) {
std::cout << "Mem2Reg: Added incoming arg to PHI "
<< (phiInst->getName().empty() ? "anonymous" : phiInst->getName())
<< " from " << currentBB->getName()
<< " with value " << (currentValue->getName().empty() ? "anonymous" : currentValue->getName())
std::cout << "Mem2Reg: Added incoming arg to Phi "
<< (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " from "
<< currentBB->getName() << " with value "
<< (allocaToValueStackMap[alloca].top()->getName().empty()
? "anonymous"
: allocaToValueStackMap[alloca].top()->getName())
<< std::endl;
}
} else {
// 栈为空时使用未定义值
if (DEBUG) {
std::cerr << "Warning: Value stack empty for alloca " << alloca->getName()
<< " when setting phi operand. Using undefined value." << std::endl;
}
Value *undefValue = UndefinedValue::get(alloca->getType()->as<PointerType>()->getBaseType());
phiInst->addIncoming(undefValue, currentBB);
}
}
}
}
// --------------------------------------------------------------------
// 第四步:递归处理支配树的子节点
// 递归访问支配树的子节点
// --------------------------------------------------------------------
const std::set<BasicBlock *> *dominatedBlocks = dt->getDominatorTreeChildren(currentBB);
if (dominatedBlocks) {
if (DEBUG) {
std::cout << "Mem2Reg: Processing " << dominatedBlocks->size()
<< " dominated blocks for " << currentBB->getName() << std::endl;
}
if (dominatedBlocks) { // 检查是否存在子节点
if(DEBUG){
std::cout << "Mem2Reg: Processing dominated blocks for " << currentBB->getName() << std::endl;
for (auto dominatedBB : *dominatedBlocks) {
if (dominatedBB) {
if (DEBUG) {
std::cout << "Mem2Reg: Recursively processing dominated block: "
<< dominatedBB->getName() << std::endl;
std::cout << "Mem2Reg: Dominated block: " << (dominatedBB ? dominatedBB->getName() : "null") << std::endl;
}
renameVariables(dominatedBB);
}
for (auto dominatedBB : *dominatedBlocks) {
if (dominatedBB) { // 确保子块有效
if (DEBUG) {
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName()
<< std::endl;
}
renameVariables(dominatedBB); // 递归调用,不再传递 currentAlloca
}
}
}
// --------------------------------------------------------------------
// 第五步:退出时恢复值栈状态
// 退出基本块时,弹出在此块中压入值栈的 SSA 值,恢复栈到进入该块时的状态
// --------------------------------------------------------------------
for (auto alloca : promotableAllocas) {
while (allocaToValueStackMap[alloca].size() > originalStackSizes[alloca]) {
if (DEBUG) {
std::cout << "Mem2Reg: Popping value "
<< (allocaToValueStackMap[alloca].top()->getName().empty() ? "anonymous" : allocaToValueStackMap[alloca].top()->getName())
<< " for alloca " << alloca->getName()
<< ". Stack size: " << allocaToValueStackMap[alloca].size()
<< (allocaToValueStackMap[alloca].top()->getName().empty()
? "anonymous"
: allocaToValueStackMap[alloca].top()->getName())
<< " for alloca " << alloca->getName() << ". Stack size: " << allocaToValueStackMap[alloca].size()
<< " -> " << (allocaToValueStackMap[alloca].size() - 1) << std::endl;
}
allocaToValueStackMap[alloca].pop();
}
}
}
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst

View File

@@ -124,9 +124,9 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
printPasses();
}
// this->clearPasses();
// this->addPass(&Mem2Reg::ID);
// this->run();
this->clearPasses();
this->addPass(&Mem2Reg::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Mem2Reg Optimizations ===\n";