381 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			381 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			LLVM
		
	
	
	
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 | 
						|
; RUN: opt < %s -loop-deletion -S | FileCheck %s
 | 
						|
 | 
						|
@G = external global i32
 | 
						|
 | 
						|
define void @test_trivial() {
 | 
						|
; CHECK-LABEL: @test_trivial(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 false, label [[LOOP_LOOP_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       loop.loop_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  store i32 0, i32* @G
 | 
						|
  br i1 false, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
define void @test_bottom_tested() {
 | 
						|
; CHECK-LABEL: @test_bottom_tested(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    [[IV_INC:%.*]] = add i32 [[IV]], 1
 | 
						|
; CHECK-NEXT:    [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
 | 
						|
; CHECK-NEXT:    br i1 [[BE_TAKEN]], label [[LOOP_LOOP_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       loop.loop_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  %iv = phi i32 [ 0, %entry], [ %iv.inc, %loop ]
 | 
						|
  store i32 0, i32* @G
 | 
						|
  %iv.inc = add i32 %iv, 1
 | 
						|
  %be_taken = icmp ne i32 %iv.inc, 1
 | 
						|
  br i1 %be_taken, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
define void @test_early_exit() {
 | 
						|
; CHECK-LABEL: @test_early_exit(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    [[IV_INC:%.*]] = add i32 [[IV]], 1
 | 
						|
; CHECK-NEXT:    [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
 | 
						|
; CHECK-NEXT:    br i1 [[BE_TAKEN]], label [[LATCH:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    br label [[LATCH_SPLIT:%.*]]
 | 
						|
; CHECK:       latch.split:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  %iv = phi i32 [ 0, %entry], [ %iv.inc, %latch ]
 | 
						|
  store i32 0, i32* @G
 | 
						|
  %iv.inc = add i32 %iv, 1
 | 
						|
  %be_taken = icmp ne i32 %iv.inc, 1
 | 
						|
  br i1 %be_taken, label %latch, label %exit
 | 
						|
latch:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
define void @test_multi_exit1() {
 | 
						|
; CHECK-LABEL: @test_multi_exit1(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    [[IV_INC:%.*]] = add i32 [[IV]], 1
 | 
						|
; CHECK-NEXT:    [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
 | 
						|
; CHECK-NEXT:    br i1 [[BE_TAKEN]], label [[LATCH:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    store i32 1, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    [[COND2:%.*]] = icmp ult i32 [[IV_INC]], 30
 | 
						|
; CHECK-NEXT:    br i1 [[COND2]], label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT]]
 | 
						|
; CHECK:       latch.loop_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  %iv = phi i32 [ 0, %entry], [ %iv.inc, %latch ]
 | 
						|
  store i32 0, i32* @G
 | 
						|
  %iv.inc = add i32 %iv, 1
 | 
						|
  %be_taken = icmp ne i32 %iv.inc, 1
 | 
						|
  br i1 %be_taken, label %latch, label %exit
 | 
						|
latch:
 | 
						|
  store i32 1, i32* @G
 | 
						|
  %cond2 = icmp ult i32 %iv.inc, 30
 | 
						|
  br i1 %cond2, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
define void @test_multi_exit2() {
 | 
						|
; CHECK-LABEL: @test_multi_exit2(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 true, label [[LATCH:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    store i32 1, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 false, label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT]]
 | 
						|
; CHECK:       latch.loop_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  store i32 0, i32* @G
 | 
						|
  br i1 true, label %latch, label %exit
 | 
						|
latch:
 | 
						|
  store i32 1, i32* @G
 | 
						|
  br i1 false, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
; TODO: SCEV seems not to recognize this as a zero btc loop
 | 
						|
define void @test_multi_exit3(i1 %cond1) {
 | 
						|
; CHECK-LABEL: @test_multi_exit3(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[LATCH:%.*]] ]
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 [[COND1:%.*]], label [[LATCH]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    store i32 1, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    [[IV_INC]] = add i32 [[IV]], 1
 | 
						|
; CHECK-NEXT:    [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
 | 
						|
; CHECK-NEXT:    br i1 [[BE_TAKEN]], label [[LOOP]], label [[EXIT]]
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  %iv = phi i32 [ 0, %entry], [ %iv.inc, %latch ]
 | 
						|
  store i32 0, i32* @G
 | 
						|
  br i1 %cond1, label %latch, label %exit
 | 
						|
latch:
 | 
						|
  store i32 1, i32* @G
 | 
						|
  %iv.inc = add i32 %iv, 1
 | 
						|
  %be_taken = icmp ne i32 %iv.inc, 1
 | 
						|
  br i1 %be_taken, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
; Subtle - This is either zero btc, or infinite, thus, can't break
 | 
						|
; backedge
 | 
						|
define void @test_multi_exit4(i1 %cond1, i1 %cond2) {
 | 
						|
; CHECK-LABEL: @test_multi_exit4(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 [[COND1:%.*]], label [[LATCH:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    store i32 1, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 [[COND2:%.*]], label [[LOOP]], label [[EXIT]]
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  store i32 0, i32* @G
 | 
						|
  br i1 %cond1, label %latch, label %exit
 | 
						|
latch:
 | 
						|
  store i32 1, i32* @G
 | 
						|
  br i1 %cond2, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
; A simple case with multiple exit blocks
 | 
						|
define void @test_multi_exit5() {
 | 
						|
; CHECK-LABEL: @test_multi_exit5(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 true, label [[LATCH:%.*]], label [[EXIT1:%.*]]
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    store i32 1, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 false, label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT2:%.*]]
 | 
						|
; CHECK:       latch.loop_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       exit1:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
; CHECK:       exit2:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  store i32 0, i32* @G
 | 
						|
  br i1 true, label %latch, label %exit1
 | 
						|
latch:
 | 
						|
  store i32 1, i32* @G
 | 
						|
  br i1 false, label %loop, label %exit2
 | 
						|
 | 
						|
exit1:
 | 
						|
  ret void
 | 
						|
exit2:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
define void @test_live_inner() {
 | 
						|
; CHECK-LABEL: @test_live_inner(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br label [[INNER:%.*]]
 | 
						|
; CHECK:       inner:
 | 
						|
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[LOOP]] ], [ [[IV_INC:%.*]], [[INNER]] ]
 | 
						|
; CHECK-NEXT:    store i32 [[IV]], i32* @G, align 4
 | 
						|
; CHECK-NEXT:    [[IV_INC]] = add i32 [[IV]], 1
 | 
						|
; CHECK-NEXT:    [[CND:%.*]] = icmp ult i32 [[IV_INC]], 200
 | 
						|
; CHECK-NEXT:    br i1 [[CND]], label [[INNER]], label [[LATCH:%.*]]
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    br i1 false, label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       latch.loop_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  store i32 0, i32* @G
 | 
						|
  br label %inner
 | 
						|
 | 
						|
inner:
 | 
						|
  %iv = phi i32 [0, %loop], [%iv.inc, %inner]
 | 
						|
  store i32 %iv, i32* @G
 | 
						|
  %iv.inc = add i32 %iv, 1
 | 
						|
  %cnd = icmp ult i32 %iv.inc, 200
 | 
						|
  br i1 %cnd, label %inner, label %latch
 | 
						|
 | 
						|
latch:
 | 
						|
  br i1 false, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
define void @test_live_outer() {
 | 
						|
; CHECK-LABEL: @test_live_outer(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    br label [[LOOP:%.*]]
 | 
						|
; CHECK:       loop:
 | 
						|
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[LATCH:%.*]] ]
 | 
						|
; CHECK-NEXT:    br label [[INNER:%.*]]
 | 
						|
; CHECK:       inner:
 | 
						|
; CHECK-NEXT:    store i32 0, i32* @G, align 4
 | 
						|
; CHECK-NEXT:    br i1 false, label [[INNER_INNER_CRIT_EDGE:%.*]], label [[LATCH]]
 | 
						|
; CHECK:       inner.inner_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       latch:
 | 
						|
; CHECK-NEXT:    store i32 [[IV]], i32* @G, align 4
 | 
						|
; CHECK-NEXT:    [[IV_INC]] = add i32 [[IV]], 1
 | 
						|
; CHECK-NEXT:    [[CND:%.*]] = icmp ult i32 [[IV_INC]], 200
 | 
						|
; CHECK-NEXT:    br i1 [[CND]], label [[LOOP]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret void
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %loop
 | 
						|
 | 
						|
loop:
 | 
						|
  %iv = phi i32 [0, %entry], [%iv.inc, %latch]
 | 
						|
  br label %inner
 | 
						|
 | 
						|
inner:
 | 
						|
  store i32 0, i32* @G
 | 
						|
  br i1 false, label %inner, label %latch
 | 
						|
 | 
						|
latch:
 | 
						|
  store i32 %iv, i32* @G
 | 
						|
  %iv.inc = add i32 %iv, 1
 | 
						|
  %cnd = icmp ult i32 %iv.inc, 200
 | 
						|
  br i1 %cnd, label %loop, label %exit
 | 
						|
 | 
						|
exit:
 | 
						|
  ret void
 | 
						|
}
 | 
						|
 | 
						|
; Key point is that inner_latch drops out of the outer loop when
 | 
						|
; the inner loop is deleted, and thus the lcssa phi needs to be
 | 
						|
; in the inner_latch block to preserve LCSSA.  We either have to
 | 
						|
; insert the LCSSA phi, or not break the inner backedge.
 | 
						|
define void @loop_nest_lcssa() {
 | 
						|
; CHECK-LABEL: @loop_nest_lcssa(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[TMP0:%.*]] = add i32 1, 2
 | 
						|
; CHECK-NEXT:    br label [[OUTER_HEADER:%.*]]
 | 
						|
; CHECK:       outer_header:
 | 
						|
; CHECK-NEXT:    br label [[INNER_HEADER:%.*]]
 | 
						|
; CHECK:       inner_header:
 | 
						|
; CHECK-NEXT:    br i1 false, label [[INNER_LATCH:%.*]], label [[OUTER_LATCH:%.*]]
 | 
						|
; CHECK:       inner_latch:
 | 
						|
; CHECK-NEXT:    [[DOTLCSSA:%.*]] = phi i32 [ [[TMP0]], [[INNER_HEADER]] ]
 | 
						|
; CHECK-NEXT:    br i1 false, label [[INNER_LATCH_INNER_HEADER_CRIT_EDGE:%.*]], label [[LOOPEXIT:%.*]]
 | 
						|
; CHECK:       inner_latch.inner_header_crit_edge:
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
; CHECK:       outer_latch:
 | 
						|
; CHECK-NEXT:    br label [[OUTER_HEADER]]
 | 
						|
; CHECK:       loopexit:
 | 
						|
; CHECK-NEXT:    [[DOTLCSSA32:%.*]] = phi i32 [ [[DOTLCSSA]], [[INNER_LATCH]] ]
 | 
						|
; CHECK-NEXT:    unreachable
 | 
						|
;
 | 
						|
entry:
 | 
						|
  br label %outer_header
 | 
						|
 | 
						|
outer_header:
 | 
						|
  %0 = add i32 1, 2
 | 
						|
  br label %inner_header
 | 
						|
 | 
						|
inner_header:
 | 
						|
  br i1 false, label %inner_latch, label %outer_latch
 | 
						|
 | 
						|
inner_latch:
 | 
						|
  br i1 false, label %inner_header, label %loopexit
 | 
						|
 | 
						|
outer_latch:
 | 
						|
  br label %outer_header
 | 
						|
 | 
						|
loopexit:
 | 
						|
  %.lcssa32 = phi i32 [ %0, %inner_latch ]
 | 
						|
  unreachable
 | 
						|
}
 |