This patch adds additional checks to avoid partial unswitching in cases where it won't be profitable, e.g. because the path directly exits the loop anyways.
912 lines
24 KiB
LLVM
912 lines
24 KiB
LLVM
; RUN: opt -loop-unswitch -verify-dom-info -verify-memoryssa -S -enable-new-pm=0 %s | FileCheck %s
|
|
|
|
declare void @clobber()
|
|
|
|
define i32 @partial_unswitch_true_successor(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor
|
|
; CHECK-LABEL: entry:
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]], label %[[SPLIT_TRUE_PH:[a-z._]+]], label %[[FALSE_CRIT:[a-z._]+]]
|
|
|
|
; CHECK: [[FALSE_CRIT]]:
|
|
; CHECK-NEXT: br label %[[FALSE_PH:[a-z.]+]]
|
|
|
|
; CHECK: [[SPLIT_TRUE_PH]]:
|
|
; CHECK-NEXT: br label %[[TRUE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[TRUE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[TRUE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[TRUE_C:%[a-z.0-9]+]] = icmp eq i32 [[TRUE_LV]], 100
|
|
; CHECK-NEXT: br i1 true, label %[[TRUE_NOCLOBBER:.+]], label %[[TRUE_CLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_NOCLOBBER]]:
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[TRUE_HEADER]]
|
|
|
|
|
|
; CHECK: [[FALSE_PH]]:
|
|
; CHECK-NEXT: br label %[[FALSE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[FALSE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[FALSE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[FALSE_C:%[a-z.0-9]+]] = icmp eq i32 [[FALSE_LV]], 100
|
|
; CHECK-NEXT: br i1 [[FALSE_C]], label %[[FALSE_NOCLOBBER:.+]], label %[[FALSE_CLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_NOCLOBBER]]:
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[FALSE_HEADER]]
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_false_successor
|
|
; CHECK-LABEL: entry:
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]], label %[[SPLIT_TRUE_PH:[a-z._]+]], label %[[FALSE_CRIT:[a-z._]+]]
|
|
|
|
; CHECK: [[FALSE_CRIT]]:
|
|
; CHECK-NEXT: br label %[[FALSE_PH:[a-z.]+]]
|
|
|
|
; CHECK: [[SPLIT_TRUE_PH]]:
|
|
; CHECK-NEXT: br label %[[TRUE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[TRUE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[TRUE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[TRUE_C:%[a-z.0-9]+]] = icmp eq i32 [[TRUE_LV]], 100
|
|
; CHECK-NEXT: br i1 [[TRUE_C]], label %[[TRUE_CLOBBER:.+]], label %[[TRUE_NOCLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_NOCLOBBER]]:
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[TRUE_HEADER]]
|
|
|
|
|
|
; CHECK: [[FALSE_PH]]:
|
|
; CHECK-NEXT: br label %[[FALSE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[FALSE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[FALSE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[FALSE_C:%[a-z.0-9]+]] = icmp eq i32 [[FALSE_LV]], 100
|
|
; CHECK-NEXT: br i1 false, label %[[FALSE_CLOBBER:.+]], label %[[FALSE_NOCLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_NOCLOBBER]]:
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[FALSE_HEADER]]
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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(i32** %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswtich_gep_load_icmp
|
|
; CHECK-LABEL: entry:
|
|
; CHECK-NEXT: [[GEP:%[a-z.0-9]+]] = getelementptr i32*, i32** %ptr, i32 1
|
|
; CHECK-NEXT: [[LV0:%[a-z.0-9]+]] = load i32*, i32** [[GEP]]
|
|
; CHECK-NEXT: [[LV1:%[a-z.0-9]+]] = load i32, i32* [[LV0]]
|
|
; CHECK-NEXT: [[C:%[a-z.0-9]+]] = icmp eq i32 [[LV1]], 100
|
|
; CHECK-NEXT: br i1 [[C]], label %[[SPLIT_TRUE_PH:[a-z._]+]], label %[[FALSE_CRIT:[a-z._]+]]
|
|
|
|
; CHECK: [[FALSE_CRIT]]:
|
|
; CHECK-NEXT: br label %[[FALSE_PH:[a-z.]+]]
|
|
|
|
; CHECK: [[SPLIT_TRUE_PH]]:
|
|
; CHECK-NEXT: br label %[[TRUE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[TRUE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[TRUE_GEP:%[a-z.0-9]+]] = getelementptr i32*, i32** %ptr, i32 1
|
|
; CHECK-NEXT: [[TRUE_LV0:%[a-z.0-9]+]] = load i32*, i32** [[TRUE_GEP]]
|
|
; CHECK-NEXT: [[TRUE_LV1:%[a-z.0-9]+]] = load i32, i32* [[TRUE_LV0]]
|
|
; CHECK-NEXT: [[TRUE_C:%[a-z.0-9]+]] = icmp eq i32 [[TRUE_LV1]], 100
|
|
; CHECK-NEXT: br i1 true, label %[[TRUE_NOCLOBBER:.+]], label %[[TRUE_CLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_NOCLOBBER]]:
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[TRUE_HEADER]]
|
|
|
|
; CHECK: [[FALSE_PH]]:
|
|
; CHECK-NEXT: br label %[[FALSE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[FALSE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[FALSE_GEP:%[a-z.0-9]+]] = getelementptr i32*, i32** %ptr, i32 1
|
|
; CHECK-NEXT: [[FALSE_LV0:%[a-z.0-9]+]] = load i32*, i32** [[FALSE_GEP]]
|
|
; CHECK-NEXT: [[FALSE_LV1:%[a-z.0-9]+]] = load i32, i32* [[FALSE_LV0]]
|
|
; CHECK-NEXT: [[FALSE_C:%[a-z.0-9]+]] = icmp eq i32 [[FALSE_LV1]], 100
|
|
; CHECK-NEXT: br i1 [[FALSE_C]], label %[[FALSE_NOCLOBBER:.+]], label %[[FALSE_CLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_NOCLOBBER]]:
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
|
|
; CHECK: [[FALSE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[FALSE_HEADER]]
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%gep = getelementptr i32*, i32** %ptr, i32 1
|
|
%lv.1 = load i32*, i32** %gep
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_reduction_phi
|
|
; CHECK-LABEL: entry:
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]], label %[[SPLIT_TRUE_PH:[a-z._]+]], label %[[FALSE_CRIT:[a-z._]+]]
|
|
|
|
; CHECK: [[FALSE_CRIT]]:
|
|
; CHECK-NEXT: br label %[[FALSE_PH:[a-z.]+]]
|
|
|
|
; CHECK: [[SPLIT_TRUE_PH]]:
|
|
; CHECK-NEXT: br label %[[TRUE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[TRUE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[TRUE_RED:%[a-z.0-9]+]] = phi i32 [ 20, %[[SPLIT_TRUE_PH]] ], [ [[TRUE_RED_NEXT:%[a-z.0-9]+]], %[[TRUE_LATCH:[a-z.0-9]+]]
|
|
; CHECK-NEXT: [[TRUE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[TRUE_C:%[a-z.0-9]+]] = icmp eq i32 [[TRUE_LV]], 100
|
|
; CHECK-NEXT: br i1 [[TRUE_C]], label %[[TRUE_CLOBBER:.+]], label %[[TRUE_NOCLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_NOCLOBBER]]:
|
|
; CHECK-NEXT: [[TRUE_ADD10:%.+]] = add i32 [[TRUE_RED]], 10
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH]]
|
|
|
|
; CHECK: [[TRUE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: [[TRUE_ADD5:%.+]] = add i32 [[TRUE_RED]], 5
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH]]
|
|
|
|
; CHECK: [[TRUE_LATCH]]:
|
|
; CHECK-NEXT: [[TRUE_RED_NEXT]] = phi i32 [ [[TRUE_ADD5]], %[[TRUE_CLOBBER]] ], [ [[TRUE_ADD10]], %[[TRUE_NOCLOBBER]] ]
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[TRUE_HEADER]]
|
|
|
|
|
|
; CHECK: [[FALSE_PH]]:
|
|
; CHECK-NEXT: br label %[[FALSE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[FALSE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[FALSE_RED:%[a-z.0-9]+]] = phi i32 [ 20, %[[FALSE_PH]] ], [ [[FALSE_RED_NEXT:%[a-z.0-9]+]], %[[FALSE_LATCH:[a-z.0-9]+]]
|
|
; CHECK-NEXT: [[FALSE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[FALSE_C:%[a-z.0-9]+]] = icmp eq i32 [[FALSE_LV]], 100
|
|
; CHECK-NEXT: br i1 false, label %[[FALSE_CLOBBER:.+]], label %[[FALSE_NOCLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: [[FALSE_ADD5:%.+]] = add i32 [[FALSE_RED]], 5
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_NOCLOBBER]]:
|
|
; CHECK-NEXT: [[FALSE_ADD10:%.+]] = add i32 [[FALSE_RED]], 10
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_LATCH]]:
|
|
; CHECK-NEXT: [[FALSE_RED_NEXT]] = phi i32 [ [[FALSE_ADD5]], %[[FALSE_CLOBBER]] ], [ [[FALSE_ADD10]], %[[FALSE_NOCLOBBER]] ]
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[FALSE_HEADER]]
|
|
;
|
|
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, i32* %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(i32* noalias %ptr.1, i32* noalias %ptr.2, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr.1, align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]], label %[[SPLIT_TRUE_PH:[a-z._]+]], label %[[FALSE_CRIT:[a-z._]+]]
|
|
|
|
; CHECK: [[FALSE_CRIT]]:
|
|
; CHECK-NEXT: br label %[[FALSE_PH:[a-z.]+]]
|
|
|
|
; CHECK: [[SPLIT_TRUE_PH]]:
|
|
; CHECK-NEXT: br label %[[TRUE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[TRUE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[TRUE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr.1, align 4
|
|
; CHECK-NEXT: [[TRUE_C:%[a-z.0-9]+]] = icmp eq i32 [[TRUE_LV]], 100
|
|
; CHECK-NEXT: br i1 true, label %[[TRUE_NOCLOBBER:.+]], label %[[TRUE_CLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_NOCLOBBER]]:
|
|
; CHECK-NEXT: [[TRUE_GEP:%[a-z0-9._]+]] = getelementptr i32, i32* %ptr.2
|
|
; CHECK-NEXT: store i32 [[TRUE_LV]], i32* [[TRUE_GEP]], align 4
|
|
; CHECK-NEXT: br label %[[TRUE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[TRUE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[TRUE_HEADER]]
|
|
|
|
|
|
; CHECK: [[FALSE_PH]]:
|
|
; CHECK-NEXT: br label %[[FALSE_HEADER:[a-z.]+]]
|
|
|
|
; CHECK: [[FALSE_HEADER]]:
|
|
; CHECK-NEXT: phi i32
|
|
; CHECK-NEXT: [[FALSE_LV:%[a-z.0-9]+]] = load i32, i32* %ptr.1, align 4
|
|
; CHECK-NEXT: [[FALSE_C:%[a-z.0-9]+]] = icmp eq i32 [[FALSE_LV]], 100
|
|
; CHECK-NEXT: br i1 [[FALSE_C]], label %[[FALSE_NOCLOBBER:.+]], label %[[FALSE_CLOBBER:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_NOCLOBBER]]:
|
|
; CHECK-NEXT: [[FALSE_GEP:%[a-z0-9._]+]] = getelementptr i32, i32* %ptr.2
|
|
; CHECK-NEXT: store i32 [[FALSE_LV]], i32* [[FALSE_GEP]], align 4
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_CLOBBER]]:
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: br label %[[FALSE_LATCH:[a-z0-9._]+]]
|
|
|
|
; CHECK: [[FALSE_LATCH]]:
|
|
; CHECK-NEXT: icmp
|
|
; CHECK-NEXT: add
|
|
; CHECK-NEXT: br {{.*}} label %[[FALSE_HEADER]]
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %ptr.1
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
%gep.1 = getelementptr i32, i32* %ptr.2, i32 %iv
|
|
store i32 %lv, i32* %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
|
|
;
|
|
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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_clobber_latch
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_clobber_header
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
call void @clobber()
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_clobber_both
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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(i32* %ptr.1, i32* %ptr.2, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_true_successor_storeclobber
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %ptr.1
|
|
%sc = icmp eq i32 %lv, 100
|
|
br i1 %sc, label %noclobber, label %clobber
|
|
|
|
noclobber:
|
|
%gep.1 = getelementptr i32, i32* %ptr.2, i32 %iv
|
|
store i32 %lv, i32* %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
|
|
}
|
|
|
|
; Check that MemorySSA updating can deal with a clobbering access of a
|
|
; duplicated load being a MemoryPHI outside the loop.
|
|
define void @partial_unswitch_memssa_update(i32* noalias %ptr, i1 %c) {
|
|
; CHECK-LABEL: @partial_unswitch_memssa_update(
|
|
; CHECK-LABEL: loop.ph:
|
|
; CHECK-NEXT: [[LV:%[a-z0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[C:%[a-z0-9]+]] = icmp eq i32 [[LV]], 0
|
|
; CHECK-NEXT: br i1 [[C]]
|
|
entry:
|
|
br i1 %c, label %loop.ph, label %outside.clobber
|
|
|
|
outside.clobber:
|
|
call void @clobber()
|
|
br label %loop.ph
|
|
|
|
loop.ph:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%lv = load i32, i32* %ptr, align 4
|
|
%hc = icmp eq i32 %lv, 0
|
|
br i1 %hc, label %if, label %then
|
|
|
|
if:
|
|
br label %loop.latch
|
|
|
|
then:
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
br i1 true, label %loop.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; 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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_preheader_insertion(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[EC:%[a-z]+]] = icmp ne i32* %ptr, null
|
|
; CHECK-NEXT: br i1 [[EC]], label %[[PH:[a-z0-9.]+]], label %[[EXIT:[a-z0-9.]+]]
|
|
|
|
; CHECK: [[PH]]:
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]]
|
|
;
|
|
entry:
|
|
%ec = icmp ne i32* %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, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_insert_point(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: call void @clobber()
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]]
|
|
;
|
|
entry:
|
|
call void @clobber()
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_successor_hoist_invariant(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[GEP:%[0-9]+]] = getelementptr i32, i32* %ptr, i64 1
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* [[GEP]], align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]]
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%gep = getelementptr i32, i32* %ptr, i64 1
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_atomic_load_unordered
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load atomic i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_atomic_load_monotonic
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load atomic i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_cond_call
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_true_successor_exit
|
|
; CHECK-LABEL: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @no_partial_unswitch_true_same_successor
|
|
; CHECK-LABEL: entry:
|
|
; CHECK-NEXT: br label %loop.header
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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(i32* %ptr, i32 %N) {
|
|
; CHECK-LABEL: @partial_unswitch_true_to_latch
|
|
; CHECK-LABEL: entry:
|
|
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
|
|
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
|
|
; CHECK-NEXT: br i1 [[C]],
|
|
;
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%lv = load i32, i32* %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
|
|
}
|