2019-04-17 12:52:47 +08:00
|
|
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
|
|
; RUN: opt -S -loop-predication < %s 2>&1 | FileCheck %s
|
|
|
|
; RUN: opt -S -passes='require<scalar-evolution>,loop(loop-predication)' < %s 2>&1 | FileCheck %s
|
|
|
|
|
|
|
|
declare void @llvm.experimental.guard(i1, ...)
|
|
|
|
|
|
|
|
define i32 @unsigned_loop_0_to_n_ult_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @unsigned_loop_0_to_n_ult_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @unsigned_loop_0_to_n_ule_latch_ult_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @unsigned_loop_0_to_n_ule_latch_ult_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ule i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp ule i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @unsigned_loop_0_to_n_ugt_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @unsigned_loop_0_to_n_ugt_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ugt i32 %length, %i
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_ult_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_ult_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_ult_check_length_range_known(i32* %array, i32* %length.ptr, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_ult_check_length_range_known(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], !range !0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 [[N]], [[LENGTH]]
|
2019-07-08 06:12:01 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 true, [[TMP0]]
|
2019-04-17 12:52:47 +08:00
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
2019-07-08 06:12:01 +08:00
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP1]], i32 9) [ "deopt"() ]
|
2019-04-17 12:52:47 +08:00
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
%length = load i32, i32* %length.ptr, !range !{i32 1, i32 2147483648}
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_inverse_latch_predicate(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_inverse_latch_predicate(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp sgt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp sgt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %exit, label %loop
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_sle_latch_ult_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_sle_latch_ult_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp sle i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp sle i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_preincrement_latch_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_preincrement_latch_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -1
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp sle i32 [[N]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_preincrement_latch_check_postincrement_guard_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_preincrement_latch_check_postincrement_guard_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -2
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp sle i32 [[N]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 1, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
|
|
|
|
%i.next = add i32 %i, 1
|
|
|
|
%within.bounds = icmp ult i32 %i.next, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%continue = icmp slt i32 %i, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_sle_latch_offset_ult_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_sle_latch_offset_ult_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -1
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[N]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 1, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp sle i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i.offset = add i32 %i, 1
|
|
|
|
%within.bounds = icmp ult i32 %i.offset, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add i32 %i, 1
|
|
|
|
%continue = icmp sle i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_offset_sle_latch_offset_ult_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_offset_sle_latch_offset_ult_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 1, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[I_NEXT_OFFSET:%.*]] = add i32 [[I_NEXT]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp sle i32 [[I_NEXT_OFFSET]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i.offset = add i32 %i, 1
|
|
|
|
%within.bounds = icmp ult i32 %i.offset, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add i32 %i, 1
|
|
|
|
%i.next.offset = add i32 %i.next, 1
|
|
|
|
%continue = icmp sle i32 %i.next.offset, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @unsupported_latch_pred_loop_0_to_n(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @unsupported_latch_pred_loop_0_to_n(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nsw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nsw i32 %i, 1
|
|
|
|
%continue = icmp ne i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_unsupported_iv_step(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_unsupported_iv_step(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nsw i32 [[I]], 2
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nsw i32 %i, 2
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_equal_iv_range_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_equal_iv_range_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[J_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[J_NEXT]] = add nsw i32 [[J]], 1
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nsw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%j = phi i32 [ %j.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
|
|
|
|
%within.bounds = icmp ult i32 %j, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%j.next = add nsw i32 %j, 1
|
|
|
|
%i.next = add nsw i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_start_to_n_offset_iv_range_check(i32* %array, i32 %start.i,
|
|
|
|
; CHECK-LABEL: @signed_loop_start_to_n_offset_iv_range_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], [[START_I:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[TMP0]], [[START_J:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp sle i32 [[N]], [[TMP1]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[START_J]], [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP4:%.*]] = and i1 [[TMP3]], [[TMP2]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ [[START_I]], [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[J_NEXT:%.*]], [[LOOP]] ], [ [[START_J]], [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP4]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], 1
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
i32 %start.j, i32 %length,
|
|
|
|
i32 %n) {
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ %start.i, %loop.preheader ]
|
|
|
|
%j = phi i32 [ %j.next, %loop ], [ %start.j, %loop.preheader ]
|
|
|
|
|
|
|
|
%within.bounds = icmp ult i32 %j, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%j.next = add i32 %j, 1
|
|
|
|
%i.next = add i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_different_iv_types(i32* %array, i16 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_different_iv_types(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[J:%.*]] = phi i16 [ [[J_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i16 [[J]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[J_NEXT]] = add i16 [[J]], 1
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%j = phi i16 [ %j.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
|
|
|
|
%within.bounds = icmp ult i16 %j, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%j.next = add i16 %j, 1
|
|
|
|
%i.next = add i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_0_to_n_different_iv_strides(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_0_to_n_different_iv_strides(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[J_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[J]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[J_NEXT]] = add nsw i32 [[J]], 2
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nsw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%j = phi i32 [ %j.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
|
|
|
|
%within.bounds = icmp ult i32 %j, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%j.next = add nsw i32 %j, 2
|
|
|
|
%i.next = add nsw i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @two_range_checks(i32* %array.1, i32 %length.1,
|
|
|
|
; CHECK-LABEL: @two_range_checks(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH_2:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH_2]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp ule i32 [[N]], [[LENGTH_1:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 0, [[LENGTH_1]]
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP3]]
|
|
|
|
; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP2]], [[TMP5]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP6]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
|
|
; CHECK-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_2:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_2_I:%.*]] = load i32, i32* [[ARRAY_2_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
i32* %array.2, i32 %length.2, i32 %n) {
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds.1 = icmp ult i32 %i, %length.1
|
|
|
|
%within.bounds.2 = icmp ult i32 %i, %length.2
|
|
|
|
%within.bounds = and i1 %within.bounds.1, %within.bounds.2
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.i64 = zext i32 %i to i64
|
|
|
|
%array.1.i.ptr = getelementptr inbounds i32, i32* %array.1, i64 %i.i64
|
|
|
|
%array.1.i = load i32, i32* %array.1.i.ptr, align 4
|
|
|
|
%loop.acc.1 = add i32 %loop.acc, %array.1.i
|
|
|
|
|
|
|
|
%array.2.i.ptr = getelementptr inbounds i32, i32* %array.2, i64 %i.i64
|
|
|
|
%array.2.i = load i32, i32* %array.2.i.ptr, align 4
|
|
|
|
%loop.acc.next = add i32 %loop.acc.1, %array.2.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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @three_range_checks(i32* %array.1, i32 %length.1,
|
|
|
|
; CHECK-LABEL: @three_range_checks(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH_3:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH_3]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp ule i32 [[N]], [[LENGTH_2:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 0, [[LENGTH_2]]
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP3]]
|
|
|
|
; CHECK-NEXT: [[TMP6:%.*]] = icmp ule i32 [[N]], [[LENGTH_1:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 0, [[LENGTH_1]]
|
|
|
|
; CHECK-NEXT: [[TMP8:%.*]] = and i1 [[TMP7]], [[TMP6]]
|
|
|
|
; CHECK-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP5]]
|
|
|
|
; CHECK-NEXT: [[TMP10:%.*]] = and i1 [[TMP9]], [[TMP8]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP10]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
|
|
; CHECK-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_2:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_2_I:%.*]] = load i32, i32* [[ARRAY_2_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_2:%.*]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_2]], [[ARRAY_3_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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
i32* %array.2, i32 %length.2,
|
|
|
|
i32* %array.3, i32 %length.3, i32 %n) {
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds.1 = icmp ult i32 %i, %length.1
|
|
|
|
%within.bounds.2 = icmp ult i32 %i, %length.2
|
|
|
|
%within.bounds.3 = icmp ult i32 %i, %length.3
|
|
|
|
%within.bounds.1.and.2 = and i1 %within.bounds.1, %within.bounds.2
|
|
|
|
%within.bounds = and i1 %within.bounds.1.and.2, %within.bounds.3
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.i64 = zext i32 %i to i64
|
|
|
|
%array.1.i.ptr = getelementptr inbounds i32, i32* %array.1, i64 %i.i64
|
|
|
|
%array.1.i = load i32, i32* %array.1.i.ptr, align 4
|
|
|
|
%loop.acc.1 = add i32 %loop.acc, %array.1.i
|
|
|
|
|
|
|
|
%array.2.i.ptr = getelementptr inbounds i32, i32* %array.2, i64 %i.i64
|
|
|
|
%array.2.i = load i32, i32* %array.2.i.ptr, align 4
|
|
|
|
%loop.acc.2 = add i32 %loop.acc.1, %array.2.i
|
|
|
|
|
|
|
|
%array.3.i.ptr = getelementptr inbounds i32, i32* %array.3, i64 %i.i64
|
|
|
|
%array.3.i = load i32, i32* %array.3.i.ptr, align 4
|
|
|
|
%loop.acc.next = add i32 %loop.acc.2, %array.3.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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @three_guards(i32* %array.1, i32 %length.1,
|
|
|
|
; CHECK-LABEL: @three_guards(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH_1:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH_1]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp ule i32 [[N]], [[LENGTH_2:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 0, [[LENGTH_2]]
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP3]]
|
|
|
|
; CHECK-NEXT: [[TMP6:%.*]] = icmp ule i32 [[N]], [[LENGTH_3:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 0, [[LENGTH_3]]
|
|
|
|
; CHECK-NEXT: [[TMP8:%.*]] = and i1 [[TMP7]], [[TMP6]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
|
|
; CHECK-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP5]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_2:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_2_I:%.*]] = load i32, i32* [[ARRAY_2_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_2:%.*]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP8]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
|
|
|
|
; CHECK-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_2]], [[ARRAY_3_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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
i32* %array.2, i32 %length.2,
|
|
|
|
i32* %array.3, i32 %length.3, i32 %n) {
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
|
|
|
|
%within.bounds.1 = icmp ult i32 %i, %length.1
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds.1, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.i64 = zext i32 %i to i64
|
|
|
|
%array.1.i.ptr = getelementptr inbounds i32, i32* %array.1, i64 %i.i64
|
|
|
|
%array.1.i = load i32, i32* %array.1.i.ptr, align 4
|
|
|
|
%loop.acc.1 = add i32 %loop.acc, %array.1.i
|
|
|
|
|
|
|
|
%within.bounds.2 = icmp ult i32 %i, %length.2
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds.2, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%array.2.i.ptr = getelementptr inbounds i32, i32* %array.2, i64 %i.i64
|
|
|
|
%array.2.i = load i32, i32* %array.2.i.ptr, align 4
|
|
|
|
%loop.acc.2 = add i32 %loop.acc.1, %array.2.i
|
|
|
|
|
|
|
|
%within.bounds.3 = icmp ult i32 %i, %length.3
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds.3, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%array.3.i.ptr = getelementptr inbounds i32, i32* %array.3, i64 %i.i64
|
|
|
|
%array.3.i = load i32, i32* %array.3.i.ptr, align 4
|
|
|
|
%loop.acc.next = add i32 %loop.acc.2, %array.3.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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @unsigned_loop_0_to_n_unrelated_condition(i32* %array, i32 %length, i32 %n, i32 %x) {
|
|
|
|
; CHECK-LABEL: @unsigned_loop_0_to_n_unrelated_condition(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[UNRELATED_COND:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[UNRELATED_COND]], [[TMP2]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
%unrelated.cond = icmp ult i32 %x, %length
|
|
|
|
%guard.cond = and i1 %within.bounds, %unrelated.cond
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %guard.cond, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
; Don't change the guard condition if there were no widened subconditions
|
|
|
|
define i32 @test_no_widened_conditions(i32* %array, i32 %length, i32 %n, i32 %x1, i32 %x2, i32 %x3) {
|
|
|
|
; CHECK-LABEL: @test_no_widened_conditions(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[UNRELATED_COND_1:%.*]] = icmp eq i32 [[X1:%.*]], [[I]]
|
|
|
|
; CHECK-NEXT: [[UNRELATED_COND_2:%.*]] = icmp eq i32 [[X2:%.*]], [[I]]
|
|
|
|
; CHECK-NEXT: [[UNRELATED_COND_3:%.*]] = icmp eq i32 [[X3:%.*]], [[I]]
|
|
|
|
; CHECK-NEXT: [[UNRELATED_COND_AND_1:%.*]] = and i1 [[UNRELATED_COND_1]], [[UNRELATED_COND_2]]
|
|
|
|
; CHECK-NEXT: [[GUARD_COND:%.*]] = and i1 [[UNRELATED_COND_AND_1]], [[UNRELATED_COND_3]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[GUARD_COND]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%unrelated.cond.1 = icmp eq i32 %x1, %i
|
|
|
|
%unrelated.cond.2 = icmp eq i32 %x2, %i
|
|
|
|
%unrelated.cond.3 = icmp eq i32 %x3, %i
|
|
|
|
%unrelated.cond.and.1 = and i1 %unrelated.cond.1, %unrelated.cond.2
|
|
|
|
%guard.cond = and i1 %unrelated.cond.and.1, %unrelated.cond.3
|
|
|
|
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %guard.cond, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_start_to_n_loop_variant_bound(i32* %array, i32 %x, i32 %start, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_start_to_n_loop_variant_bound(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ [[START:%.*]], [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[BOUND:%.*]] = add i32 [[I]], [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[BOUND]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nsw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ %start, %loop.preheader ]
|
|
|
|
%bound = add i32 %i, %x
|
|
|
|
%within.bounds = icmp ult i32 %i, %bound
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nsw i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @signed_loop_start_to_n_non_monotonic_predicate(i32* %array, i32 %x, i32 %start, i32 %n) {
|
|
|
|
; CHECK-LABEL: @signed_loop_start_to_n_non_monotonic_predicate(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ [[START:%.*]], [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp eq i32 [[I]], [[X:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[GUARD_COND]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nsw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ %start, %loop.preheader ]
|
|
|
|
%guard.cond = icmp eq i32 %i, %x
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %guard.cond, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nsw i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @unsigned_loop_0_to_n_hoist_length(i32* %array, i16 %length.i16, i32 %n) {
|
|
|
|
; CHECK-LABEL: @unsigned_loop_0_to_n_hoist_length(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = zext i16 [[LENGTH_I16:%.*]] to i32
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i32 [[N]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 0, [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%length = zext i16 %length.i16 to i32
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @unsigned_loop_0_to_n_cant_hoist_length(i32* %array, i32 %length, i32 %divider, i32 %n) {
|
|
|
|
; CHECK-LABEL: @unsigned_loop_0_to_n_cant_hoist_length(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[LENGTH_UDIV:%.*]] = udiv i32 [[LENGTH:%.*]], [[DIVIDER:%.*]]
|
[LoopPredication] Allow predication of loop invariant computations (within the loop)
The purpose of this patch is to eliminate a pass ordering dependence between LoopPredication and LICM. To understand the purpose, consider the following snippet of code inside some loop 'L' with IV 'i'
A = _a.length;
guard (i < A)
a = _a[i]
B = _b.length;
guard (i < B);
b = _b[i];
...
Z = _z.length;
guard (i < Z)
z = _z[i]
accum += a + b + ... + z;
Today, we need LICM to hoist the length loads, LoopPredication to make the guards loop invariant, and TrivialUnswitch to eliminate the loop invariant guard to establish must execute for the next length load. Today, if we can't prove speculation safety, we'd have to iterate these three passes 26 times to reduce this example down to the minimal form.
Using the fact that the array lengths are known to be invariant, we can short circuit this iteration. By forming the loop invariant form of all the guards at once, we remove the need for LoopPredication from the iterative cycle. At the moment, we'd still have to iterate LICM and TrivialUnswitch; we'll leave that part for later.
As a secondary benefit, this allows LoopPred to expose peeling oppurtunities in a much more obvious manner. See the udiv test changes as an example. If the udiv was not hoistable (i.e. we couldn't prove speculation safety) this would be an example where peeling becomes obviously profitable whereas it wasn't before.
A couple of subtleties in the implementation:
- SCEV's isSafeToExpand guarantees speculation safety (i.e. let's us expand at a new point). It is not a precondition for expansion if we know the SCEV corresponds to a Value which dominates the requested expansion point.
- SCEV's isLoopInvariant returns true for expressions which compute the same value across all iterations executed, regardless of where the original Value is located. (i.e. it can be in the loop) This implies we have a speculation burden to prove before expanding them outside loops.
- invariant_loads and AA->pointsToConstantMemory are two cases that SCEV currently does not handle, but meets the SCEV definition of invariance. I plan to sink this part into SCEV once this has baked for a bit.
Differential Revision: https://reviews.llvm.org/D60093
llvm-svn: 358684
2019-04-19 00:33:17 +08:00
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH_UDIV]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH_UDIV]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
2019-04-17 12:52:47 +08:00
|
|
|
; 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: [[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_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp eq i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%length.udiv = udiv i32 %length, %divider
|
|
|
|
%within.bounds = icmp ult i32 %i, %length.udiv
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%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 [ 0, %entry ], [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
; This is a case where the length information tells us that the guard
|
|
|
|
; must trigger on some iteration.
|
|
|
|
define i32 @provably_taken(i32* %array, i32* %length.ptr) {
|
|
|
|
; CHECK-LABEL: @provably_taken(
|
|
|
|
; CHECK-NEXT: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], !range !1
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], false
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP1]], i32 9) [ "deopt"() ]
|
|
|
|
; 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: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp slt i32 [[I_NEXT]], 200
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
|
|
;
|
|
|
|
loop.preheader:
|
|
|
|
%length = load i32, i32* %length.ptr, !range !{i32 0, i32 50}
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%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
|
|
|
|
%loop.acc.next = add i32 %loop.acc, %array.i
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp slt i32 %i.next, 200
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
%result = phi i32 [ %loop.acc.next, %loop ]
|
|
|
|
ret i32 %result
|
|
|
|
}
|
2019-06-01 00:54:38 +08:00
|
|
|
|
|
|
|
; NE Check (as produced by LFTR) where we can prove Start < End via simple
|
|
|
|
; instruction analysis
|
|
|
|
define i32 @ne_latch_zext(i32* %array, i32 %length, i16 %n16) {
|
|
|
|
; CHECK-LABEL: @ne_latch_zext(
|
|
|
|
; CHECK-NEXT: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[N:%.*]] = zext i16 [[N16:%.*]] to i32
|
2019-06-01 06:22:29 +08:00
|
|
|
; CHECK-NEXT: [[NPLUS1:%.*]] = add nuw nsw i32 [[N]], 1
|
[LoopPred] Handle a subset of NE comparison based latches
At the moment, LoopPredication completely bails out if it sees a latch of the form:
%cmp = icmp ne %iv, %N
br i1 %cmp, label %loop, label %exit
OR
%cmp = icmp ne %iv.next, %NPlus1
br i1 %cmp, label %loop, label %exit
This is unfortunate since this is exactly the form that LFTR likes to produce. So, go ahead and recognize simple cases where we can.
For pre-increment loops, we leverage the fact that LFTR likes canonical counters (i.e. those starting at zero) and a (presumed) range fact on RHS to discharge the check trivially.
For post-increment forms, the key insight is in remembering that LFTR had to insert a (N+1) for the RHS. CVP can hopefully prove that add nsw/nuw (if there's appropriate range on N to start with). This leaves us both with the post-inc IV and the RHS involving an nsw/nuw add, and SCEV can discharge that with no problem.
This does still need to be extended to handle non-one steps, or other harder patterns of variable (but range restricted) starting values. That'll come later.
Differential Revision: https://reviews.llvm.org/D62748
llvm-svn: 362282
2019-06-01 08:31:58 +08:00
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[NPLUS1]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
2019-06-01 00:54:38 +08:00
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
|
[LoopPred] Handle a subset of NE comparison based latches
At the moment, LoopPredication completely bails out if it sees a latch of the form:
%cmp = icmp ne %iv, %N
br i1 %cmp, label %loop, label %exit
OR
%cmp = icmp ne %iv.next, %NPlus1
br i1 %cmp, label %loop, label %exit
This is unfortunate since this is exactly the form that LFTR likes to produce. So, go ahead and recognize simple cases where we can.
For pre-increment loops, we leverage the fact that LFTR likes canonical counters (i.e. those starting at zero) and a (presumed) range fact on RHS to discharge the check trivially.
For post-increment forms, the key insight is in remembering that LFTR had to insert a (N+1) for the RHS. CVP can hopefully prove that add nsw/nuw (if there's appropriate range on N to start with). This leaves us both with the post-inc IV and the RHS involving an nsw/nuw add, and SCEV can discharge that with no problem.
This does still need to be extended to handle non-one steps, or other harder patterns of variable (but range restricted) starting values. That'll come later.
Differential Revision: https://reviews.llvm.org/D62748
llvm-svn: 362282
2019-06-01 08:31:58 +08:00
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
2019-06-01 06:22:29 +08:00
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[NPLUS1]]
|
2019-06-01 00:54:38 +08:00
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
loop.preheader:
|
|
|
|
%n = zext i16 %n16 to i32
|
2019-06-01 06:22:29 +08:00
|
|
|
%nplus1 = add nsw nuw i32 %n, 1
|
2019-06-01 00:54:38 +08:00
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
2019-06-01 06:22:29 +08:00
|
|
|
%i.next = add nsw nuw i32 %i, 1
|
|
|
|
%continue = icmp ne i32 %i.next, %nplus1
|
2019-06-01 00:54:38 +08:00
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
2019-06-01 04:34:57 +08:00
|
|
|
; Same as previous, but with a pre-increment test since this is easier to match
|
|
|
|
define i32 @ne_latch_zext_preinc(i32* %array, i32 %length, i16 %n16) {
|
|
|
|
; CHECK-LABEL: @ne_latch_zext_preinc(
|
|
|
|
; CHECK-NEXT: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[N:%.*]] = zext i16 [[N16:%.*]] to i32
|
[LoopPred] Handle a subset of NE comparison based latches
At the moment, LoopPredication completely bails out if it sees a latch of the form:
%cmp = icmp ne %iv, %N
br i1 %cmp, label %loop, label %exit
OR
%cmp = icmp ne %iv.next, %NPlus1
br i1 %cmp, label %loop, label %exit
This is unfortunate since this is exactly the form that LFTR likes to produce. So, go ahead and recognize simple cases where we can.
For pre-increment loops, we leverage the fact that LFTR likes canonical counters (i.e. those starting at zero) and a (presumed) range fact on RHS to discharge the check trivially.
For post-increment forms, the key insight is in remembering that LFTR had to insert a (N+1) for the RHS. CVP can hopefully prove that add nsw/nuw (if there's appropriate range on N to start with). This leaves us both with the post-inc IV and the RHS involving an nsw/nuw add, and SCEV can discharge that with no problem.
This does still need to be extended to handle non-one steps, or other harder patterns of variable (but range restricted) starting values. That'll come later.
Differential Revision: https://reviews.llvm.org/D62748
llvm-svn: 362282
2019-06-01 08:31:58 +08:00
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -1
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i32 [[N]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
|
2019-06-01 04:34:57 +08:00
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
|
[LoopPred] Handle a subset of NE comparison based latches
At the moment, LoopPredication completely bails out if it sees a latch of the form:
%cmp = icmp ne %iv, %N
br i1 %cmp, label %loop, label %exit
OR
%cmp = icmp ne %iv.next, %NPlus1
br i1 %cmp, label %loop, label %exit
This is unfortunate since this is exactly the form that LFTR likes to produce. So, go ahead and recognize simple cases where we can.
For pre-increment loops, we leverage the fact that LFTR likes canonical counters (i.e. those starting at zero) and a (presumed) range fact on RHS to discharge the check trivially.
For post-increment forms, the key insight is in remembering that LFTR had to insert a (N+1) for the RHS. CVP can hopefully prove that add nsw/nuw (if there's appropriate range on N to start with). This leaves us both with the post-inc IV and the RHS involving an nsw/nuw add, and SCEV can discharge that with no problem.
This does still need to be extended to handle non-one steps, or other harder patterns of variable (but range restricted) starting values. That'll come later.
Differential Revision: https://reviews.llvm.org/D62748
llvm-svn: 362282
2019-06-01 08:31:58 +08:00
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
2019-06-01 04:34:57 +08:00
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
loop.preheader:
|
|
|
|
%n = zext i16 %n16 to i32
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp ne i32 %i, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
2019-06-01 00:54:38 +08:00
|
|
|
; NE Check (as produced by LFTR) where we can prove Start < End via the
|
|
|
|
; condition guarding the loop entry.
|
|
|
|
define i32 @ne_latch_dom_check(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @ne_latch_dom_check(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
2019-06-01 06:22:29 +08:00
|
|
|
; CHECK-NEXT: [[NPLUS1:%.*]] = add nuw i32 [[N]], 1
|
2019-06-01 00:54:38 +08:00
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
2019-06-01 06:22:29 +08:00
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[NPLUS1]]
|
2019-06-01 00:54:38 +08:00
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
2019-06-01 06:22:29 +08:00
|
|
|
%nplus1 = add nuw i32 %n, 1
|
2019-06-01 00:54:38 +08:00
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
2019-06-01 06:22:29 +08:00
|
|
|
%i.next = add nsw nuw i32 %i, 1
|
|
|
|
%continue = icmp ne i32 %i.next, %nplus1
|
2019-06-01 00:54:38 +08:00
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
2019-06-01 04:34:57 +08:00
|
|
|
; Same as previous, but easier to match
|
|
|
|
define i32 @ne_latch_dom_check_preinc(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @ne_latch_dom_check_preinc(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
[LoopPred] Handle a subset of NE comparison based latches
At the moment, LoopPredication completely bails out if it sees a latch of the form:
%cmp = icmp ne %iv, %N
br i1 %cmp, label %loop, label %exit
OR
%cmp = icmp ne %iv.next, %NPlus1
br i1 %cmp, label %loop, label %exit
This is unfortunate since this is exactly the form that LFTR likes to produce. So, go ahead and recognize simple cases where we can.
For pre-increment loops, we leverage the fact that LFTR likes canonical counters (i.e. those starting at zero) and a (presumed) range fact on RHS to discharge the check trivially.
For post-increment forms, the key insight is in remembering that LFTR had to insert a (N+1) for the RHS. CVP can hopefully prove that add nsw/nuw (if there's appropriate range on N to start with). This leaves us both with the post-inc IV and the RHS involving an nsw/nuw add, and SCEV can discharge that with no problem.
This does still need to be extended to handle non-one steps, or other harder patterns of variable (but range restricted) starting values. That'll come later.
Differential Revision: https://reviews.llvm.org/D62748
llvm-svn: 362282
2019-06-01 08:31:58 +08:00
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -1
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i32 [[N]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
|
2019-06-01 04:34:57 +08:00
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
[LoopPred] Handle a subset of NE comparison based latches
At the moment, LoopPredication completely bails out if it sees a latch of the form:
%cmp = icmp ne %iv, %N
br i1 %cmp, label %loop, label %exit
OR
%cmp = icmp ne %iv.next, %NPlus1
br i1 %cmp, label %loop, label %exit
This is unfortunate since this is exactly the form that LFTR likes to produce. So, go ahead and recognize simple cases where we can.
For pre-increment loops, we leverage the fact that LFTR likes canonical counters (i.e. those starting at zero) and a (presumed) range fact on RHS to discharge the check trivially.
For post-increment forms, the key insight is in remembering that LFTR had to insert a (N+1) for the RHS. CVP can hopefully prove that add nsw/nuw (if there's appropriate range on N to start with). This leaves us both with the post-inc IV and the RHS involving an nsw/nuw add, and SCEV can discharge that with no problem.
This does still need to be extended to handle non-one steps, or other harder patterns of variable (but range restricted) starting values. That'll come later.
Differential Revision: https://reviews.llvm.org/D62748
llvm-svn: 362282
2019-06-01 08:31:58 +08:00
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
2019-06-01 04:34:57 +08:00
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%continue = icmp ne i32 %i, %n
|
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
2019-07-09 09:27:45 +08:00
|
|
|
; Same as previous, except swapped br/cmp
|
|
|
|
define i32 @eq_latch_dom_check_preinc(i32* %array, i32 %length, i32 %n) {
|
|
|
|
; CHECK-LABEL: @eq_latch_dom_check_preinc(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
|
|
; CHECK: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -1
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i32 [[N]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[I]], [[N]]
|
|
|
|
; CHECK-NEXT: br i1 [[DONE]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%tmp5 = icmp sle i32 %n, 0
|
|
|
|
br i1 %tmp5, label %exit, label %loop.preheader
|
|
|
|
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 1
|
|
|
|
%done = icmp eq i32 %i, %n
|
|
|
|
br i1 %done, label %exit, label %loop
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
2019-06-01 04:34:57 +08:00
|
|
|
|
2019-06-01 00:54:38 +08:00
|
|
|
; NE latch - can't prove (end-start) mod step == 0 (i.e. might wrap
|
|
|
|
; around several times or even be infinite)
|
|
|
|
define i32 @neg_ne_latch_mod_step(i32* %array, i32 %length, i16 %n16) {
|
|
|
|
; CHECK-LABEL: @neg_ne_latch_mod_step(
|
|
|
|
; CHECK-NEXT: loop.preheader:
|
|
|
|
; CHECK-NEXT: [[N:%.*]] = zext i16 [[N16:%.*]] to i32
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 3
|
2019-06-01 04:34:57 +08:00
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], [[N]]
|
2019-06-01 00:54:38 +08:00
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
loop.preheader:
|
|
|
|
%n = zext i16 %n16 to i32
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.next = add i32 %i, 3
|
2019-06-01 04:34:57 +08:00
|
|
|
%continue = icmp ne i32 %i, %n
|
2019-06-01 00:54:38 +08:00
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
|
|
|
; NE latch - TODO: could prove (end-start) mod step == 0
|
|
|
|
define i32 @ne_latch_mod_step(i32* %array, i32 %length) {
|
|
|
|
; CHECK-LABEL: @ne_latch_mod_step(
|
|
|
|
; CHECK-NEXT: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 2
|
2019-06-01 04:34:57 +08:00
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], 400
|
2019-06-01 00:54:38 +08:00
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.next = add nuw i32 %i, 2
|
2019-06-01 04:34:57 +08:00
|
|
|
%continue = icmp ne i32 %i, 400
|
2019-06-01 00:54:38 +08:00
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
|
|
|
; NE Latch - but end > start so wraps around and not equivelent to a ult
|
|
|
|
define i32 @neg_ne_latch_swapped_order(i32* %array, i32 %length) {
|
|
|
|
; CHECK-LABEL: @neg_ne_latch_swapped_order(
|
|
|
|
; CHECK-NEXT: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 400, [[LOOP_PREHEADER:%.*]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
2019-06-01 04:34:57 +08:00
|
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], 0
|
2019-06-01 00:54:38 +08:00
|
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret i32 0
|
|
|
|
;
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 400, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
|
|
|
|
%i.next = add i32 %i, 1
|
2019-06-01 04:34:57 +08:00
|
|
|
%continue = icmp ne i32 %i, 0
|
2019-06-01 00:54:38 +08:00
|
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
|
2019-06-07 02:02:36 +08:00
|
|
|
; Negative test, make sure we don't crash on unconditional latches
|
|
|
|
; TODO: there's no reason we shouldn't be able to predicate the
|
|
|
|
; condition for an statically infinite loop.
|
|
|
|
define i32 @unconditional_latch(i32* %a, i32 %length) {
|
|
|
|
; CHECK-LABEL: @unconditional_latch(
|
|
|
|
; CHECK-NEXT: loop.preheader:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 400, [[LOOP_PREHEADER:%.*]] ]
|
|
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
|
|
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
|
|
|
|
; CHECK-NEXT: store volatile i32 0, i32* [[A:%.*]]
|
|
|
|
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
|
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
|
|
;
|
|
|
|
loop.preheader:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%i = phi i32 [ %i.next, %loop ], [ 400, %loop.preheader ]
|
|
|
|
%within.bounds = icmp ult i32 %i, %length
|
|
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
|
|
|
|
store volatile i32 0, i32* %a
|
|
|
|
%i.next = add i32 %i, 1
|
|
|
|
br label %loop
|
|
|
|
}
|