mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
eb30ce19c4
These intrinsics, not the icmp+select are the canonical form nowadays, so we might as well directly emit them. This should not cause any regressions, but if it does, then then they would needed to be fixed regardless. Note that this doesn't deal with `SCEVExpander::isHighCostExpansion()`, but that is a pessimization, not a correctness issue. Additionally, the non-intrinsic form has issues with undef, see https://reviews.llvm.org/D88287#2587863
1094 lines
47 KiB
LLVM
1094 lines
47 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -loop-predication -S | FileCheck %s
|
|
|
|
declare void @prevent_merging()
|
|
|
|
; Base case - with side effects in loop
|
|
define i32 @test1(i32* %array, i32 %length, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @test1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP3]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
|
|
|
|
define i32 @test_non_canonical(i32* %array, i32 %length, i1 %cond_0) {
|
|
; CHECK-LABEL: @test_non_canonical(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[LENGTH:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP3]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %length
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
|
|
define i32 @test_two_range_checks(i32* %array, i32 %length.1, i32 %length.2, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @test_two_range_checks(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2:%.*]], i32 [[LENGTH_1:%.*]])
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH_1]], [[UMIN1]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i32 [[LENGTH_2]], [[UMIN1]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = freeze i1 [[TMP4]]
|
|
; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP3]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP6]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED2:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED2]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH_1]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS2:%.*]] = icmp ult i32 [[I]], [[LENGTH_2]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED2]], label [[DEOPT3:%.*]], !prof !0
|
|
; CHECK: deopt3:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET3]]
|
|
; CHECK: guarded2:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED2]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length.1
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%within.bounds2 = icmp ult i32 %i, %length.2
|
|
br i1 %within.bounds2, label %guarded2, label %deopt3, !prof !0
|
|
|
|
deopt3:
|
|
call void @unknown()
|
|
%deoptret3 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret3
|
|
|
|
guarded2:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded2 ]
|
|
ret i32 %result
|
|
}
|
|
|
|
@G = external global i32
|
|
|
|
define i32 @test_unanalyzeable_exit(i32* %array, i32 %length, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @test_unanalyzeable_exit(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED2:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED2]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, i32* @G, align 4
|
|
; CHECK-NEXT: [[UNKNOWN:%.*]] = icmp eq i32 [[VOL]], 0
|
|
; CHECK-NEXT: br i1 [[UNKNOWN]], label [[GUARDED2]], label [[DEOPT3:%.*]], !prof !0
|
|
; CHECK: deopt3:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET3]]
|
|
; CHECK: guarded2:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED2]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%vol = load volatile i32, i32* @G
|
|
%unknown = icmp eq i32 %vol, 0
|
|
br i1 %unknown, label %guarded2, label %deopt3, !prof !0
|
|
|
|
deopt3:
|
|
call void @unknown()
|
|
%deoptret3 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret3
|
|
|
|
guarded2:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded2 ]
|
|
ret i32 %result
|
|
}
|
|
|
|
define i32 @test_unanalyzeable_exit2(i32* %array, i32 %length, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @test_unanalyzeable_exit2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP3]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED2:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED2]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, i32* @G, align 4
|
|
; CHECK-NEXT: [[UNKNOWN:%.*]] = icmp eq i32 [[VOL]], 0
|
|
; CHECK-NEXT: br i1 [[UNKNOWN]], label [[GUARDED2]], label [[DEOPT3:%.*]], !prof !0
|
|
; CHECK: deopt3:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET3]]
|
|
; CHECK: guarded2:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED2]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%vol = load volatile i32, i32* @G
|
|
%unknown = icmp eq i32 %vol, 0
|
|
br i1 %unknown, label %guarded2, label %deopt3, !prof !0
|
|
|
|
deopt3:
|
|
call void @unknown()
|
|
%deoptret3 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret3
|
|
|
|
guarded2:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded2 ]
|
|
ret i32 %result
|
|
}
|
|
|
|
|
|
define i32 @test_unanalyzeable_latch(i32* %array, i32 %length, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @test_unanalyzeable_latch(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
; CHECK-NEXT: br i1 [[WITHIN_BOUNDS]], label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, i32* @G, align 4
|
|
; CHECK-NEXT: [[UNKNOWN:%.*]] = icmp eq i32 [[VOL]], 0
|
|
; CHECK-NEXT: br i1 [[UNKNOWN]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%vol = load volatile i32, i32* @G
|
|
%unknown = icmp eq i32 %vol, 0
|
|
br i1 %unknown, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
|
|
define i32 @provably_taken(i32* %array, i1 %cond_0) {
|
|
; CHECK-LABEL: @provably_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 false
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP1]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], 198
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], 200
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, 198
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, 200
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
define i32 @provably_not_taken(i32* %array, i1 %cond_0) {
|
|
; CHECK-LABEL: @provably_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 true
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP1]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], 205
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], 200
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, 205
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, 200
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
|
|
;; Unswitch likes to produce some ugly exit blocks without simplifications
|
|
;; being applied. Make sure we can handle that form.
|
|
define i32 @unswitch_exit_form(i32* %array, i32 %length, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @unswitch_exit_form(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP3]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt.loopexit:
|
|
; CHECK-NEXT: br label [[DEOPT]]
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 1, [[DEOPT_LOOPEXIT:%.*]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: br label [[ACTUAL_DEOPT:%.*]]
|
|
; CHECK: actual_deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[PHI]]) ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT_LOOPEXIT]], !prof !0
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
;; This is written to look like an unsimplified loop exit after unswitch
|
|
;; (i.e. phis, merge, and branch to actual block)
|
|
%phi = phi i32 [0, %entry], [1, %loop]
|
|
call void @unknown() ;; it's okay to skip possible throws
|
|
br label %actual_deopt
|
|
|
|
actual_deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %phi) ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt, !prof !0
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
define i32 @swapped_wb(i32* %array, i32 %length, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @swapped_wb(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDENABLE_COND]], [[TMP3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %widenable_cond, %cond_0
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
define i32 @trivial_wb(i32* %array, i32 %length, i32 %n) {
|
|
; CHECK-LABEL: @trivial_wb(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[TMP3]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
br i1 %widenable_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded ]
|
|
ret i32 %result
|
|
}
|
|
|
|
; TODO: Non-latch exits can still be predicated
|
|
; This is currently prevented by an overly restrictive profitability check.
|
|
define i32 @todo_unconditional_latch(i32* %array, i32 %length, i1 %cond_0) {
|
|
; CHECK-LABEL: @todo_unconditional_latch(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
; CHECK-NEXT: br i1 [[WITHIN_BOUNDS]], label [[GUARDED]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
br label %loop
|
|
}
|
|
|
|
|
|
; If we have a stray widenable branch in the loop, we should still be able to
|
|
; run. This can happen when unswitching's cost model avoids unswitching some
|
|
; branches.
|
|
define i32 @wb_in_loop(i32* %array, i32 %length, i32 %n, i1 %cond_0) {
|
|
; CHECK-LABEL: @wb_in_loop(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i32 [[LENGTH]], [[UMIN]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = freeze i1 [[TMP4]]
|
|
; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP3]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[TMP6]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[LOOP_PREHEADER:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: [[DEOPTRET:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED2:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED2]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET2]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS2:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: [[WB_COND:%.*]] = and i1 [[WITHIN_BOUNDS2]], true
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED2]], label [[DEOPT3:%.*]], !prof !0
|
|
; CHECK: deopt3:
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: [[DEOPTRET3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
; CHECK-NEXT: ret i32 [[DEOPTRET3]]
|
|
; CHECK: guarded2:
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: store i32 0, i32* [[ARRAY_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED2]] ]
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%wc2 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0
|
|
|
|
deopt:
|
|
%deoptret = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret
|
|
|
|
loop.preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%loop.acc = phi i32 [ %loop.acc.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
%i = phi i32 [ %i.next, %guarded2 ], [ 0, %loop.preheader ]
|
|
call void @unknown()
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
br i1 %within.bounds, label %guarded, label %deopt2, !prof !0
|
|
|
|
deopt2:
|
|
call void @unknown()
|
|
%deoptret2 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret2
|
|
|
|
guarded:
|
|
call void @unknown()
|
|
%within.bounds2 = icmp ult i32 %i, %length
|
|
%wb_cond = and i1 %within.bounds2, %wc2
|
|
br i1 %wb_cond, label %guarded2, label %deopt3, !prof !0
|
|
|
|
deopt3:
|
|
call void @unknown()
|
|
%deoptret3 = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
|
|
ret i32 %deoptret3
|
|
|
|
guarded2:
|
|
%i.i64 = zext i32 %i to i64
|
|
%array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
|
|
%array.i = load i32, i32* %array.i.ptr, align 4
|
|
store i32 0, i32* %array.i.ptr
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
%i.next = add nuw i32 %i, 1
|
|
%continue = icmp ult i32 %i.next, %n
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32 [ %loop.acc.next, %guarded2 ]
|
|
ret i32 %result
|
|
}
|
|
|
|
|
|
|
|
declare void @unknown()
|
|
|
|
declare i1 @llvm.experimental.widenable.condition()
|
|
declare i32 @llvm.experimental.deoptimize.i32(...)
|
|
|
|
!0 = !{!"branch_weights", i32 1048576, i32 1}
|
|
!1 = !{i32 1, i32 -2147483648}
|
|
!2 = !{i32 0, i32 50}
|