Compiler construction llvm IR中的冗余基本块

Compiler construction llvm IR中的冗余基本块,compiler-construction,llvm,Compiler Construction,Llvm,我只是在玩一个程序,在llvm中观看它的IR,我注意到某些基本块对我来说没有意义。 我的代码: void proc() { int i,j,k,m,n,l; k=119; 对于(i=20;i

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

void proc()
{
int i,j,k,m,n,l;
k=119;
对于(i=20;i<200;i++)
{
对于(j=13;j<130;j++)
{
l=80;
}
}
}
相应的IR:

 store i32 119, i32* %3, align 4
  store i32 20, i32* %1, align 4
  br label %7

; <label>:7:                                      ; preds = %19, %0
  %8 = load i32, i32* %1, align 4
  %9 = icmp slt i32 %8, 200
  br i1 %9, label %10, label %22

; <label>:10:                                     ; preds = %7
  store i32 13, i32* %2, align 4
  br label %11

; <label>:11:                                     ; preds = %15, %10
  %12 = load i32, i32* %2, align 4
  %13 = icmp slt i32 %12, 130
  br i1 %13, label %14, label %18

; <label>:14:                                     ; preds = %11
  store i32 80, i32* %6, align 4
  br label %15

; <label>:15:                                     ; preds = %14
  %16 = load i32, i32* %2, align 4
  %17 = add nsw i32 %16, 1
  store i32 %17, i32* %2, align 4
  br label %11

; <label>:18:                                     ; preds = %11
  br label %19

; <label>:19:                                     ; preds = %18
  %20 = load i32, i32* %1, align 4
  %21 = add nsw i32 %20, 1
  store i32 %21, i32* %1, align 4
  br label %7

; <label>:22:                                     ; preds = %7
  ret void
存储i32 119,i32*%3,对齐4
存储i32 20,i32*%1,对齐4
br标签%7
; :7:                                      ; preds=%19,%0
%8=加载i32,i32*%1,对齐4
%9=icmp slt i32%8200
br i1%9,标签%10,标签%22
; :10:                                     ; preds=%7
存储i32 13,i32*%2,对齐4
br标签%11
; :11:                                     ; preds=%15,%10
%12=加载i32,i32*%2,对齐4
%13=icmp slt i32%12130
br i1%13,标签%14,标签%18
; :14:                                     ; preds=%11
存储i32 80,i32*%6,对齐4
br标签%15
; :15:                                     ; preds=%14
%16=加载i32,i32*%2,对齐4
%17=添加新南威尔士州i32%16,1
存储i32%17,i32*%2,对齐4
br标签%11
; :18:                                     ; preds=%11
br标签%19
; :19:                                     ; preds=%18
%20=加载i32,i32*%1,对齐4
%21=添加新南威尔士州i32%20,1
存储i32%21,i32*%1,对齐4
br标签%7
; :22:                                     ; preds=%7
ret void

我的问题是标签14和15。看起来标签15只有一个前身14。既然如此,为什么我们不能把它和标签14合并呢?我假设基本块构造是通过上述算法完成的

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

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

相反,下面的大量简化伪代码对正在发生的情况进行了总结,这些伪代码松散地基于。这是转换(init;cond;incr)body形式的语句的逻辑。为简单起见,我们假设
cond
incr
都不是空的,并且
cond
是一个表达式,而不是一个声明

  • 创建新的基本块:
    conditionBlock
    bodyBlock
    incrBlock
    exitBlock
  • 将init的代码附加到当前基本块,然后跳转到
    conditionBlock
  • cond
    的代码附加到
    conditionBlock
    中,然后是
    br i1%cond、标签%bodyBlock、标签%exitBlock
  • {break:exitBlock,continue:incrBlock}
    推到break/continue堆栈上
  • body
    的代码附加到
    bodyBlock
    ,然后跳转到
    conditionBlock
  • 弹出“中断/继续”堆栈
  • 将退出块设置为当前基本块
要获得您所期望的输出,它必须将
incr
的代码发送到
bodyBlock
中,而不是为其设置单独的块。但是它无法将
incrBlock
推到中断/继续堆栈上。当然,这在您的情况下并不重要,因为您的代码不包含任何
continue
语句,但在一般情况下,编译器需要break/continue堆栈来知道在
break
s或
continue
s的情况下跳转到哪里


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

可能编译器总是为循环增量创建一个基本块,因此如果循环中有
continue
,它可以将其用作跳转目标(即使没有,它也会这样做,因为它不会伤害任何东西)?或者,代码只是以这种方式更方便地工作。“我假设基本块构造是通过这里提到的算法完成的。”该算法假设您将现有的三个地址代码分为基本块,但LLVM代码总是分为基本块。LLVM前端通常从AST到LLVM(我很确定clang会这样做),所以我们讨论的输入仍然包含循环和if语句,而不是跳转。@sepp2k,“我假设基本块构造是通过这里提到的算法完成的。".这里,我指的是那篇文章中提到的关于leader的规则,即如何拆分为基本块。或者你是说llvm代码从AST转换为CFG?我是说C代码从AST转换为llvm代码,这是CFG。没有基本块的llvm代码是不存在的。所以这不像
C->BLOCK llvm->LLVM-CFG
,它只是
C->LLVM
,这就是你的CFG。因此,识别基本块不是一个单独的步骤,它是生成LLVM的一部分。确切地说,它只是从树形式到LLVM形式,这是一个CFG(至少我很确定情况就是这样,因为LLVM通常就是这样使用的——我还没有看过clang的代码,但我怀疑clang是否会定义自己的TAC,然后将其转换为LLVM,而且LLVM肯定没有无块TAC形式)。
 store i32 119, i32* %3, align 4
  store i32 20, i32* %1, align 4
  br label %7

; <label>:7:                                      ; preds = %19, %0
  %8 = load i32, i32* %1, align 4
  %9 = icmp slt i32 %8, 200
  br i1 %9, label %10, label %22

; <label>:10:                                     ; preds = %7
  store i32 13, i32* %2, align 4
  br label %11

; <label>:11:                                     ; preds = %15, %10
  %12 = load i32, i32* %2, align 4
  %13 = icmp slt i32 %12, 130
  br i1 %13, label %14, label %18

; <label>:14:                                     ; preds = %11
  store i32 80, i32* %6, align 4
  br label %15

; <label>:15:                                     ; preds = %14
  %16 = load i32, i32* %2, align 4
  %17 = add nsw i32 %16, 1
  store i32 %17, i32* %2, align 4
  br label %11

; <label>:18:                                     ; preds = %11
  br label %19

; <label>:19:                                     ; preds = %18
  %20 = load i32, i32* %1, align 4
  %21 = add nsw i32 %20, 1
  store i32 %21, i32* %1, align 4
  br label %7

; <label>:22:                                     ; preds = %7
  ret void