
With the addition of #84628, truncs to i1 are being emitted as conditions to branch instructions. This caused significant regressions in cases which were previously improved by loop unswitch. Adding truncs to i1 restore the previous performance seen.
1471 lines
51 KiB
LLVM
1471 lines
51 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>),verify<loops>' -S < %s | FileCheck %s
|
|
|
|
declare void @clobber()
|
|
|
|
define i32 @partial_unswitch_true_successor(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP0:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @partial_unswitch_false_successor(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_false_successor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT:%.*]], label [[ENTRY_SPLIT_US:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[CLOBBER:%.*]], label [[NOCLOBBER:%.*]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP2:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %clobber, label %noclobber
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @partial_unswtich_gep_load_icmp(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswtich_gep_load_icmp(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr ptr, ptr [[PTR:%.*]], i32 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 4
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 100
|
|
; CHECK-NEXT: br i1 [[TMP3]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr ptr, ptr [[PTR]], i32 1
|
|
; CHECK-NEXT: [[LV_1:%.*]] = load ptr, ptr [[GEP]], align 8
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[LV_1]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP3:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%gep = getelementptr ptr, ptr %ptr, i32 1
|
|
%lv.1 = load ptr, ptr %gep
|
|
%lv = load i32, ptr %lv.1
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @partial_unswitch_reduction_phi(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_reduction_phi(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT:%.*]], label [[ENTRY_SPLIT_US:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: [[RED_US:%.*]] = phi i32 [ 20, [[ENTRY_SPLIT_US]] ], [ [[RED_NEXT_US:%.*]], [[LOOP_LATCH_US]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: [[ADD_10_US:%.*]] = add i32 [[RED_US]], 10
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[RED_NEXT_US]] = phi i32 [ [[ADD_10_US]], [[NOCLOBBER_US]] ]
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: [[RED_NEXT_LCSSA_US:%.*]] = phi i32 [ [[RED_NEXT_US]], [[LOOP_LATCH_US]] ]
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[RED:%.*]] = phi i32 [ 20, [[ENTRY_SPLIT]] ], [ [[RED_NEXT:%.*]], [[LOOP_LATCH]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[CLOBBER:%.*]], label [[NOCLOBBER:%.*]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: [[ADD_5:%.*]] = add i32 [[RED]], 5
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: [[ADD_10:%.*]] = add i32 [[RED]], 10
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[RED_NEXT]] = phi i32 [ [[ADD_5]], [[CLOBBER]] ], [ [[ADD_10]], [[NOCLOBBER]] ]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP4:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: [[RED_NEXT_LCSSA:%.*]] = phi i32 [ [[RED_NEXT]], [[LOOP_LATCH]] ]
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[RED_NEXT_LCSSA]], [[EXIT_SPLIT]] ], [ [[RED_NEXT_LCSSA_US]], [[EXIT_SPLIT_US]] ]
|
|
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%red = phi i32 [ 20, %entry ], [ %red.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %clobber, label %noclobber
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
%add.5 = add i32 %red, 5
|
|
br label %loop.latch
|
|
|
|
noclobber:
|
|
%add.10 = add i32 %red, 10
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%red.next = phi i32 [ %add.5, %clobber ], [ %add.10, %noclobber ]
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
%red.next.lcssa = phi i32 [ %red.next, %loop.latch ]
|
|
ret i32 %red.next.lcssa
|
|
}
|
|
|
|
; Partial unswitching is possible, because the store in %noclobber does not
|
|
; alias the load of the condition.
|
|
define i32 @partial_unswitch_true_successor_noclobber(ptr noalias %ptr.1, ptr noalias %ptr.2, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_noclobber(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR_1:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: [[LV_US:%.*]] = load i32, ptr [[PTR_1]], align 4
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: [[GEP_1_US:%.*]] = getelementptr i32, ptr [[PTR_2:%.*]], i32 [[IV_US]]
|
|
; CHECK-NEXT: store i32 [[LV_US]], ptr [[GEP_1_US]], align 4
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR_1]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i32, ptr [[PTR_2]], i32 [[IV]]
|
|
; CHECK-NEXT: store i32 [[LV]], ptr [[GEP_1]], align 4
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP5:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr.1
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
%gep.1 = getelementptr i32, ptr %ptr.2, i32 %iv
|
|
store i32 %lv, ptr %gep.1
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define void @no_partial_unswitch_phi_cond(i1 %lc, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_phi_cond(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[SC:%.*]] = phi i1 [ [[LC:%.*]], [[ENTRY]] ], [ true, [[LOOP_LATCH]] ]
|
|
; CHECK-NEXT: br i1 [[SC]], label [[CLOBBER:%.*]], label [[NOCLOBBER:%.*]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%sc = phi i1 [ %lc, %entry ], [ true, %loop.latch ]
|
|
br i1 %sc, label %clobber, label %noclobber
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @no_partial_unswitch_clobber_latch(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_clobber_latch(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
call void @clobber()
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @no_partial_unswitch_clobber_header(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_clobber_header(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
call void @clobber()
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @no_partial_unswitch_clobber_both(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_clobber_both(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define i32 @no_partial_unswitch_true_successor_storeclobber(ptr %ptr.1, ptr %ptr.2, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_true_successor_storeclobber(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR_1:%.*]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i32, ptr [[PTR_2:%.*]], i32 [[IV]]
|
|
; CHECK-NEXT: store i32 [[LV]], ptr [[GEP_1]], align 4
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr.1
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
%gep.1 = getelementptr i32, ptr %ptr.2, i32 %iv
|
|
store i32 %lv, ptr %gep.1
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
; Make sure the duplicated instructions are moved to a preheader that always
|
|
; executes when the loop body also executes. Do not check the unswitched code,
|
|
; because it is already checked in the @partial_unswitch_true_successor test
|
|
; case.
|
|
define i32 @partial_unswitch_true_successor_preheader_insertion(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_preheader_insertion(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[EC:%.*]] = icmp ne ptr [[PTR:%.*]], null
|
|
; CHECK-NEXT: br i1 [[EC]], label [[LOOP_PH:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: loop.ph:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PH_SPLIT_US:%.*]], label [[LOOP_PH_SPLIT:%.*]]
|
|
; CHECK: loop.ph.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[LOOP_PH_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_LOOPEXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.loopexit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT_LOOPEXIT:%.*]]
|
|
; CHECK: loop.ph.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[LOOP_PH_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_LOOPEXIT_SPLIT:%.*]], !llvm.loop [[LOOP6:![0-9]+]]
|
|
; CHECK: exit.loopexit.split:
|
|
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
|
|
; CHECK: exit.loopexit:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
|
|
entry:
|
|
%ec = icmp ne ptr %ptr, null
|
|
br i1 %ec, label %loop.ph, label %exit
|
|
|
|
loop.ph:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %loop.ph ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
; Make sure the duplicated instructions are hoisted just before the branch of
|
|
; the preheader. Do not check the unswitched code, because it is already checked
|
|
; in the @partial_unswitch_true_successor test case
|
|
define i32 @partial_unswitch_true_successor_insert_point(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_insert_point(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP7:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
call void @clobber()
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
; Make sure invariant instructions in the loop are also hoisted to the preheader.
|
|
; Do not check the unswitched code, because it is already checked in the
|
|
; @partial_unswitch_true_successor test case
|
|
define i32 @partial_unswitch_true_successor_hoist_invariant(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_hoist_invariant(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i32, ptr [[PTR:%.*]], i64 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 100
|
|
; CHECK-NEXT: br i1 [[TMP2]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[PTR]], i64 1
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[GEP]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP8:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%gep = getelementptr i32, ptr %ptr, i64 1
|
|
%lv = load i32, ptr %gep
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
; Do not unswitch if the condition depends on an atomic load. Duplicating such
|
|
; loads is not safe.
|
|
define i32 @no_partial_unswitch_atomic_load_unordered(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_atomic_load_unordered(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load atomic i32, ptr [[PTR:%.*]] unordered, align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load atomic i32, ptr %ptr unordered, align 4
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
; Do not unswitch if the condition depends on an atomic load. Duplicating such
|
|
; loads is not safe.
|
|
define i32 @no_partial_unswitch_atomic_load_monotonic(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_atomic_load_monotonic(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load atomic i32, ptr [[PTR:%.*]] monotonic, align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load atomic i32, ptr %ptr monotonic, align 4
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
|
|
declare i32 @get_value()
|
|
|
|
; Do not unswitch if the condition depends on a call, that may clobber memory.
|
|
; Duplicating such a call is not safe.
|
|
define i32 @no_partial_unswitch_cond_call(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_cond_call(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = call i32 @get_value()
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = call i32 @get_value()
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @no_partial_unswitch_true_successor_exit(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_true_successor_exit(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[EXIT:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %exit, label %clobber
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @no_partial_unswitch_true_same_successor(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_true_same_successor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[NOCLOBBER]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %noclobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @partial_unswitch_true_to_latch(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_to_latch(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[LOOP_LATCH]], label [[CLOBBER:%.*]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP9:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %loop.latch, label %clobber
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
; There could be multiple unswitch candidates which include partially invariant
|
|
; condition. When the exiting block is selected as best unswitch one, clone loop
|
|
; blocks.
|
|
define i32 @partial_unswitch_exiting_block_with_multiple_unswitch_candidates(i32 %0, i32 %1, ptr %ptr) {
|
|
; CHECK-LABEL: @partial_unswitch_exiting_block_with_multiple_unswitch_candidates(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[EXIT_COND:%.*]] = icmp ne i32 [[TMP0:%.*]], 0
|
|
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[PTR:%.*]], align 16
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 41
|
|
; CHECK-NEXT: br i1 [[TMP3]], label [[ENTRY_SPLIT:%.*]], label [[ENTRY_SPLIT_US:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br i1 [[EXIT_COND]], label [[ENTRY_SPLIT_US_SPLIT_US:%.*]], label [[ENTRY_SPLIT_US_SPLIT:%.*]]
|
|
; CHECK: entry.split.us.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_US_US:%.*]]
|
|
; CHECK: loop.us.us:
|
|
; CHECK-NEXT: br label [[EXITING_US_US:%.*]]
|
|
; CHECK: exiting.us.us:
|
|
; CHECK-NEXT: br label [[LOOP_US_US]]
|
|
; CHECK: entry.split.us.split:
|
|
; CHECK-NEXT: br label [[LOOP_US:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: br label [[EXITING_US:%.*]]
|
|
; CHECK: exiting.us:
|
|
; CHECK-NEXT: br label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: [[RET_VAL_US:%.*]] = phi i32 [ 1, [[EXITING_US]] ]
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[PTR]], align 16
|
|
; CHECK-NEXT: [[IF_COND:%.*]] = icmp ult i32 [[VAL]], 41
|
|
; CHECK-NEXT: br i1 [[IF_COND]], label [[IF_THEN:%.*]], label [[EXITING:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: store i32 [[TMP1:%.*]], ptr [[PTR]], align 16
|
|
; CHECK-NEXT: br label [[EXITING]]
|
|
; CHECK: exiting:
|
|
; CHECK-NEXT: br i1 [[EXIT_COND]], label [[LOOP]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP10:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: [[RET_VAL:%.*]] = phi i32 [ 1, [[EXITING]] ]
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[RET_VAL]], [[EXIT_SPLIT]] ], [ [[RET_VAL_US]], [[EXIT_SPLIT_US]] ]
|
|
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
|
|
;
|
|
entry:
|
|
%exit.cond = icmp ne i32 %0, 0
|
|
br label %loop
|
|
|
|
loop:
|
|
%val = load i32, ptr %ptr, align 16
|
|
%if.cond = icmp ult i32 %val, 41
|
|
br i1 %if.cond, label %if.then, label %exiting
|
|
|
|
if.then:
|
|
store i32 %1, ptr %ptr, align 16
|
|
br label %exiting
|
|
|
|
exiting:
|
|
br i1 %exit.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
%ret.val = phi i32 [ 1, %exiting ]
|
|
ret i32 %ret.val
|
|
}
|
|
|
|
; The path with noclobber block is only duplicated so we need to calculate only
|
|
; the cost of the path with noclobber.
|
|
define i32 @partial_unswitch_true_successor_for_cost_calculation(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_for_cost_calculation(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP11:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @partial_unswitch_true_successor_trunc(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_trunc(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i1
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = trunc i32 [[LV]] to i1
|
|
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP12:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = trunc i32 %lv to i1
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
define i32 @partial_unswitch_false_successor_trunc(ptr %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_false_successor_trunc(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i1
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT:%.*]], label [[ENTRY_SPLIT_US:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
|
|
; CHECK: loop.header.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
|
|
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
|
|
; CHECK: noclobber.us:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
|
|
; CHECK: loop.latch.us:
|
|
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
|
|
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
|
|
; CHECK-NEXT: [[SC:%.*]] = trunc i32 [[LV]] to i1
|
|
; CHECK-NEXT: br i1 [[SC]], label [[CLOBBER:%.*]], label [[NOCLOBBER:%.*]]
|
|
; CHECK: clobber:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: noclobber:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP13:![0-9]+]]
|
|
; CHECK: exit.split:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, ptr %ptr
|
|
%sc = trunc i32 %lv to i1
|
|
br i1 %sc, label %clobber, label %noclobber
|
|
|
|
clobber:
|
|
call void @clobber()
|
|
br label %loop.latch
|
|
|
|
noclobber:
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%c = icmp ult i32 %iv, %N
|
|
%iv.next = add i32 %iv, 1
|
|
br i1 %c, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret i32 10
|
|
}
|
|
|
|
; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[UNSWITCH_PARTIAL_DISABLE:![0-9]+]]}
|
|
; CHECK: [[UNSWITCH_PARTIAL_DISABLE]] = !{!"llvm.loop.unswitch.partial.disable"}
|
|
; CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP10]] = distinct !{[[LOOP10]], [[UNSWITCH_PARTIAL_DISABLE]]}
|
|
; CHECK: [[LOOP11]] = distinct !{[[LOOP11]], [[UNSWITCH_PARTIAL_DISABLE]]}
|