From 1e3791a80170b51047fcfc033c212fdc0fcd9494 Mon Sep 17 00:00:00 2001 From: rain2133 <1370973498@qq.com> Date: Mon, 11 Aug 2025 20:51:55 +0800 Subject: [PATCH] =?UTF-8?q?[midend-LoopNormalization]=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84=E5=BE=AA=E7=8E=AF=E7=89=B9?= =?UTF-8?q?=E5=BE=81=E5=88=86=E6=9E=90=E7=BB=93=E6=9E=9C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E3=80=82=E4=BC=98=E5=8C=96phi=E6=8C=87=E4=BB=A4=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../midend/Pass/Optimize/LoopNormalization.h | 8 +- .../Pass/Optimize/LoopNormalization.cpp | 164 ++++++++++++++---- 2 files changed, 131 insertions(+), 41 deletions(-) diff --git a/src/include/midend/Pass/Optimize/LoopNormalization.h b/src/include/midend/Pass/Optimize/LoopNormalization.h index c676b97..ef65ae3 100644 --- a/src/include/midend/Pass/Optimize/LoopNormalization.h +++ b/src/include/midend/Pass/Optimize/LoopNormalization.h @@ -1,7 +1,6 @@ #pragma once #include "Loop.h" // 循环分析依赖 -#include "LoopCharacteristics.h" // 循环特征分析依赖 #include "Dom.h" // 支配树分析依赖 #include "IR.h" // IR定义 #include "IRBuilder.h" // IR构建器 @@ -47,7 +46,6 @@ private: // ========== 缓存的分析结果 ========== LoopAnalysisResult* loopAnalysis; // 循环结构分析结果 - LoopCharacteristicsResult* loopCharacteristics; // 循环特征分析结果 DominatorTree* domTree; // 支配树分析结果 // ========== 规范化统计 ========== @@ -56,9 +54,11 @@ private: size_t loopsNeedingPreheader; // 需要前置块的循环数 size_t preheadersCreated; // 创建的前置块数 size_t loopsNormalized; // 规范化的循环数 + size_t redundantPhisRemoved; // 删除的冗余PHI节点数 NormalizationStats() : totalLoops(0), loopsNeedingPreheader(0), - preheadersCreated(0), loopsNormalized(0) {} + preheadersCreated(0), loopsNormalized(0), + redundantPhisRemoved(0) {} } stats; // ========== 核心规范化方法 ========== @@ -78,7 +78,7 @@ private: BasicBlock* createPreheaderForLoop(Loop* loop); /** - * 检查循环是否需要前置块 + * 检查循环是否需要前置块(基于结构性需求) * @param loop 要检查的循环 * @return true如果需要前置块 */ diff --git a/src/midend/Pass/Optimize/LoopNormalization.cpp b/src/midend/Pass/Optimize/LoopNormalization.cpp index f82be5d..d101bf8 100644 --- a/src/midend/Pass/Optimize/LoopNormalization.cpp +++ b/src/midend/Pass/Optimize/LoopNormalization.cpp @@ -1,7 +1,7 @@ #include "LoopNormalization.h" #include "Dom.h" #include "Loop.h" -#include "LoopCharacteristics.h" +#include "SysYIROptUtils.h" #include #include #include @@ -30,7 +30,6 @@ bool LoopNormalizationPass::runOnFunction(Function *F, AnalysisManager &AM) { return false; // 没有循环需要规范化 } - loopCharacteristics = AM.getAnalysisResult(F); domTree = AM.getAnalysisResult(F); if (!domTree) { @@ -156,10 +155,14 @@ BasicBlock* LoopNormalizationPass::createPreheaderForLoop(Loop* loop) { return nullptr; } - // 在前置块中创建一个简单的跳转指令到循环头部 + // 在前置块中创建跳转指令到循环头部 builder->setPosition(preheader, preheader->end()); UncondBrInst* br = builder->createUncondBrInst(header); + // 更新preheader的CFG关系 + preheader->addSuccessor(header); + header->addPredecessor(preheader); + // 重定向外部前驱到新的前置块 redirectExternalPredecessors(loop, preheader, header); @@ -169,6 +172,14 @@ BasicBlock* LoopNormalizationPass::createPreheaderForLoop(Loop* loop) { // 更新支配树关系 updateDominatorRelations(preheader, loop); + // 重要:更新循环对象的前置块信息 + // 这样后续的优化遍可以通过 loop->getPreHeader() 获取到新创建的前置块 + loop->setPreHeader(preheader); + + if (DEBUG) { + std::cout << " Updated loop object: preheader set to " << preheader->getName() << std::endl; + } + return preheader; } @@ -184,13 +195,10 @@ bool LoopNormalizationPass::needsPreheader(Loop* loop) { return false; } - // 如果有多个外部前驱,或者单个外部前驱不适合作为前置块,则需要创建前置块 - if (externalPreds.size() > 1) { - return true; - } - - // 检查唯一的外部前驱是否适合作为前置块 - return !isSuitableAsPreheader(externalPreds[0], loop); + // 基于结构性需求判断: + // 1. 如果有多个外部前驱,必须创建前置块来合并它们 + // 2. 如果单个外部前驱不适合作为前置块,需要创建新的前置块 + return (externalPreds.size() > 1) || !isSuitableAsPreheader(externalPreds[0], loop); } BasicBlock* LoopNormalizationPass::getExistingPreheader(Loop* loop) { @@ -208,13 +216,16 @@ BasicBlock* LoopNormalizationPass::getExistingPreheader(Loop* loop) { } void LoopNormalizationPass::updateDominatorRelations(BasicBlock* newBlock, Loop* loop) { - // 这里需要更新支配树关系 - // 新的前置块应该支配循环头部,并且被循环外的前驱支配 + // 由于在getAnalysisUsage中声明了DominatorTree会失效, + // PassManager会在本遍运行后自动将支配树结果标记为失效, + // 后续需要支配树的Pass会触发重新计算,所以这里无需手动更新 + if (DEBUG) { - std::cout << " Updating dominator relations for new preheader " << newBlock->getName() << std::endl; + BasicBlock* header = loop->getHeader(); + std::cout << " DominatorTree marked for invalidation - new preheader " + << newBlock->getName() << " will dominate " << header->getName() + << " after recomputation by PassManager" << std::endl; } - // 实际的支配树更新逻辑在这里实现 - // 由于支配树分析通常在Pass运行后重新计算,这里主要是标记需要更新 } void LoopNormalizationPass::redirectExternalPredecessors(Loop* loop, BasicBlock* preheader, BasicBlock* header) { @@ -295,16 +306,32 @@ bool LoopNormalizationPass::validateNormalization(Loop* loop) { } // 检查外部前驱是否适合作为前置块 - if (!isSuitableAsPreheader(externalPreds[0], loop)) { + BasicBlock* preheader = externalPreds[0]; + if (!isSuitableAsPreheader(preheader, loop)) { if (DEBUG) - std::cout << " Validation failed: External predecessor " << externalPreds[0]->getName() + std::cout << " Validation failed: External predecessor " << preheader->getName() << " is not suitable as preheader" << std::endl; return false; } + // 额外验证:检查CFG连接性 + if (!preheader->hasSuccessor(header)) { + if (DEBUG) + std::cout << " Validation failed: Preheader " << preheader->getName() + << " is not connected to header " << header->getName() << std::endl; + return false; + } + + if (!header->hasPredecessor(preheader)) { + if (DEBUG) + std::cout << " Validation failed: Header " << header->getName() + << " does not have preheader " << preheader->getName() << " as predecessor" << std::endl; + return false; + } + if (DEBUG) std::cout << " Validation passed for loop " << loop->getName() << std::endl; - + return true; } @@ -356,48 +383,105 @@ void LoopNormalizationPass::updatePhiNodesForPreheader(BasicBlock* header, Basic << " for new preheader " << preheader->getName() << std::endl; } + std::vector phisToRemove; // 需要删除的PHI节点 + for (auto& inst : header->getInstructions()) { if (auto* phi = dynamic_cast(inst.get())) { if (DEBUG) { std::cout << " Processing PHI node: " << phi->getName() << std::endl; } - // 收集来自外部前驱的值 - std::vector> externalValues; + // 收集来自外部前驱的值 - 需要保持原始的映射关系 + std::map externalValues; for (BasicBlock* oldPred : oldPreds) { Value* value = phi->getvalfromBlk(oldPred); if (value) { - externalValues.push_back({value, oldPred}); + externalValues[oldPred] = value; } } - // 从PHI节点中移除旧的外部前驱 - for (BasicBlock* oldPred : oldPreds) { - phi->removeIncoming(oldPred); - } - - // 如果有多个来自外部的值,需要在前置块中创建新的PHI节点 + // 处理PHI节点的更新 if (externalValues.size() > 1) { - // 在前置块中创建新的PHI节点来合并外部值 + // 多个外部前驱:在前置块中创建新的PHI节点 builder->setPosition(preheader, preheader->getInstructions().begin()); std::vector values; std::vector blocks; - for (auto& [value, block] : externalValues) { + for (auto& [block, value] : externalValues) { values.push_back(value); blocks.push_back(block); } - PhiInst* newPhi = builder->createPhiInst(phi->getType(), values, blocks, "preheader.phi"); + PhiInst* newPhi = builder->createPhiInst(phi->getType(), values, blocks); - // 将新PHI的结果作为来自前置块的值添加到原PHI中 + // 移除所有外部前驱的条目 + for (BasicBlock* oldPred : oldPreds) { + phi->removeIncoming(oldPred); + } + + // 添加来自新前置块的条目 phi->addIncoming(newPhi, preheader); + } else if (externalValues.size() == 1) { - // 只有一个外部值,直接添加 - phi->addIncoming(externalValues[0].first, preheader); + // 单个外部前驱:直接重新映射 + Value* value = externalValues.begin()->second; + + // 移除旧的外部前驱条目 + for (BasicBlock* oldPred : oldPreds) { + phi->removeIncoming(oldPred); + } + + // 添加来自新前置块的条目 + phi->addIncoming(value, preheader); + + // 检查PHI节点是否只剩下一个条目(只来自前置块) + if (phi->getNumIncomingValues() == 1) { + if (DEBUG) { + std::cout << " PHI node " << phi->getName() + << " now has only one incoming value, scheduling for removal" << std::endl; + } + // 用单一值替换所有使用 + Value* singleValue = phi->getIncomingValue(0u); + phi->replaceAllUsesWith(singleValue); + phisToRemove.push_back(phi); + } + } else { + // 没有外部值的PHI节点:检查是否需要更新 + // 这种PHI节点只有循环内的边,通常不需要修改 + // 但我们仍然需要检查是否只有一个条目 + if (phi->getNumIncomingValues() == 1) { + if (DEBUG) { + std::cout << " PHI node " << phi->getName() + << " has only one incoming value (no external), scheduling for removal" << std::endl; + } + // 用单一值替换所有使用 + Value* singleValue = phi->getIncomingValue(0u); + phi->replaceAllUsesWith(singleValue); + phisToRemove.push_back(phi); + } + } + + if (DEBUG && std::find(phisToRemove.begin(), phisToRemove.end(), phi) == phisToRemove.end()) { + std::cout << " Updated PHI node with " << externalValues.size() + << " external values, total incoming: " << phi->getNumIncomingValues() << std::endl; } } } + + // 删除标记为移除的PHI节点 + for (PhiInst* phi : phisToRemove) { + if (DEBUG) { + std::cout << " Removing redundant PHI node: " << phi->getName() << std::endl; + } + SysYIROptUtils::usedelete(phi); + } + + // 更新统计信息 + stats.redundantPhisRemoved += phisToRemove.size(); + + if (DEBUG && !phisToRemove.empty()) { + std::cout << " Removed " << phisToRemove.size() << " redundant PHI nodes" << std::endl; + } } void LoopNormalizationPass::printStats(Function* F) { @@ -406,6 +490,7 @@ void LoopNormalizationPass::printStats(Function* F) { std::cout << "Loops needing preheader: " << stats.loopsNeedingPreheader << std::endl; std::cout << "Preheaders created: " << stats.preheadersCreated << std::endl; std::cout << "Loops successfully normalized: " << stats.loopsNormalized << std::endl; + std::cout << "Redundant PHI nodes removed: " << stats.redundantPhisRemoved << std::endl; if (stats.totalLoops > 0) { double normalizationRate = (double)stats.loopsNormalized / stats.totalLoops * 100.0; @@ -419,14 +504,19 @@ void LoopNormalizationPass::getAnalysisUsage(std::set &analysisDependenc std::set &analysisInvalidations) const { // LoopNormalization依赖的分析 analysisDependencies.insert(&LoopAnalysisPass::ID); // 循环结构分析 - analysisDependencies.insert(&LoopCharacteristicsPass::ID); // 循环特征分析 analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 支配树分析 // LoopNormalization会修改CFG结构,因此会使以下分析失效 analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树需要重新计算 - // 注意:循环结构分析可能需要更新,但我们不让它失效,因为我们只是添加前置块 - // analysisInvalidations.insert(&LoopAnalysisPass::ID); // 通常不需要失效 - // analysisInvalidations.insert(&LoopCharacteristicsPass::ID); // 通常不需要失效 + + // 注意:我们不让循环结构分析失效,原因如下: + // 1. 循环规范化只添加前置块,不改变循环的核心结构(头部、体、回边) + // 2. 我们会手动更新Loop对象的前置块信息(通过loop->setPreHeader()) + // 3. 让循环分析失效并重新计算的成本较高且不必要 + // 4. 后续优化遍可以正确获取到更新后的前置块信息 + // + // 如果未来有更复杂的循环结构修改,可能需要考虑让循环分析失效: + // analysisInvalidations.insert(&LoopAnalysisPass::ID); } } // namespace sysy