我只是在玩一个程序,并在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的算法完成的。
答案 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
的语句的逻辑。为简单起见,我们假设cond
和incr
都不为空,并且cond
是表达式,而不是声明。
conditionBlock
,bodyBlock
,incrBlock
和exitBlock
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
。
因此,编译器仅总是生成这些块,然后在优化阶段将不必要的块合并。