forked from OSchip/llvm-project
286 lines
8.3 KiB
LLVM
286 lines
8.3 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -loop-unroll -verify-loop-lcssa -S | FileCheck %s
|
|
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
|
|
|
; This test shows how unrolling an inner loop could break LCSSA for an outer
|
|
; loop, and there is no cheap way to recover it.
|
|
;
|
|
; In this case the inner loop, L3, is being unrolled. It only runs one
|
|
; iteration, so unrolling basically means replacing
|
|
; br i1 true, label %exit, label %L3_header
|
|
; with
|
|
; br label %exit
|
|
;
|
|
; However, this change messes up the loops structure: for instance, block
|
|
; L3_body no longer belongs to L2. It becomes an exit block for L2, so LCSSA
|
|
; phis for definitions in L2 should now be placed there. In particular, we need
|
|
; to insert such a definition for %y1.
|
|
|
|
define void @foo1() {
|
|
; CHECK-LABEL: @foo1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[L1_HEADER:%.*]]
|
|
; CHECK: L1_header:
|
|
; CHECK-NEXT: br label [[L2_HEADER:%.*]]
|
|
; CHECK: L2_header:
|
|
; CHECK-NEXT: [[Y1:%.*]] = phi i64 [ undef, [[L1_HEADER]] ], [ [[X_LCSSA:%.*]], [[L2_LATCH:%.*]] ]
|
|
; CHECK-NEXT: br label [[L3_HEADER:%.*]]
|
|
; CHECK: L3_header:
|
|
; CHECK-NEXT: br i1 true, label [[L2_LATCH]], label [[L3_BODY:%.*]]
|
|
; CHECK: L2_latch:
|
|
; CHECK-NEXT: [[X_LCSSA]] = phi i64 [ undef, [[L3_HEADER]] ]
|
|
; CHECK-NEXT: br label [[L2_HEADER]]
|
|
; CHECK: L3_body:
|
|
; CHECK-NEXT: [[Y1_LCSSA:%.*]] = phi i64 [ [[Y1]], [[L3_HEADER]] ]
|
|
; CHECK-NEXT: store i64 [[Y1_LCSSA]], i64* undef, align 8
|
|
; CHECK-NEXT: br i1 false, label [[L3_LATCH:%.*]], label [[L1_LATCH:%.*]]
|
|
; CHECK: L3_latch:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L1_latch:
|
|
; CHECK-NEXT: [[Y_LCSSA:%.*]] = phi i64 [ [[Y1_LCSSA]], [[L3_BODY]] ]
|
|
; CHECK-NEXT: br label [[L1_HEADER]]
|
|
;
|
|
entry:
|
|
br label %L1_header
|
|
|
|
L1_header:
|
|
br label %L2_header
|
|
|
|
L2_header:
|
|
%y1 = phi i64 [ undef, %L1_header ], [ %x.lcssa, %L2_latch ]
|
|
br label %L3_header
|
|
|
|
L3_header:
|
|
%y2 = phi i64 [ 0, %L3_latch ], [ %y1, %L2_header ]
|
|
%x = add i64 undef, -1
|
|
br i1 true, label %L2_latch, label %L3_body
|
|
|
|
L2_latch:
|
|
%x.lcssa = phi i64 [ %x, %L3_header ]
|
|
br label %L2_header
|
|
|
|
L3_body:
|
|
store i64 %y1, i64* undef
|
|
br i1 false, label %L3_latch, label %L1_latch
|
|
|
|
L3_latch:
|
|
br i1 true, label %exit, label %L3_header
|
|
|
|
L1_latch:
|
|
%y.lcssa = phi i64 [ %y2, %L3_body ]
|
|
br label %L1_header
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Additional tests for some corner cases.
|
|
define void @foo2() {
|
|
; CHECK-LABEL: @foo2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[L1_HEADER:%.*]]
|
|
; CHECK: L1_header:
|
|
; CHECK-NEXT: br label [[L2_HEADER:%.*]]
|
|
; CHECK: L2_header.loopexit:
|
|
; CHECK-NEXT: [[DEC_US_LCSSA:%.*]] = phi i64 [ undef, [[L3_HEADER:%.*]] ]
|
|
; CHECK-NEXT: br label [[L2_HEADER]]
|
|
; CHECK: L2_header:
|
|
; CHECK-NEXT: [[A:%.*]] = phi i64 [ undef, [[L1_HEADER]] ], [ [[DEC_US_LCSSA]], [[L2_HEADER_LOOPEXIT:%.*]] ]
|
|
; CHECK-NEXT: br label [[L3_HEADER]]
|
|
; CHECK: L3_header:
|
|
; CHECK-NEXT: br i1 true, label [[L2_HEADER_LOOPEXIT]], label [[L3_BREAK_TO_L1:%.*]]
|
|
; CHECK: L3_break_to_L1:
|
|
; CHECK-NEXT: [[A_LCSSA:%.*]] = phi i64 [ [[A]], [[L3_HEADER]] ]
|
|
; CHECK-NEXT: br i1 false, label [[L3_LATCH:%.*]], label [[L1_LATCH:%.*]]
|
|
; CHECK: L1_latch:
|
|
; CHECK-NEXT: [[B_LCSSA:%.*]] = phi i64 [ [[A_LCSSA]], [[L3_BREAK_TO_L1]] ]
|
|
; CHECK-NEXT: br label [[L1_HEADER]]
|
|
; CHECK: L3_latch:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %L1_header
|
|
|
|
L1_header:
|
|
br label %L2_header
|
|
|
|
L2_header:
|
|
%a = phi i64 [ undef, %L1_header ], [ %dec_us, %L3_header ]
|
|
br label %L3_header
|
|
|
|
L3_header:
|
|
%b = phi i64 [ 0, %L3_latch ], [ %a, %L2_header ]
|
|
%dec_us = add i64 undef, -1
|
|
br i1 true, label %L2_header, label %L3_break_to_L1
|
|
|
|
L3_break_to_L1:
|
|
br i1 false, label %L3_latch, label %L1_latch
|
|
|
|
L1_latch:
|
|
%b_lcssa = phi i64 [ %b, %L3_break_to_L1 ]
|
|
br label %L1_header
|
|
|
|
L3_latch:
|
|
br i1 true, label %Exit, label %L3_header
|
|
|
|
Exit:
|
|
ret void
|
|
}
|
|
|
|
define void @foo3() {
|
|
; CHECK-LABEL: @foo3(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[L1_HEADER:%.*]]
|
|
; CHECK: L1_header:
|
|
; CHECK-NEXT: [[A:%.*]] = phi i8* [ [[B:%.*]], [[L1_LATCH:%.*]] ], [ null, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: br i1 undef, label [[L2_HEADER_PREHEADER:%.*]], label [[L1_LATCH]]
|
|
; CHECK: L2_header.preheader:
|
|
; CHECK-NEXT: br label [[L2_HEADER:%.*]]
|
|
; CHECK: L2_header:
|
|
; CHECK-NEXT: br i1 false, label [[L2_LATCH:%.*]], label [[L1_LATCH_LOOPEXIT:%.*]]
|
|
; CHECK: L2_latch:
|
|
; CHECK-NEXT: [[A_LCSSA:%.*]] = phi i8* [ [[A]], [[L2_HEADER]] ]
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: L1_latch.loopexit:
|
|
; CHECK-NEXT: br label [[L1_LATCH]]
|
|
; CHECK: L1_latch:
|
|
; CHECK-NEXT: [[B]] = phi i8* [ undef, [[L1_HEADER]] ], [ null, [[L1_LATCH_LOOPEXIT]] ]
|
|
; CHECK-NEXT: br label [[L1_HEADER]]
|
|
; CHECK: Exit:
|
|
; CHECK-NEXT: [[A_LCSSA2:%.*]] = phi i8* [ [[A_LCSSA]], [[L2_LATCH]] ]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %L1_header
|
|
|
|
L1_header:
|
|
%a = phi i8* [ %b, %L1_latch ], [ null, %entry ]
|
|
br i1 undef, label %L2_header, label %L1_latch
|
|
|
|
L2_header:
|
|
br i1 undef, label %L2_latch, label %L1_latch
|
|
|
|
L2_latch:
|
|
br i1 true, label %L2_exit, label %L2_header
|
|
|
|
L1_latch:
|
|
%b = phi i8* [ undef, %L1_header ], [ null, %L2_header ]
|
|
br label %L1_header
|
|
|
|
L2_exit:
|
|
%a_lcssa1 = phi i8* [ %a, %L2_latch ]
|
|
br label %Exit
|
|
|
|
Exit:
|
|
%a_lcssa2 = phi i8* [ %a_lcssa1, %L2_exit ]
|
|
ret void
|
|
}
|
|
|
|
; PR26688
|
|
define i8 @foo4() {
|
|
; CHECK-LABEL: @foo4(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[L1_HEADER:%.*]]
|
|
; CHECK: L1_header:
|
|
; CHECK-NEXT: br label [[L2_HEADER:%.*]]
|
|
; CHECK: L2_header.loopexit:
|
|
; CHECK-NEXT: br label [[L2_HEADER]]
|
|
; CHECK: L2_header:
|
|
; CHECK-NEXT: br label [[L3_HEADER:%.*]]
|
|
; CHECK: L3_header:
|
|
; CHECK-NEXT: br i1 true, label [[L2_HEADER_LOOPEXIT:%.*]], label [[L3_EXITING:%.*]]
|
|
; CHECK: L3_exiting:
|
|
; CHECK-NEXT: br i1 true, label [[L3_BODY:%.*]], label [[L1_LATCH:%.*]]
|
|
; CHECK: L3_body:
|
|
; CHECK-NEXT: [[X_LCSSA:%.*]] = phi i1 [ false, [[L3_EXITING]] ]
|
|
; CHECK-NEXT: br i1 [[X_LCSSA]], label [[L3_LATCH:%.*]], label [[L3_LATCH]]
|
|
; CHECK: L3_latch:
|
|
; CHECK-NEXT: ret i8 0
|
|
; CHECK: L1_latch:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
br label %L1_header
|
|
|
|
L1_header:
|
|
%x = icmp eq i32 1, 0
|
|
br label %L2_header
|
|
|
|
L2_header:
|
|
br label %L3_header
|
|
|
|
L3_header:
|
|
br i1 true, label %L2_header, label %L3_exiting
|
|
|
|
L3_exiting:
|
|
br i1 true, label %L3_body, label %L1_latch
|
|
|
|
L3_body:
|
|
br i1 %x, label %L3_latch, label %L3_latch
|
|
|
|
L3_latch:
|
|
br i1 false, label %L3_header, label %exit
|
|
|
|
L1_latch:
|
|
br label %L1_header
|
|
|
|
exit:
|
|
ret i8 0
|
|
}
|
|
|
|
define void @foo5() {
|
|
; CHECK-LABEL: @foo5(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[OUTER:%.*]]
|
|
; CHECK: outer:
|
|
; CHECK-NEXT: br label [[INNER1:%.*]]
|
|
; CHECK: inner1:
|
|
; CHECK-NEXT: br label [[INNER2_INDIRECT_EXIT:%.*]]
|
|
; CHECK: inner2_indirect_exit:
|
|
; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[B:%.*]], [[INNER2_LATCH:%.*]] ], [ undef, [[INNER1]] ]
|
|
; CHECK-NEXT: indirectbr i8* undef, [label [[INNER2_LATCH]], label [[INNER3:%.*]], label %outer_latch]
|
|
; CHECK: inner2_latch:
|
|
; CHECK-NEXT: [[B]] = load i32, i32* undef, align 8
|
|
; CHECK-NEXT: br label [[INNER2_INDIRECT_EXIT]]
|
|
; CHECK: inner3:
|
|
; CHECK-NEXT: [[A_LCSSA:%.*]] = phi i32 [ [[A_LCSSA]], [[INNER3]] ], [ [[A]], [[INNER2_INDIRECT_EXIT]] ]
|
|
; CHECK-NEXT: br i1 true, label [[OUTER_LATCH_LOOPEXIT:%.*]], label [[INNER3]]
|
|
; CHECK: outer_latch.loopexit:
|
|
; CHECK-NEXT: [[A_LCSSA_LCSSA2:%.*]] = phi i32 [ [[A_LCSSA]], [[INNER3]] ]
|
|
; CHECK-NEXT: [[A_LCSSA_LCSSA:%.*]] = phi i32 [ [[A_LCSSA]], [[INNER3]] ]
|
|
; CHECK-NEXT: br label [[OUTER_LATCH:%.*]]
|
|
; CHECK: outer_latch:
|
|
; CHECK-NEXT: br label [[OUTER]]
|
|
;
|
|
entry:
|
|
br label %outer
|
|
|
|
outer:
|
|
br label %inner1
|
|
|
|
inner1:
|
|
br i1 true, label %inner2_indirect_exit.preheader, label %inner1
|
|
|
|
inner2_indirect_exit.preheader:
|
|
br label %inner2_indirect_exit
|
|
|
|
inner2_indirect_exit:
|
|
%a = phi i32 [ %b, %inner2_latch ], [ undef, %inner2_indirect_exit.preheader ]
|
|
indirectbr i8* undef, [label %inner2_latch, label %inner3, label %outer_latch]
|
|
|
|
inner2_latch:
|
|
%b = load i32, i32* undef, align 8
|
|
br label %inner2_indirect_exit
|
|
|
|
inner3:
|
|
%a.lcssa = phi i32 [ %a.lcssa, %inner3 ], [ %a, %inner2_indirect_exit ]
|
|
br i1 true, label %outer_latch.loopexit, label %inner3
|
|
|
|
outer_latch.loopexit:
|
|
%a.lcssa.lcssa = phi i32 [ %a.lcssa, %inner3 ]
|
|
br label %outer_latch
|
|
|
|
outer_latch:
|
|
br label %outer
|
|
}
|