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

循环不变量(Loop Invariant Code Motion)

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

源码

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

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

	for(int i=0;i<limit-2;i++)  // limit -2 是循环不变量
	{
		sum += i;
	}

	return 0;
}

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

; <label>:2                                       ; preds = %11, %0
  %3 = load i32, i32* %i, align 4
  %4 = load i32, i32* %limit, align 4
  %5 = sub nsw i32 %4, 2                      // 未优化前 limit -2,计算多次
  %6 = icmp slt i32 %3, %5
  br i1 %6, label %7, label %14

; <label>:7                                       ; preds = %2
  %8 = load i32, i32* %i, align 4
  %9 = load i32, i32* %sum, align 4
  %10 = add nsw i32 %9, %8
  store i32 %10, i32* %sum, align 4
  br label %11

; <label>:11                                      ; preds = %7
  %12 = load i32, i32* %i, align 4
  %13 = add nsw i32 %12, 1
  store i32 %13, i32* %i, align 4
  br label %2

; <label>:14                                      ; preds = %2
  ret i32 0
}

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

; <label>:4                                       ; preds = %11, %0
  %5 = load i32, i32* %i, align 4
  %6 = icmp slt i32 %5, %3
  br i1 %6, label %7, label %14

; <label>:7                                       ; preds = %4
  %8 = load i32, i32* %i, align 4
  %9 = load i32, i32* %sum, align 4
  %10 = add nsw i32 %9, %8
  store i32 %10, i32* %sum, align 4
  br label %11

; <label>:11                                      ; preds = %7
  %12 = load i32, i32* %i, align 4
  %13 = add nsw i32 %12, 1
  store i32 %13, i32* %i, align 4
  br label %4

; <label>:14                                      ; preds = %4
  ret i32 0
}

实现原理

.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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值