如何找到出现在 LLVM IR 级别的两个特定基本块之间的所有基本块?

Posted

技术标签:

【中文标题】如何找到出现在 LLVM IR 级别的两个特定基本块之间的所有基本块?【英文标题】:How to find all basic blocks appearing between two specific basic blocks in LLVM IR level? 【发布时间】:2019-06-04 07:30:52 【问题描述】:

我正在LLVM 做一些分析,出于某些原因,我想找到可以在两个特定基本块之间执行的所有基本块。

例如,假设我们有两个名为AB 的基本块。现在我想知道在执行基本块A之后和基本块B之前会出现哪些基本块。

一种可能的解决方案是使用控制辉光图的可达性分析。例如,如果基本块C 可以从A 访问,并且基本块B 也可以从C 访问,那么我们可以说C 可以在A 之后和B 之前执行。

我在 LLVM 中唯一能找到的就是 llvm/analysis/CFG.h 中的这个函数:

/// Determine whether instruction 'To' is reachable from 'From', without passing
/// through any blocks in ExclusionSet, returning true if uncertain.
///
/// Determine whether there is a path from From to To within a single function.
/// Returns false only if we can prove that once 'From' has been executed then
/// 'To' can not be executed. Conservatively returns true.
///
/// This function is linear with respect to the number of blocks in the CFG,
/// walking down successors from From to reach To, with a fixed threshold.
/// Using DT or LI allows us to answer more quickly. LI reduces the cost of
/// an entire loop of any number of blocks to be the same as the cost of a
/// single block. DT reduces the cost by allowing the search to terminate when
/// we find a block that dominates the block containing 'To'. DT is most useful
/// on branchy code but not loops, and LI is most useful on code with loops but
/// does not help on branchy code outside loops.
bool isPotentiallyReachable(
     const Instruction *From, const Instruction *To,
     const SmallPtrSetImpl<BasicBlock *> *ExclusionSet = nullptr,
     const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);

但问题是这个函数太保守了,答案也不确定。我想知道某些答案。

【问题讨论】:

【参考方案1】:

您正在寻找的概念称为统治。您想要由 A 支配和由 B 后支配的块。为此,您制作或获得 DominatorTree 和 PostDominatorTree,并查看 A 和 B 下面的树部分。您可以获得一个来自通行证管理人员,如果您正在编写通行证。

但是,请注意 LLVM 的代码是保守的,因为这类事情往往会很快变得复杂。那些在 A 之后执行(即由 A 控制)但返回或抛出异常而不是分支到 B 的块呢?你想要那些吗?如果有无限循环怎么办?这些可能是故意的。如果可能抛出异常并且处理程序不是由 B 后支配怎么办?这种事情充满了你必须考虑的情况。

【讨论】:

我想我还不是很清楚。如果块A 支配像C 这样的块,则意味着从入口块到C 的每条路径都应该经过块A。但就我而言,从AC 只有一条路径就足够了。统治比我所寻找的要强大。 另一种解决方案是查找从AB 的所有路径,并查看这些路径中出现了哪些块。但我试过了,它是如此复杂和耗时。 使用 llvm::successors() 迭代器可以很容易地构建可以从 A 到达的块集,以及使用 llvm::predecessors() 迭代器可以到达 B 的块集。然后你只需选择一个交叉路口。 你是对的!现在我正在迭代块A 的所有继任者并重复此操作,直到我到达块B。在我的具体问题中,我确信我会到达B,并且我不会陷入无限循环。感谢您提醒我这个简单的解决方案:)。

以上是关于如何找到出现在 LLVM IR 级别的两个特定基本块之间的所有基本块?的主要内容,如果未能解决你的问题,请参考以下文章

解析和修改 LLVM IR 代码

LLVM 之 IR 篇:如何编写消除死代码 Pass

如何从给定 LLVM IR 的源代码中获取变量的所有行号?

如何在 LLVM IR 的 switch 指令中使用 char*?

LLVM 之 IR 篇:如何基于传统 Pass 框架扩展 LLVM IR 优化器

LLVM 之 IR 篇:零基础快速入门 LLVM IR