Algorithm 如何构建具有无止境循环的函数的后支配树?

Algorithm 如何构建具有无止境循环的函数的后支配树?,algorithm,graph,compiler-construction,llvm,decompiler,Algorithm,Graph,Compiler Construction,Llvm,Decompiler,我身边的一个项目是a,它将本机代码转换为LLVM IR,对其进行简化并输出伪C。程序过程的一个基本阶段是,在程序中查找区域并将其转换为结构化控制流语句(即非GOTO) 我必须推出自己的代码来查找区域,因为LLVM的区域看起来与论文期望的不完全一样。然而,查找区域需要有一个后支配树,结果是LLVM的后支配树构建算法无法为没有结束块的函数生成一个后支配树,就像以无限循环“结束”的函数一样 这似乎是因为树构建算法需要一个起点。通常情况下,起始点是函数的返回块,因为它会在其他块中占主导地位;但是没有任何

我身边的一个项目是a,它将本机代码转换为LLVM IR,对其进行简化并输出伪C。程序过程的一个基本阶段是,在程序中查找区域并将其转换为结构化控制流语句(即非GOTO)

我必须推出自己的代码来查找区域,因为LLVM的区域看起来与论文期望的不完全一样。然而,查找区域需要有一个后支配树,结果是LLVM的后支配树构建算法无法为没有结束块的函数生成一个后支配树,就像以无限循环“结束”的函数一样

这似乎是因为树构建算法需要一个起点。通常情况下,起始点是函数的返回块,因为它会在其他块中占主导地位;但是没有任何in函数旋转成一个无止境的循环,因为它们没有任何
返回
不可到达
终止符。(在这一点上,可能值得注意的是,LLVM的区域代码也依赖于后支配树,对于无法构建它的函数也没有用处。)

在我看来,即使这个算法失败了,函数不返回的事实并不意味着你不能为它创建一个post-dominator树。1事实上,如果这个无休止的循环只有一个back-edge(这是我可以保证的),那么具有该back-edge的节点必然会post-dominator树控制图中的所有其他节点,因此,应该可以创建一个后支配树

如果我能找到那个节点,我可能会将它提供给LLVM的后dom基础设施,并从中得到一个合理的后支配者树。不幸的是,我不是很有想象力,我能想到的识别关键节点的唯一直接方法是“它是一个post主宰一切的节点”,这当然不会帮助我引导post主宰者树

找到后边缘并不特别困难。正如Doug Currie所说,您可以通过一个简单的DFS来实现,事实上,这是我项目的另一部分。然而,对于一个具有无止境循环和嵌套终止循环的函数,我不知道在没有控制信息的情况下,如何区分内部后缘和外部后缘。(如果有帮助,在流程的这个阶段,每个循环都保证有一个入口节点,最多一个出口节点。)

那么,如何构建一个没有任何返回基本块的函数的后支配树呢


一,。我的编译器和图论背景完全是自学的。这可能不准确。

严格地说,当存在无限循环(不仅仅是无界循环——一个没有出口的严格无限循环)时,不存在后支配器,因为对于循环中的每个节点,循环中的下一个节点将在它之后执行,因此循环中没有“最后”节点


处理它的一种方法是执行正常的post-dominator查找,除了从出口执行初始深度优先遍历之后,检查未访问的节点。如果存在,则无法从它们访问出口(没有从节点到出口的路径),因此可以随机选择一个并将其添加为psuedo出口(就好像节点包含到出口的条件分支,只是条件始终为false),然后重新启动。这会给你一个后支配者树,但不一定是唯一的(因为你可能会随机选择不同的节点来添加退出分支),但通常这并不重要。

作为一个黑客,为了让你的分析成功,你能不能在循环中插入一个假结束条件,这个条件永远不会变成真的,例如,在伪代码中:
如果(5==7)中断?@500 InternalServerError,我仍然需要找到确切的位置,那将是在有后缘的节点上,我不知道如何找到。你可以用DFS找到后缘;例如,@DougCurrie,不能保证一个循环无限的函数只有一个循环。如果无限循环有一个内部(终止)循环,我不知道如何确定哪个后缘属于无限循环。我应该在问题中包括这一点。@zneak,请参阅G RAMALINGAM的“在几乎线性时间内识别循环”,其中描述了用于查找循环和循环嵌套的近似线性时间算法。这实际上是我在评论中试图达到的目的,虽然我不能像你一样理解word。即使不是每个不可到达的节点都是一个无止境循环的一部分,这也行得通吗?根据定义,所有不可到达的节点都必须是一个无止境循环的一部分,因为每个节点都必须至少有一个后续节点(如果只有自身的话)在我看来,一个未访问的节点可以无条件地导致一个无止境的循环,而不是它的一部分,不是吗?@zneak:是的,但这样的节点必须无条件地导致一个无止境的循环——你不能有没有无止境循环的未访问节点。因此,一旦您添加了导致所有节点都可以通过出口的反向边遍历访问的never-Take分支,您就已经处理了所有无休止的循环。只是有多种方法可以做到这一点(这可能导致代码效率的提高或降低),但所有这些方法都是“正确的”,因为它们保留了原始程序的语义。