LLVM Pass 分析【2】:Loop Invariant Code Motion

循环不变量(Loop Invariant Code Motion)

循环不变量(loop invariant)就是不会随着每轮循环改变的表达式,优化程序只在循环体外计算一次并在循环过程中使用。编译器的优化程序能找出循环不变量并使用“代码移动(code motion)”将其移出循环体。

源码

#include 
#include 
#include 

int main()
{
	int sum =0;
	int limit = 12;

	for(int i=0;i

LLVM IR

; ModuleID = 'loopInvarable.c'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  %sum = alloca i32, align 4
  %limit = alloca i32, align 4
  %i = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 0, i32* %sum, align 4
  store i32 12, i32* %limit, align 4
  store i32 0, i32* %i, align 4
  br label %2

; 

LLVM IR (优化后)

; ModuleID = 'loopInvarable.ll'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  %sum = alloca i32, align 4
  %limit = alloca i32, align 4
  %i = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 0, i32* %sum, align 4
  store i32 12, i32* %limit, align 4
  store i32 0, i32* %i, align 4
  %2 = load i32, i32* %limit, align 4
  %3 = sub nsw i32 %2, 2                // 优化后 limit -2,计算一次,后面直接使用该计算结果
  br label %4

; 

实现原理

.mark

LLVM opt参数 -licm

This pass performs loop invariant code motion, attempting to remove as much code from the body of a loop as possible. It does this by either hoisting code into the preheader block, or by sinking code to the exit blocks if it is safe. This pass also promotes must-aliased memory locations in the loop to live in registers, thus hoisting and sinking “invariant” loads and stores.

This pass uses alias analysis for two purposes:

  1. Moving loop invariant loads and calls out of loops. If we can determine that a load or call inside of a loop never aliases anything stored to, we can hoist it or sink it like any other instruction.
  2. Scalar Promotion of Memory. If there is a store instruction inside of the loop, we try to move the store to happen AFTER the loop instead of inside of the loop. This can only happen if a few conditions are true:
    1. The pointer stored through is loop invariant.
    2. There are no stores or loads in the loop which may alias the pointer. There are no calls in the loop which mod/ref the pointer.

If these conditions are true, we can promote the loads and stores in the loop of the pointer to use a temporary alloca’d variable. We then use the mem2reg functionality to construct the appropriate SSA form for the variable.

参考资料

https://www.cs.cmu.edu/~15745/lectures/L9-LICM.pdf
https://www.llvm.org/docs/Passes.html

你可能感兴趣的:(#,LLVM,Scalar,Opt)