[midend]loop分析构建
This commit is contained in:
179
src/midend/Pass/Analysis/Loop.cpp
Normal file
179
src/midend/Pass/Analysis/Loop.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
#include "Dom.h" // 确保包含 DominatorTreeAnalysisPass 的定义
|
||||
#include "Loop.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义 Pass 的唯一 ID
|
||||
void *LoopAnalysisPass::ID = (void *)&LoopAnalysisPass::ID;
|
||||
|
||||
bool LoopAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
|
||||
return false; // 空函数,没有循环
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
std::cout << "Running LoopAnalysisPass on function: " << F->getName() << std::endl;
|
||||
|
||||
// 获取支配树分析结果
|
||||
// 这是循环分析的关键依赖
|
||||
DominatorTree *DT = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
|
||||
if (!DT) {
|
||||
// 无法获取支配树,无法进行循环分析
|
||||
std::cerr << "Error: DominatorTreeAnalysisResult not available for function " << F->getName() << std::endl;
|
||||
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
|
||||
bool changed = false; // 循环分析本身不修改IR,所以通常返回false
|
||||
|
||||
// 步骤 1: 识别回边和对应的自然循环
|
||||
// 回边 (N -> D) 定义:D 支配 N
|
||||
std::vector<std::pair<BasicBlock *, BasicBlock *>> backEdges;
|
||||
for (auto &BB : F->getBasicBlocks()) {
|
||||
for (BasicBlock *Succ : BB->getSuccessors()) {
|
||||
if (DT->getDominators(BB.get()) && DT->getDominators(BB.get())->count(Succ)) {
|
||||
// Succ 支配 BB,所以 (BB -> Succ) 是一条回边
|
||||
backEdges.push_back({BB.get(), Succ});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤 2: 为每条回边构建自然循环
|
||||
for (auto &edge : backEdges) {
|
||||
BasicBlock *N = edge.first; // 回边的尾部
|
||||
BasicBlock *D = edge.second; // 回边的头部 (循环头)
|
||||
|
||||
// 创建新的 Loop 对象
|
||||
std::unique_ptr<Loop> currentLoop = std::make_unique<Loop>(D);
|
||||
|
||||
// 收集循环体块:从 N 逆向遍历到 D (不包括中间的 D)
|
||||
std::set<BasicBlock *> loopBlocks; // 临时存储循环块
|
||||
std::queue<BasicBlock *> q;
|
||||
|
||||
q.push(N);
|
||||
loopBlocks.insert(N); // 回边的尾部首先是循环块
|
||||
|
||||
while (!q.empty()) {
|
||||
BasicBlock *current = q.front();
|
||||
q.pop();
|
||||
|
||||
for (BasicBlock *pred : current->getPredecessors()) {
|
||||
if (pred == D) {
|
||||
// 找到循环头,将其加入循环块集合,但不继续逆向遍历它的前驱,
|
||||
// 因为我们是从 N 到 D 的路径,D 已经是终点。
|
||||
loopBlocks.insert(D);
|
||||
continue;
|
||||
}
|
||||
// 如果是 D 自身,并且它已经在循环块集合中,也不再处理
|
||||
if (loopBlocks.find(pred) == loopBlocks.end()) {
|
||||
loopBlocks.insert(pred);
|
||||
q.push(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将收集到的块添加到 Loop 对象中
|
||||
for (BasicBlock *loopBB : loopBlocks) {
|
||||
currentLoop->addBlock(loopBB);
|
||||
}
|
||||
|
||||
// 步骤 3: 识别循环出口块 (Exit Blocks)
|
||||
for (BasicBlock *loopBB : loopBlocks) {
|
||||
for (BasicBlock *succ : loopBB->getSuccessors()) {
|
||||
if (loopBlocks.find(succ) == loopBlocks.end()) {
|
||||
// 如果后继不在循环体内,则 loopBB 是一个出口块
|
||||
currentLoop->addExitBlock(loopBB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤 4: 识别循环前置块 (Pre-Header) - 您的前端已做很多工作,这里是确认和规范化
|
||||
BasicBlock *candidatePreHeader = nullptr;
|
||||
int externalPredecessorCount = 0;
|
||||
for (BasicBlock *predOfHeader : D->getPredecessors()) {
|
||||
if (loopBlocks.find(predOfHeader) == loopBlocks.end()) {
|
||||
// 如果前驱不在循环体内,则是一个外部前驱
|
||||
externalPredecessorCount++;
|
||||
candidatePreHeader = predOfHeader;
|
||||
}
|
||||
}
|
||||
|
||||
if (externalPredecessorCount == 1) {
|
||||
currentLoop->setPreHeader(candidatePreHeader);
|
||||
} else {
|
||||
// TODO: 如果有多个外部前驱或没有,这里应该插入新的基本块作为前置块,
|
||||
// 并调整控制流。这会修改 IR,需要返回 true。
|
||||
// 目前,我们只是简单地不设置 preHeader。
|
||||
}
|
||||
|
||||
CurrentResult->addLoop(std::move(currentLoop));
|
||||
}
|
||||
|
||||
// 步骤 5: 处理嵌套循环 (确定父子关系)
|
||||
// 遍历所有已识别的循环,确定它们的嵌套关系
|
||||
const auto &allLoops = CurrentResult->getAllLoops();
|
||||
for (const auto &outerLoop_ptr : allLoops) {
|
||||
Loop *outerLoop = outerLoop_ptr.get();
|
||||
for (const auto &innerLoop_ptr : allLoops) {
|
||||
Loop *innerLoop = innerLoop_ptr.get();
|
||||
|
||||
// 一个循环不能是它自己的父循环
|
||||
if (outerLoop == innerLoop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断 innerLoop 是否嵌套在 outerLoop 内
|
||||
// 条件:innerLoop 的头被 outerLoop 的头支配,且 innerLoop 的所有块都在 outerLoop 内
|
||||
if (DT->getDominators(innerLoop->getHeader()) &&
|
||||
DT->getDominators(innerLoop->getHeader())->count(outerLoop->getHeader())) {
|
||||
bool allInnerBlocksInOuter = true;
|
||||
for (BasicBlock *innerBB : innerLoop->getBlocks()) {
|
||||
if (!outerLoop->contains(innerBB)) {
|
||||
allInnerBlocksInOuter = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allInnerBlocksInOuter) {
|
||||
// 找到了一个嵌套关系,但还需要确定是直接嵌套还是多层嵌套
|
||||
// 简单方法:如果 innerLoop 没有其他父循环,或者这个 outerLoop 是其最近的父循环
|
||||
// 更精确的做法是找支配 innerLoop 头的,且被 innerLoop 头支配的最近的循环头
|
||||
|
||||
// 简单的直接嵌套判断:如果 innerLoop 还没有父循环,或者当前 outerLoop 比现有父循环更“紧密”
|
||||
if (!innerLoop->getParentLoop()) { // 还没设置父循环
|
||||
innerLoop->setParentLoop(outerLoop);
|
||||
outerLoop->addNestedLoop(innerLoop);
|
||||
} else {
|
||||
// 如果 innerLoop 已经有父循环,判断 outerLoop 是否是更直接的父循环
|
||||
// (outerLoop 的头是否支配 innerLoop->getParentLoop() 的头)
|
||||
if (DT->getDominators(innerLoop->getParentLoop()->getHeader()) &&
|
||||
DT->getDominators(innerLoop->getParentLoop()->getHeader())->count(outerLoop->getHeader())) {
|
||||
// outerLoop 支配 innerLoop 现有父循环的头,说明 outerLoop 更外层
|
||||
// 保持现有父循环不变
|
||||
} else if (DT->getDominators(outerLoop->getHeader()) &&
|
||||
DT->getDominators(outerLoop->getHeader())->count(innerLoop->getParentLoop()->getHeader())) {
|
||||
// outerLoop 被 innerLoop 现有父循环的头支配,说明 outerLoop 更内层
|
||||
// 这种情况不应该发生,因为我们已经判断 outerLoop 支配 innerLoop 的头
|
||||
// 可能是 bug 或复杂情况,需要进一步分析
|
||||
} else {
|
||||
// 否则,outerLoop 可能是更直接的父循环,需要更新
|
||||
// TODO 用更复杂的算法来构建循环树
|
||||
// innerLoop->getParentLoop()->NestedLoops.erase(
|
||||
// std::remove(innerLoop->getParentLoop()->NestedLoops.begin(),
|
||||
// innerLoop->getParentLoop()->NestedLoops.Loops.end(), innerLoop),
|
||||
// innerLoop->getParentLoop()->NestedLoops.end());
|
||||
// innerLoop->setParentLoop(outerLoop);
|
||||
outerLoop->addNestedLoop(innerLoop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
Reference in New Issue
Block a user