[llvm cookbook] 模块化设计示例

llvm被设计成一系列库的集合。什么意思?就是每个模块都可以拿出来单独使用。
本文用llvm优化器opt命令行工具来展示它的模块化用法。

编写文件 testfile.ll

define i32 @test1(i32 %A) {
%B = add i32 %A, 0
ret i32 %B
}

define internal i32 @test(i32 %X, i32 %dead) {
ret i32 %X
}

define i32 @caller() {
%A = call i32 @test(i32 123, i32 456)
ret i32 %A
}

在任意目录执行如下命令

opt -S -instcombine testfile.ll -o output1.ll

输出文件 output1.ll内容如下

; ModuleID = 'testfile.ll'
source_filename = "testfile.ll"

define i32 @test1(i32 %A) {
ret i32 %A
}

define internal i32 @test(i32 %X, i32 %dead) {
ret i32 %X
}

define i32 @caller() {
%A = call i32 @test(i32 123, i32 456)
ret i32 %A
}

可以看到函数 test1 中的指令被合并了,这就是instcombine的作用。

再次执行命令:

opt -S -deadargelim testfile.ll -o output2.ll

输出output2.ll如下:

; ModuleID = 'testfile.ll'
source_filename = "testfile.ll"

define i32 @test1(i32 %A) {
%B = add i32 %A, 0
ret i32 %B
}

define internal i32 @test(i32 %X) {
ret i32 %X
}

define i32 @caller() {
%A = call i32 @test(i32 123)
ret i32 %A
}

这一次,指令没有合并,但test函数中没有用到的参数被删除了,就是deadargelim的作用。

llvm优化器的各pass相互不知道依赖关系,这个关系主要靠PassManager来管理。

除了优化器,还有代码生产器中的各模块也可以独立使用,包括

  • instruction selection
  • register allocation
  • scheduling
  • code layout optimization
  • assembly emission