【发布时间】:2018-11-12 03:55:20
【问题描述】:
我只是在玩一个程序并在 llvm 中观察它的 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;
}
}
}
对应的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
我的问题是标签 14 和 15。看起来标签 15 只有一个前任,即 14。既然如此,为什么我们不能将它与标签 14 合并?我假设基本的块构造是由提到的算法here 完成的。
【问题讨论】:
-
也许编译器总是为循环增量创建一个基本块,因此如果循环中有
continue,它可以将其用作跳转目标(即使没有,它也会这样做,因为它没有伤害任何东西)?或者也许代码只是这样更方便地计算出来。 -
"我假设基本块的构建是由这里提到的算法完成的。"该算法假定您将现有的三地址代码分类为基本块,但 LLVM 代码始终分为基本块。 LLVM 前端通常从 AST 转到 LLVM(我很确定 clang 无论如何都会这样做),所以我们谈论的输入仍然包含循环和 if 语句,而不是跳转。
-
@sepp2k, "我假设基本块的构建是由这里提到的算法完成的。"。我指的是那篇文章中提到的关于领导者的规则,即如何拆分成基本块。还是您的意思是 llvm 代码从 AST 转换为 CFG?
-
我的意思是 C 代码从 AST 转换为 LLVM 代码,是 CFG。没有基本块的 LLVM 代码是不存在的。所以它不像
C -> blockless LLVM-> LLVM-CFG,它只是C -> LLVM,那是你的CFG。所以识别基本块不是一个单独的步骤,它是生成 LLVM 的一部分。 -
没错,它只是从树形式到 LLVM 形式,这是一个 CFG(至少我很确定情况就是这样,因为这就是通常使用 LLVM 的方式——我实际上并没有看过在 clang 的代码中,但我怀疑 clang 会定义它自己的 TAC,然后将其转换为 LLVM,并且绝对没有 LLVM 的无块 TAC 形式。
标签: compiler-construction llvm