[midend-LoopNormalization]消除不必要的循环特征分析结果使用。优化phi指令处理逻辑

This commit is contained in:
rain2133
2025-08-11 20:51:55 +08:00
parent 6a7355ed28
commit 1e3791a801
2 changed files with 131 additions and 41 deletions

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "Loop.h" // 循环分析依赖 #include "Loop.h" // 循环分析依赖
#include "LoopCharacteristics.h" // 循环特征分析依赖
#include "Dom.h" // 支配树分析依赖 #include "Dom.h" // 支配树分析依赖
#include "IR.h" // IR定义 #include "IR.h" // IR定义
#include "IRBuilder.h" // IR构建器 #include "IRBuilder.h" // IR构建器
@@ -47,7 +46,6 @@ private:
// ========== 缓存的分析结果 ========== // ========== 缓存的分析结果 ==========
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果 LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
LoopCharacteristicsResult* loopCharacteristics; // 循环特征分析结果
DominatorTree* domTree; // 支配树分析结果 DominatorTree* domTree; // 支配树分析结果
// ========== 规范化统计 ========== // ========== 规范化统计 ==========
@@ -56,9 +54,11 @@ private:
size_t loopsNeedingPreheader; // 需要前置块的循环数 size_t loopsNeedingPreheader; // 需要前置块的循环数
size_t preheadersCreated; // 创建的前置块数 size_t preheadersCreated; // 创建的前置块数
size_t loopsNormalized; // 规范化的循环数 size_t loopsNormalized; // 规范化的循环数
size_t redundantPhisRemoved; // 删除的冗余PHI节点数
NormalizationStats() : totalLoops(0), loopsNeedingPreheader(0), NormalizationStats() : totalLoops(0), loopsNeedingPreheader(0),
preheadersCreated(0), loopsNormalized(0) {} preheadersCreated(0), loopsNormalized(0),
redundantPhisRemoved(0) {}
} stats; } stats;
// ========== 核心规范化方法 ========== // ========== 核心规范化方法 ==========
@@ -78,7 +78,7 @@ private:
BasicBlock* createPreheaderForLoop(Loop* loop); BasicBlock* createPreheaderForLoop(Loop* loop);
/** /**
* 检查循环是否需要前置块 * 检查循环是否需要前置块(基于结构性需求)
* @param loop 要检查的循环 * @param loop 要检查的循环
* @return true如果需要前置块 * @return true如果需要前置块
*/ */

View File

@@ -1,7 +1,7 @@
#include "LoopNormalization.h" #include "LoopNormalization.h"
#include "Dom.h" #include "Dom.h"
#include "Loop.h" #include "Loop.h"
#include "LoopCharacteristics.h" #include "SysYIROptUtils.h"
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
@@ -30,7 +30,6 @@ bool LoopNormalizationPass::runOnFunction(Function *F, AnalysisManager &AM) {
return false; // 没有循环需要规范化 return false; // 没有循环需要规范化
} }
loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
domTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F); domTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
if (!domTree) { if (!domTree) {
@@ -156,10 +155,14 @@ BasicBlock* LoopNormalizationPass::createPreheaderForLoop(Loop* loop) {
return nullptr; return nullptr;
} }
// 在前置块中创建一个简单的跳转指令到循环头部 // 在前置块中创建跳转指令到循环头部
builder->setPosition(preheader, preheader->end()); builder->setPosition(preheader, preheader->end());
UncondBrInst* br = builder->createUncondBrInst(header); UncondBrInst* br = builder->createUncondBrInst(header);
// 更新preheader的CFG关系
preheader->addSuccessor(header);
header->addPredecessor(preheader);
// 重定向外部前驱到新的前置块 // 重定向外部前驱到新的前置块
redirectExternalPredecessors(loop, preheader, header); redirectExternalPredecessors(loop, preheader, header);
@@ -169,6 +172,14 @@ BasicBlock* LoopNormalizationPass::createPreheaderForLoop(Loop* loop) {
// 更新支配树关系 // 更新支配树关系
updateDominatorRelations(preheader, 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; return preheader;
} }
@@ -184,13 +195,10 @@ bool LoopNormalizationPass::needsPreheader(Loop* loop) {
return false; return false;
} }
// 如果有多个外部前驱,或者单个外部前驱不适合作为前置块,则需要创建前置块 // 基于结构性需求判断:
if (externalPreds.size() > 1) { // 1. 如果有多个外部前驱,必须创建前置块来合并它们
return true; // 2. 如果单个外部前驱不适合作为前置块,需要创建新的前置块
} return (externalPreds.size() > 1) || !isSuitableAsPreheader(externalPreds[0], loop);
// 检查唯一的外部前驱是否适合作为前置块
return !isSuitableAsPreheader(externalPreds[0], loop);
} }
BasicBlock* LoopNormalizationPass::getExistingPreheader(Loop* loop) { BasicBlock* LoopNormalizationPass::getExistingPreheader(Loop* loop) {
@@ -208,13 +216,16 @@ BasicBlock* LoopNormalizationPass::getExistingPreheader(Loop* loop) {
} }
void LoopNormalizationPass::updateDominatorRelations(BasicBlock* newBlock, Loop* loop) { void LoopNormalizationPass::updateDominatorRelations(BasicBlock* newBlock, Loop* loop) {
// 这里需要更新支配树关系 // 由于在getAnalysisUsage中声明了DominatorTree会失效
// 新的前置块应该支配循环头部,并且被循环外的前驱支配 // PassManager会在本遍运行后自动将支配树结果标记为失效
// 后续需要支配树的Pass会触发重新计算所以这里无需手动更新
if (DEBUG) { 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) { void LoopNormalizationPass::redirectExternalPredecessors(Loop* loop, BasicBlock* preheader, BasicBlock* header) {
@@ -295,13 +306,29 @@ bool LoopNormalizationPass::validateNormalization(Loop* loop) {
} }
// 检查外部前驱是否适合作为前置块 // 检查外部前驱是否适合作为前置块
if (!isSuitableAsPreheader(externalPreds[0], loop)) { BasicBlock* preheader = externalPreds[0];
if (!isSuitableAsPreheader(preheader, loop)) {
if (DEBUG) 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; << " is not suitable as preheader" << std::endl;
return false; 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) if (DEBUG)
std::cout << " Validation passed for loop " << loop->getName() << std::endl; std::cout << " Validation passed for loop " << loop->getName() << std::endl;
@@ -356,47 +383,104 @@ void LoopNormalizationPass::updatePhiNodesForPreheader(BasicBlock* header, Basic
<< " for new preheader " << preheader->getName() << std::endl; << " for new preheader " << preheader->getName() << std::endl;
} }
std::vector<PhiInst*> phisToRemove; // 需要删除的PHI节点
for (auto& inst : header->getInstructions()) { for (auto& inst : header->getInstructions()) {
if (auto* phi = dynamic_cast<PhiInst*>(inst.get())) { if (auto* phi = dynamic_cast<PhiInst*>(inst.get())) {
if (DEBUG) { if (DEBUG) {
std::cout << " Processing PHI node: " << phi->getName() << std::endl; std::cout << " Processing PHI node: " << phi->getName() << std::endl;
} }
// 收集来自外部前驱的值 // 收集来自外部前驱的值 - 需要保持原始的映射关系
std::vector<std::pair<Value*, BasicBlock*>> externalValues; std::map<BasicBlock*, Value*> externalValues;
for (BasicBlock* oldPred : oldPreds) { for (BasicBlock* oldPred : oldPreds) {
Value* value = phi->getvalfromBlk(oldPred); Value* value = phi->getvalfromBlk(oldPred);
if (value) { if (value) {
externalValues.push_back({value, oldPred}); externalValues[oldPred] = value;
} }
} }
// PHI节点中移除旧的外部前驱 // 处理PHI节点的更新
for (BasicBlock* oldPred : oldPreds) {
phi->removeIncoming(oldPred);
}
// 如果有多个来自外部的值需要在前置块中创建新的PHI节点
if (externalValues.size() > 1) { if (externalValues.size() > 1) {
// 在前置块中创建新的PHI节点来合并外部值 // 多个外部前驱:在前置块中创建新的PHI节点
builder->setPosition(preheader, preheader->getInstructions().begin()); builder->setPosition(preheader, preheader->getInstructions().begin());
std::vector<Value*> values; std::vector<Value*> values;
std::vector<BasicBlock*> blocks; std::vector<BasicBlock*> blocks;
for (auto& [value, block] : externalValues) { for (auto& [block, value] : externalValues) {
values.push_back(value); values.push_back(value);
blocks.push_back(block); 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); phi->addIncoming(newPhi, preheader);
} else if (externalValues.size() == 1) { } 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;
} }
} }
@@ -406,6 +490,7 @@ void LoopNormalizationPass::printStats(Function* F) {
std::cout << "Loops needing preheader: " << stats.loopsNeedingPreheader << std::endl; std::cout << "Loops needing preheader: " << stats.loopsNeedingPreheader << std::endl;
std::cout << "Preheaders created: " << stats.preheadersCreated << std::endl; std::cout << "Preheaders created: " << stats.preheadersCreated << std::endl;
std::cout << "Loops successfully normalized: " << stats.loopsNormalized << 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) { if (stats.totalLoops > 0) {
double normalizationRate = (double)stats.loopsNormalized / stats.totalLoops * 100.0; double normalizationRate = (double)stats.loopsNormalized / stats.totalLoops * 100.0;
@@ -419,14 +504,19 @@ void LoopNormalizationPass::getAnalysisUsage(std::set<void *> &analysisDependenc
std::set<void *> &analysisInvalidations) const { std::set<void *> &analysisInvalidations) const {
// LoopNormalization依赖的分析 // LoopNormalization依赖的分析
analysisDependencies.insert(&LoopAnalysisPass::ID); // 循环结构分析 analysisDependencies.insert(&LoopAnalysisPass::ID); // 循环结构分析
analysisDependencies.insert(&LoopCharacteristicsPass::ID); // 循环特征分析
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 支配树分析 analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 支配树分析
// LoopNormalization会修改CFG结构因此会使以下分析失效 // LoopNormalization会修改CFG结构因此会使以下分析失效
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树需要重新计算 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 } // namespace sysy