-simplifycfg: Simplify the CFG
在了解这个 pass 之前需要学习的背景知识是 Loop Terminology in LLVM。
Description
-simplifycfg pass,类似 instruction level 的 -dce 等 pass,是 basic block (i.e. the minimal units of program control-flow graph) level 的 optimization pass。
通过 simplifying program control-flow graph(例如 dead basic block elimination or basic block merging)的方式优化程序的 performance。具体而言它可以优化的情景有四种:
- Removing basic blocks with no predecessors.
因为没有 basic block 会通向这个 basic block, obviously dead 了,所以可以被remove掉。
- Merging a basic block into its predecessor if there is only one and the predecessor only has one successor.
很明显都是单向路径,所以直接 merge 就好了,这道理就像笔直的道路没有必要单独开一个红绿灯一样。
- Eliminating Phi nodes for basic blocks with a single predecessor.
因为只有一个predecessor,所以
Phinode 只有一个赋值的方向,还不如直接等于,所以可以被 eliminate。
- Eliminating a basic block that only contains an unconditional branch.
这个可能有点抽象,所以给出一个 code example。我们先给定一个原始的 IR code。
define i32 @example_func(i32 %x) { entry: %cmp = icmp sgt i32 %x, 10 br i1 %cmp, label %greater, label %less_or_equal greater: ; Basic block with only an unconditional branch br label %exit less_or_equal: ; Basic block with useful instructions %sub = sub i32 10, %x %result = add i32 %sub, 5 br label %exit exit: %final_result = phi i32 [ 0, %entry ], [ %result, %less_or_equal ], [ 0, %greater ] ret i32 %final_result }
可以看到,这会
greaterbasic block 的brinstruction 只跳转到一个固定的 basic block,是一个 unconditional branch,没有任何实际的操作。 所以这个 block 可以被删掉(i.e. 直接从其 predecessor 跳转到其 successor)。-simplifycfgtransform 过的 IR code 如下所示:define i32 @example_func(i32 %x) { entry: %cmp = icmp sgt i32 %x, 10 br i1 %cmp, label %less_or_equal, label %less_or_equal less_or_equal: ; Basic block with useful instructions %sub = sub i32 10, %x %result = add i32 %sub, 5 br label %exit exit: %final_result = phi i32 [ 0, %entry ], [ %result, %less_or_equal ], [ 0, %entry ] ret i32 %final_result }
Code Example
上面已经给过一个比较清楚的 code example 了,所以这里略。