From 7af38270982418c4ebd10c79b6d6787c8b855f6d Mon Sep 17 00:00:00 2001 From: CGH0S7 <776459475@qq.com> Date: Tue, 19 Aug 2025 16:37:52 +0800 Subject: [PATCH] =?UTF-8?q?[midend-m2r]=E4=BF=AE=E6=94=B9Mem2Reg.cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/midend/Pass/Optimize/Mem2Reg.cpp | 296 +++++++++++++++------------ 1 file changed, 166 insertions(+), 130 deletions(-) diff --git a/src/midend/Pass/Optimize/Mem2Reg.cpp b/src/midend/Pass/Optimize/Mem2Reg.cpp index f1c7d59..5573eb7 100644 --- a/src/midend/Pass/Optimize/Mem2Reg.cpp +++ b/src/midend/Pass/Optimize/Mem2Reg.cpp @@ -7,6 +7,8 @@ #include "SysYIROptUtils.h" #include // 用于断言 #include // 用于调试输出 +#include // 用于工作队列 +#include // 用于已访问集合 namespace sysy { @@ -100,29 +102,31 @@ bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) { // 这种 GEP 有两个操作数:基指针和索引。 // 检查 GEP 的操作数数量和索引值 - // GEP 的操作数通常是:, , , ... - // 对于一个 `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(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(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(user)) { - allocaToStoresMap[alloca].insert(storeInst); - allocaToDefBlocksMap[alloca].insert(storeInst->getParent()); - } else if (auto gep = dynamic_cast(user)) { - // 如果是 GEP,递归收集其下游的 store - for (auto gep_use : gep->getUses()) { - if (auto gep_store = dynamic_cast(gep_use->getUser())) { - allocaToStoresMap[alloca].insert(gep_store); - allocaToDefBlocksMap[alloca].insert(gep_store->getParent()); - } + // 使用工作队列处理所有可能的用户,包括嵌套的GEP + std::queue workQueue; + std::unordered_set 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(user)) { + // 找到一个store指令 + allocaToStoresMap[alloca].insert(storeInst); + allocaToDefBlocksMap[alloca].insert(storeInst->getParent()); + } else if (auto gep = dynamic_cast(user)) { + // 找到一个GEP指令,将其加入工作队列继续处理 + workQueue.push(gep); } + // 其他类型的用户不处理 } } } @@ -211,56 +227,70 @@ void Mem2RegContext::insertPhis(AllocaInst *alloca, const std::unordered_set 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(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(inst)) { + ++instIter; + continue; } + // 处理 LoadInst - else if (auto loadInst = dynamic_cast(inst)) { + if (auto loadInst = dynamic_cast(inst)) { for (auto alloca : promotableAllocas) { - // 检查 LoadInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP Value *ptrOperand = loadInst->getPointer(); - if (ptrOperand == alloca || (dynamic_cast(ptrOperand) && - dynamic_cast(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(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()->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(inst)) { for (auto alloca : promotableAllocas) { - // 检查 StoreInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP Value *ptrOperand = storeInst->getPointer(); - if (ptrOperand == alloca || (dynamic_cast(ptrOperand) && - dynamic_cast(ptrOperand)->getBasePointer() == alloca)) { + + // 优化:只做一次dynamic_cast + auto gepPtr = dynamic_cast(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()->getBaseType()); + phiInst->addIncoming(undefValue, currentBB); } } } } - // -------------------------------------------------------------------- - // 递归访问支配树的子节点 - // -------------------------------------------------------------------- - const std::set *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 *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