当我们如果完成了对源码的转换,得到了LLVM的IR表示形式,它是作为一种向汇编代码转换的一个公共平台,依赖不同的后端会得到不同的汇编码,在转换为汇编码之前,如果我们对IR进行优化的话就可以得到执行效率更高的代码
在LLVM的架构当中,Pass的作用就是优化LLVM IR,Pass作用于LLVM IR,用来处理IR,分析IR,寻找优化的机会并修改IR,从而产生优化的代码。在下面命令行工具opt就是用来在LLVM IR上运行各种优化Pass的
通常来说编译器的优化会有多种级别,有0~3级别,优化级别越高,代码得到的优化也越多
首先我们先去写一个C语言程序
int main(int argc,char **argv)
{
int i,j,k,t=0;
for (i=0; i<10; i++) {
for (j=0; j<10; j++) {
for (k=0; k<10; k++) {
t++;
}
}
for (j=0;j<10; j++) {
t++;
}
}
for (i=0; i<20; i++) {
for (j=0; j<20; j++) {
t++;
}
for (j=0; j<20; j++) {
t++;
}
}
return t;
}
使用clang命令也就是clang -S -O0 -emit-llvm example.c 把源码转换成LLVM IR生成的包含LLVM IR的example.ll的文件内容如下所示
; ModuleID = 'example.c'
source_filename = "example.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.13.0"
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @main(i32, i8**) #0 {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i8**, align 8
%6 = alloca i32, align 4
%7 = alloca i32, align 4
%8 = alloca i32, align 4
%9 = alloca i32, align 4
store i32 0, i32* %3, align 4
store i32 %0, i32* %4, align 4
store i8** %1, i8*** %5, align 8
store i32 0, i32* %9, align 4
store i32 0, i32* %6, align 4
br label %10
; <label>:10: ; preds = %42, %2
%11 = load i32, i32* %6, align 4
%12 = icmp slt i32 %11, 10
br i1 %12, label %13, label %45
; <label>:13: ; preds = %10
store i32 0, i32* %7, align 4
br label %14
; <label>:14: ; preds = %28, %13
%15 = load i32, i32* %7, align 4
%16 = icmp slt i32 %15, 10
br i1 %16, label %17, label %31
; <label>:17: ; preds = %14
store i32 0, i32* %8, align 4
br label %18
; <label>:18: ; preds = %24, %17
%19 = load i32, i32* %8, align 4
%20 = icmp slt i32 %19, 10
br i1 %20, label %21, label %27
; <label>:21: ; preds = %18
%22 = load i32, i32* %9, align 4
%23 = add nsw i32 %22, 1
store i32 %23, i32* %9, align 4
br label %24
; <label>:24: ; preds = %21
%25 = load i32, i32* %8, align 4
%26 = add nsw i32 %25, 1
store i32 %26, i32* %8, align 4
br label %18
; <label>:27: ; preds = %18
br label %28
; <label>:28: ; preds = %27
%29 = load i32, i32* %7, align 4
%30 = add nsw i32 %29, 1
store i32 %30, i32* %7, align 4
br label %14
; <label>:31: ; preds = %14
store i32 0, i32* %7, align 4
br label %32
; <label>:32: ; preds = %38, %31
%33 = load i32, i32* %7, align 4
%34 = icmp slt i32 %33, 10
br i1 %34, label %35, label %41
; <label>:35: ; preds = %32
%36 = load i32, i32* %9, align 4
%37 = add nsw i32 %36, 1
store i32 %37, i32* %9, align 4
br label %38
; <label>:38: ; preds = %35
%39 = load i32, i32* %7, align 4
%40 = add nsw i32 %39, 1
store i32 %40, i32* %7, align 4
br label %32
; <label>:41: ; preds = %32
br label %42
; <label>:42: ; preds = %41
%43 = load i32, i32* %6, align 4
%44 = add nsw i32 %43, 1
store i32 %44, i32* %6, align 4
br label %10
; <label>:45: ; preds = %10
store i32 0, i32* %6, align 4
br label %46
; <label>:46: ; preds = %70, %45
%47 = load i32, i32* %6, align 4
%48 = icmp slt i32 %47, 20
br i1 %48, label %49, label %73
; <label>:49: ; preds = %46
store i32 0, i32* %7, align 4
br label %50
; <label>:50: ; preds = %56, %49
%51 = load i32, i32* %7, align 4
%52 = icmp slt i32 %51, 20
br i1 %52, label %53, label %59
; <label>:53: ; preds = %50
%54 = load i32, i32* %9, align 4
%55 = add nsw i32 %54, 1
store i32 %55, i32* %9, align 4
br label %56
; <label>:56: ; preds = %53
%57 = load i32, i32* %7, align 4
%58 = add nsw i32 %57, 1
store i32 %58, i32* %7, align 4
br label %50
; <label>:59: ; preds = %50
store i32 0, i32* %7, align 4
br label %60
; <label>:60: ; preds = %66, %59
%61 = load i32, i32* %7, align 4
%62 = icmp slt i32 %61, 20
br i1 %62, label %63, label %69
; <label>:63: ; preds = %60
%64 = load i32, i32* %9, align 4
%65 = add nsw i32 %64, 1
store i32 %65, i32* %9, align 4
br label %66
; <label>:66: ; preds = %63
%67 = load i32, i32* %7, align 4
%68 = add nsw i32 %67, 1
store i32 %68, i32* %7, align 4
br label %60
; <label>:69: ; preds = %60
br label %70
; <label>:70: ; preds = %69
%71 = load i32, i32* %6, align 4
%72 = add nsw i32 %71, 1
store i32 %72, i32* %6, align 4
br label %46
; <label>:73: ; preds = %46
%74 = load i32, i32* %9, align 4
ret i32 %74
}
我们可以使用opt -O0 -S example.ll去进行优化包含IR的example.ll文件,我们还可以使用下面的命令进行优化
- opt -O1 -S example.ll
- opt -O2 -S example.ll
- opt -O3 -S example.ll
这里其实就是opt命令行工具使用example.ll文件作为输入,运行优先级别对应的一系列Pass,它也能在同一个优先级别重复运行一些Pass。如果我们需要去查看在每一个优先级别运行了哪些Pass,我们只需要在opt命令之后加入–debug-pass=Structure命令行选项就可以了
我们通过执行opt -O1 -S example.ll获得的结果如下所示,优化的直接返回1900了,其实上面的C程序返回的结果就是1900
; ModuleID = 'example.ll'
source_filename = "example.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.13.0"
; Function Attrs: norecurse nounwind readnone
define i32 @main(i32, i8** nocapture readnone) local_unnamed_addr #0 {
ret i32 1900
}
attributes #0 = { norecurse nounwind readnone }