From d465fb02a51291737ed96a234cded7a1b0f5c9a6 Mon Sep 17 00:00:00 2001 From: CGH0S7 <776459475@qq.com> Date: Tue, 19 Aug 2025 17:44:54 +0800 Subject: [PATCH] =?UTF-8?q?[midend-m2r]=E6=81=A2=E5=A4=8D=E5=8E=9F?= =?UTF-8?q?=E6=9C=89mem2reg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/midend/Pass/Optimize/Mem2Reg.cpp | 282 ++++++++++++--------------- src/midend/Pass/Pass.cpp | 6 +- 2 files changed, 126 insertions(+), 162 deletions(-) diff --git a/src/midend/Pass/Optimize/Mem2Reg.cpp b/src/midend/Pass/Optimize/Mem2Reg.cpp index 5573eb7..f1c7d59 100644 --- a/src/midend/Pass/Optimize/Mem2Reg.cpp +++ b/src/midend/Pass/Optimize/Mem2Reg.cpp @@ -7,8 +7,6 @@ #include "SysYIROptUtils.h" #include // 用于断言 #include // 用于调试输出 -#include // 用于工作队列 -#include // 用于已访问集合 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 的操作数通常是:, , , ... + // 对于一个 `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 (auto constInt = dynamic_cast(firstIndexVal)) { - if (constInt->getInt() != 0) { - // 索引不是0,表示访问数组元素 - 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; // 索引不是常量,表示动态数组访问 } - } else { - // 索引不是常量,表示动态数组访问 - return false; } // 此外,GEP 的结果也必须只被 LoadInst 或 StoreInst 使用 @@ -155,35 +151,23 @@ bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) { // 收集所有对给定 AllocaInst 进行存储的 StoreInst void Mem2RegContext::collectStores(AllocaInst *alloca) { - // 使用工作队列处理所有可能的用户,包括嵌套的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); + // 遍历 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()); + } } - // 其他类型的用户不处理 } } } @@ -227,70 +211,56 @@ 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指令,它们已在第一步处理 - if (dynamic_cast(inst)) { - ++instIter; - continue; - } - - // 处理 LoadInst - if (auto loadInst = dynamic_cast(inst)) { + // 处理 Phi 指令 (如果是当前 alloca 的 Phi) + if (auto phiInst = dynamic_cast(inst)) { + // 检查这个 Phi 是否是为某个可提升的 alloca 插入的 for (auto alloca : promotableAllocas) { - Value *ptrOperand = loadInst->getPointer(); - - // 优化:只做一次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); + 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(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; + } + 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(inst)) { for (auto alloca : promotableAllocas) { + // 检查 StoreInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP Value *ptrOperand = storeInst->getPointer(); - - // 优化:只做一次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 (ptrOperand == alloca || (dynamic_cast(ptrOperand) && + dynamic_cast(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); - - 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); + 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; } } } } - // -------------------------------------------------------------------- - // 第四步:递归处理支配树的子节点 + // 递归访问支配树的子节点 // -------------------------------------------------------------------- const std::set *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) { + std::cout << "Mem2Reg: Dominated block: " << (dominatedBB ? dominatedBB->getName() : "null") << std::endl; + } } - for (auto dominatedBB : *dominatedBlocks) { - if (dominatedBB) { + if (dominatedBB) { // 确保子块有效 if (DEBUG) { - std::cout << "Mem2Reg: Recursively processing dominated block: " - << dominatedBB->getName() << std::endl; + std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName() + << std::endl; } - renameVariables(dominatedBB); + 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 diff --git a/src/midend/Pass/Pass.cpp b/src/midend/Pass/Pass.cpp index 93401ee..0678e4e 100644 --- a/src/midend/Pass/Pass.cpp +++ b/src/midend/Pass/Pass.cpp @@ -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";