[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
#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如果需要前置块
*/

View File

@ -1,7 +1,7 @@
#include "LoopNormalization.h"
#include "Dom.h"
#include "Loop.h"
#include "LoopCharacteristics.h"
#include "SysYIROptUtils.h"
#include <iostream>
#include <algorithm>
#include <sstream>
@ -30,7 +30,6 @@ bool LoopNormalizationPass::runOnFunction(Function *F, AnalysisManager &AM) {
return false; // 没有循环需要规范化
}
loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
domTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(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<PhiInst*> phisToRemove; // 需要删除的PHI节点
for (auto& inst : header->getInstructions()) {
if (auto* phi = dynamic_cast<PhiInst*>(inst.get())) {
if (DEBUG) {
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) {
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<Value*> values;
std::vector<BasicBlock*> 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<void *> &analysisDependenc
std::set<void *> &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