llvm IR中的冗余基本块

时间:2018-11-12 03:55:21

标签: compiler-construction llvm

我只是在玩一个程序,并在llvm中观看它的IR,我注意到某些基本块对我来说没有意义。 我的代码:

self.traces[name] = self.canvas.plot(dataset_x, dataset_y,
    pen=pg.mkPen(sColor, width=3), name='''<font size="15">{}</font>'''.format(name))

相应的IR:

void proc()
{
    int i, j, k, m, n, l;
    k = 119;
    for (i = 20; i < 200; i++)
    {
        for (j = 13; j < 130; j++)
        {
                l = 80;
        }
    }
}

我的问题是标签14和15。标签15似乎只有一个前身14。既然如此,为什么我们不能只将它与标签14合并呢?我假设基本块的构造是由上述here的算法完成的。

1 个答案:

答案 0 :(得分:1)

(此答案主要是我在评论中已经推测的内容的摘要,只是更详细且不再推测,因为我现在已经深入到clang的源代码中以验证正在发生的事情)

LLVM代码始终构成基本块,并且用于表示API中LLVM代码的类型已经形成控制流程图。没有基本块就没有非结构化LLVM的形式,因此就没有将非结构化LLVM转换为CFG的过程。 Clang直接将C AST转换为LLVM。因此,它不会在非结构化的三地址代码中找到基本块,而是在一步之内将C转换为LLVM时就找到了基本块。因此,维基百科的算法不适用。

下面基于CodeGenFunction::EmitForStmt in CodeGen/CGStmt.cpp的松散简化的伪代码总结了正在发生的事情。这是翻译格式为for(init; cond; incr) body的语句的逻辑。为简单起见,我们假设condincr都不为空,并且cond是表达式,而不是声明。

  • 创建新的基本块:conditionBlockbodyBlockincrBlockexitBlock
  • 将初始化代码附加到当前基本块上,然后跳转到conditionBlock
  • cond的代码附加到conditionBlock,后跟br i1 %cond, label %bodyBlock, label %exitBlock
  • {break: exitBlock, continue: incrBlock}推入中断/继续堆栈
  • body的代码附加到bodyBlock,然后跳转到conditionBlock
  • 弹出中断/继续堆栈
  • exitBlock设置为当前基本块

要获得所需的输出,必须将incr的代码发送到bodyBlock中,而不是使用单独的代码块。但是这样就无法将incrBlock推送到中断/继续堆栈中。当然,这对您来说并不重要,因为您的代码不包含任何continue语句,但是在一般情况下,编译器需要break / continue堆栈来知道在{{1}情况下跳转到哪里}或break

因此,编译器仅总是生成这些块,然后在优化阶段将不必要的块合并。