[midend-m2r]修改Mem2Reg.cpp
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert> // 用于断言
|
||||
#include <iostream> // 用于调试输出
|
||||
#include <queue> // 用于工作队列
|
||||
#include <unordered_set> // 用于已访问集合
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -100,29 +102,31 @@ bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) {
|
||||
// 这种 GEP 有两个操作数:基指针和索引。
|
||||
|
||||
// 检查 GEP 的操作数数量和索引值
|
||||
// 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,通常表示数组或结构体字段访问
|
||||
// GEP 的操作数包括:基指针 + 索引列表
|
||||
// getNumOperands() == 1 表示只有基指针,没有索引(不应该出现)
|
||||
// getNumOperands() == 2 表示基指针 + 1个索引
|
||||
// getNumOperands() > 2 表示基指针 + 多个索引(复杂访问)
|
||||
|
||||
if (gep->getNumOperands() < 2) {
|
||||
// 没有索引的GEP是无效的
|
||||
return false;
|
||||
}
|
||||
if (gep->getNumOperands() == 2) { // 只有基指针和一个索引
|
||||
Value *firstIndexVal = gep->getOperand(1); // 获取第一个索引值
|
||||
if (auto constInt = dynamic_cast<ConstantInteger *>(firstIndexVal)) {
|
||||
if (constInt->getInt() != 0) {
|
||||
// std::cerr << "Mem2Reg: Not promotable (GEP with non-zero first index): " << alloca->name() << std::endl;
|
||||
return false; // 索引不是0,表示访问数组的非第一个元素
|
||||
}
|
||||
} else {
|
||||
// std::cerr << "Mem2Reg: Not promotable (GEP with non-constant first index): " << alloca->name() <<
|
||||
// std::endl;
|
||||
return false; // 索引不是常量,表示动态数组访问
|
||||
|
||||
if (gep->getNumOperands() > 2) {
|
||||
// 多个索引,表示复杂的数组或结构体访问
|
||||
return false;
|
||||
}
|
||||
|
||||
// 只有一个索引的情况,检查索引是否为常量0
|
||||
Value *firstIndexVal = gep->getOperand(1);
|
||||
if (auto constInt = dynamic_cast<ConstantInteger *>(firstIndexVal)) {
|
||||
if (constInt->getInt() != 0) {
|
||||
// 索引不是0,表示访问数组元素
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// 索引不是常量,表示动态数组访问
|
||||
return false;
|
||||
}
|
||||
|
||||
// 此外,GEP 的结果也必须只被 LoadInst 或 StoreInst 使用
|
||||
@@ -151,23 +155,35 @@ bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) {
|
||||
|
||||
// 收集所有对给定 AllocaInst 进行存储的 StoreInst
|
||||
void Mem2RegContext::collectStores(AllocaInst *alloca) {
|
||||
// 遍历 alloca 的所有用途
|
||||
for (auto use : alloca->getUses()) {
|
||||
auto user = use->getUser();
|
||||
if (!user)
|
||||
continue;
|
||||
|
||||
if (auto storeInst = dynamic_cast<StoreInst *>(user)) {
|
||||
allocaToStoresMap[alloca].insert(storeInst);
|
||||
allocaToDefBlocksMap[alloca].insert(storeInst->getParent());
|
||||
} else if (auto gep = dynamic_cast<GetElementPtrInst *>(user)) {
|
||||
// 如果是 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());
|
||||
}
|
||||
// 使用工作队列处理所有可能的用户,包括嵌套的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()) {
|
||||
auto user = use->getUser();
|
||||
if (!user || visited.count(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);
|
||||
}
|
||||
// 其他类型的用户不处理
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,56 +227,70 @@ void Mem2RegContext::insertPhis(AllocaInst *alloca, const std::unordered_set<Bas
|
||||
}
|
||||
|
||||
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
|
||||
// 移除了 AllocaInst *currentAlloca 参数,因为这个函数是为整个基本块处理所有可提升的 Alloca
|
||||
void Mem2RegContext::renameVariables(BasicBlock *currentBB) {
|
||||
// 1. 在函数开始时,记录每个 promotableAlloca 的当前栈深度。
|
||||
// 这将用于在函数返回时精确地回溯栈状态。
|
||||
// 记录每个 alloca 在此基本块开始时的栈深度,用于退出时精确回溯
|
||||
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;
|
||||
bool instDeleted = false;
|
||||
|
||||
// 处理 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,处理下一个指令
|
||||
}
|
||||
}
|
||||
// 跳过PHI指令,它们已在第一步处理
|
||||
if (dynamic_cast<PhiInst *>(inst)) {
|
||||
++instIter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理 LoadInst
|
||||
else if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
|
||||
if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
|
||||
for (auto alloca : promotableAllocas) {
|
||||
// 检查 LoadInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP
|
||||
Value *ptrOperand = loadInst->getPointer();
|
||||
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::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;
|
||||
|
||||
// 优化:只做一次dynamic_cast
|
||||
auto gepPtr = dynamic_cast<GetElementPtrInst *>(ptrOperand);
|
||||
if (ptrOperand == alloca ||
|
||||
(gepPtr && gepPtr->getOperand(0) == alloca)) { // GEP的第一个操作数是基指针
|
||||
|
||||
if (allocaToValueStackMap[alloca].empty()) {
|
||||
// 栈为空时使用未定义值而非崩溃
|
||||
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())
|
||||
<< " for alloca " << alloca->getName() << std::endl;
|
||||
}
|
||||
|
||||
loadInst->replaceAllUsesWith(currentValue);
|
||||
}
|
||||
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
instDeleted = true;
|
||||
break;
|
||||
@@ -270,98 +300,104 @@ 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();
|
||||
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
|
||||
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
|
||||
|
||||
// 优化:只做一次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 (DEBUG) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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)) {
|
||||
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 "
|
||||
<< (allocaToValueStackMap[alloca].top()->getName().empty()
|
||||
? "anonymous"
|
||||
: allocaToValueStackMap[alloca].top()->getName())
|
||||
<< std::endl;
|
||||
PhiInst *phiInst = allocaToPhiMap[alloca][successorBB];
|
||||
if (!allocaToValueStackMap[alloca].empty()) {
|
||||
Value *currentValue = allocaToValueStackMap[alloca].top();
|
||||
phiInst->addIncoming(currentValue, 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::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 dominated blocks for " << currentBB->getName() << std::endl;
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
std::cout << "Mem2Reg: Dominated block: " << (dominatedBB ? dominatedBB->getName() : "null") << std::endl;
|
||||
}
|
||||
}
|
||||
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 值,恢复栈到进入该块时的状态
|
||||
// 第四步:递归处理支配树的子节点
|
||||
// --------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
if (dominatedBB) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Recursively processing dominated block: "
|
||||
<< dominatedBB->getName() << std::endl;
|
||||
}
|
||||
renameVariables(dominatedBB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 第五步:退出时恢复值栈状态
|
||||
// --------------------------------------------------------------------
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user