When doing load/store promotion within LICM, if we
cannot prove that it is safe to sink the store we won't
hoist the load, even though we can prove the load could
be dereferenced and moved outside the loop. This patch
implements the load promotion by moving it in the loop
preheader by inserting proper PHI in the loop. The store
is kept as is in the loop. By doing this, we avoid doing
the load from a memory location in each iteration.
Please consider this small example:
loop {
var = *ptr;
if (var) break;
*ptr= var + 1;
}
After this patch, it will be:
var0 = *ptr;
loop {
var1 = phi (var0, var2);
if (var1) break;
var2 = var1 + 1;
*ptr = var2;
}
This addresses some problems from [0].
[0] https://bugs.llvm.org/show_bug.cgi?id=51193
Differential revision: https://reviews.llvm.org/D113289
158 lines
5.1 KiB
LLVM
158 lines
5.1 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -S -passes='loop-mssa(licm)' < %s | FileCheck %s
|
|
|
|
declare i1 @cond(i32 %v) readnone
|
|
declare void @capture(i32* %p) readnone
|
|
|
|
define void @test_captured_after_loop(i32 %len) {
|
|
; CHECK-LABEL: @test_captured_after_loop(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COUNT:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: [[COUNT_PROMOTED:%.*]] = load i32, i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[C_INC2:%.*]] = phi i32 [ [[COUNT_PROMOTED]], [[ENTRY:%.*]] ], [ [[C_INC1:%.*]], [[LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[I_NEXT:%.*]], [[LATCH]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond(i32 [[I]])
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF:%.*]], label [[LATCH]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: [[C_INC:%.*]] = add i32 [[C_INC2]], 1
|
|
; CHECK-NEXT: br label [[LATCH]]
|
|
; CHECK: latch:
|
|
; CHECK-NEXT: [[C_INC1]] = phi i32 [ [[C_INC]], [[IF]] ], [ [[C_INC2]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_NEXT]], [[LEN:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[C_INC1_LCSSA:%.*]] = phi i32 [ [[C_INC1]], [[LATCH]] ]
|
|
; CHECK-NEXT: store i32 [[C_INC1_LCSSA]], i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: call void @capture(i32* [[COUNT]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%count = alloca i32
|
|
store i32 0, i32* %count
|
|
br label %loop
|
|
|
|
loop:
|
|
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
|
|
%cond = call i1 @cond(i32 %i)
|
|
br i1 %cond, label %if, label %latch
|
|
|
|
if:
|
|
%c = load i32, i32* %count
|
|
%c.inc = add i32 %c, 1
|
|
store i32 %c.inc, i32* %count
|
|
br label %latch
|
|
|
|
latch:
|
|
%i.next = add nuw i32 %i, 1
|
|
%cmp = icmp eq i32 %i.next, %len
|
|
br i1 %cmp, label %exit, label %loop
|
|
|
|
exit:
|
|
call void @capture(i32* %count)
|
|
ret void
|
|
}
|
|
|
|
define void @test_captured_in_loop(i32 %len) {
|
|
; CHECK-LABEL: @test_captured_in_loop(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COUNT:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond(i32 [[I]])
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF:%.*]], label [[LATCH]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: [[C:%.*]] = load i32, i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: [[C_INC:%.*]] = add i32 [[C]], 1
|
|
; CHECK-NEXT: store i32 [[C_INC]], i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: call void @capture(i32* [[COUNT]])
|
|
; CHECK-NEXT: br label [[LATCH]]
|
|
; CHECK: latch:
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_NEXT]], [[LEN:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%count = alloca i32
|
|
store i32 0, i32* %count
|
|
br label %loop
|
|
|
|
loop:
|
|
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
|
|
%cond = call i1 @cond(i32 %i)
|
|
br i1 %cond, label %if, label %latch
|
|
|
|
if:
|
|
%c = load i32, i32* %count
|
|
%c.inc = add i32 %c, 1
|
|
store i32 %c.inc, i32* %count
|
|
call void @capture(i32* %count)
|
|
br label %latch
|
|
|
|
latch:
|
|
%i.next = add nuw i32 %i, 1
|
|
%cmp = icmp eq i32 %i.next, %len
|
|
br i1 %cmp, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_captured_before_loop(i32 %len) {
|
|
; CHECK-LABEL: @test_captured_before_loop(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COUNT:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: call void @capture(i32* [[COUNT]])
|
|
; CHECK-NEXT: [[COUNT_PROMOTED:%.*]] = load i32, i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[C_INC2:%.*]] = phi i32 [ [[COUNT_PROMOTED]], [[ENTRY:%.*]] ], [ [[C_INC1:%.*]], [[LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[I_NEXT:%.*]], [[LATCH]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond(i32 [[I]])
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF:%.*]], label [[LATCH]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: [[C_INC:%.*]] = add i32 [[C_INC2]], 1
|
|
; CHECK-NEXT: store i32 [[C_INC]], i32* [[COUNT]], align 4
|
|
; CHECK-NEXT: br label [[LATCH]]
|
|
; CHECK: latch:
|
|
; CHECK-NEXT: [[C_INC1]] = phi i32 [ [[C_INC]], [[IF]] ], [ [[C_INC2]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_NEXT]], [[LEN:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%count = alloca i32
|
|
store i32 0, i32* %count
|
|
call void @capture(i32* %count)
|
|
br label %loop
|
|
|
|
loop:
|
|
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
|
|
%cond = call i1 @cond(i32 %i)
|
|
br i1 %cond, label %if, label %latch
|
|
|
|
if:
|
|
%c = load i32, i32* %count
|
|
%c.inc = add i32 %c, 1
|
|
store i32 %c.inc, i32* %count
|
|
br label %latch
|
|
|
|
latch:
|
|
%i.next = add nuw i32 %i, 1
|
|
%cmp = icmp eq i32 %i.next, %len
|
|
br i1 %cmp, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|