
LSR uses SCEVExpander to generate induction formulas. The expander internally tries to reuse existing IR expressions. To do that, it needs to strip any poison generating flags (nsw, nuw, exact, nneg, etc..) which may not be valid for the newly added users. This is conservatively correct, but has the effect that LSR will strip nneg flags on zext instructions involved in trip counts in loop preheaders. To avoid this, this patch adjusts the expanded to reinfer the flags on the CSE candidate if legal for all possible users. This should fix the regression reported in https://github.com/llvm/llvm-project/issues/71200. This should arguably be done inside canReuseInstruction instead, but doing it outside is more conservative compile time wise. Both canReuseInstruction and isGuaranteedNotToBePoison walk operand lists, so right now we are performing work which is roughly O(N^2) in the size of the operand graph. We should fix that before making the per operand step more expensive. My tenative plan is to land this, and then rework the code to sink the logic into more core interfaces.
2016 lines
89 KiB
LLVM
2016 lines
89 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -S -passes=loop-predication < %s 2>&1 | FileCheck %s
|
|
; RUN: opt -S -passes='require<scalar-evolution>,loop-mssa(loop-predication)' -verify-memoryssa < %s 2>&1 | FileCheck %s
|
|
|
|
declare void @llvm.experimental.guard(i1, ...)
|
|
|
|
define i32 @unsigned_loop_0_to_n_ult_check(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ugt i32 [[LENGTH]], [[I]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %array, ptr %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, ptr [[LENGTH_PTR:%.*]], align 4, !range [[RNG0:![0-9]+]]
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 [[N]], [[LENGTH]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 true, [[TMP0]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[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: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP4:%.*]] = freeze i1 [[TMP3]]
|
|
; 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 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP4:%.*]] = freeze i1 [[TMP3]]
|
|
; 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: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I_NEXT]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP4:%.*]] = freeze i1 [[TMP3]]
|
|
; 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_OFFSET:%.*]] = add i32 [[I]], 1
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I_OFFSET]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[I_OFFSET:%.*]] = add i32 [[I]], 1
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I_OFFSET]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 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 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP5:%.*]] = freeze i1 [[TMP4]]
|
|
; 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: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[J]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP5]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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:%.*]] = freeze i1 [[TMP2]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[N]], [[LENGTH_1:%.*]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 0, [[LENGTH_1]]
|
|
; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP4]]
|
|
; CHECK-NEXT: [[TMP7:%.*]] = freeze i1 [[TMP6]]
|
|
; CHECK-NEXT: [[TMP8:%.*]] = and i1 [[TMP3]], [[TMP7]]
|
|
; 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_1:%.*]] = icmp ult i32 [[I]], [[LENGTH_1]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS_2:%.*]] = icmp ult i32 [[I]], [[LENGTH_2]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = and i1 [[WITHIN_BOUNDS_1]], [[WITHIN_BOUNDS_2]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP8]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[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, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_2_I:%.*]] = load i32, ptr [[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]]
|
|
;
|
|
ptr %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, ptr %array.1, i64 %i.i64
|
|
%array.1.i = load i32, ptr %array.1.i.ptr, align 4
|
|
%loop.acc.1 = add i32 %loop.acc, %array.1.i
|
|
|
|
%array.2.i.ptr = getelementptr inbounds i32, ptr %array.2, i64 %i.i64
|
|
%array.2.i = load i32, ptr %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(ptr %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:%.*]] = freeze i1 [[TMP2]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[N]], [[LENGTH_2:%.*]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 0, [[LENGTH_2]]
|
|
; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP4]]
|
|
; CHECK-NEXT: [[TMP7:%.*]] = freeze i1 [[TMP6]]
|
|
; CHECK-NEXT: [[TMP8:%.*]] = icmp ule i32 [[N]], [[LENGTH_1:%.*]]
|
|
; CHECK-NEXT: [[TMP9:%.*]] = icmp ult i32 0, [[LENGTH_1]]
|
|
; CHECK-NEXT: [[TMP10:%.*]] = and i1 [[TMP9]], [[TMP8]]
|
|
; CHECK-NEXT: [[TMP11:%.*]] = freeze i1 [[TMP10]]
|
|
; CHECK-NEXT: [[TMP12:%.*]] = and i1 [[TMP3]], [[TMP7]]
|
|
; CHECK-NEXT: [[TMP13:%.*]] = and i1 [[TMP12]], [[TMP11]]
|
|
; 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_1:%.*]] = icmp ult i32 [[I]], [[LENGTH_1]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS_2:%.*]] = icmp ult i32 [[I]], [[LENGTH_2]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS_3:%.*]] = icmp ult i32 [[I]], [[LENGTH_3]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS_1_AND_2:%.*]] = and i1 [[WITHIN_BOUNDS_1]], [[WITHIN_BOUNDS_2]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = and i1 [[WITHIN_BOUNDS_1_AND_2]], [[WITHIN_BOUNDS_3]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP13]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[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, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_2_I:%.*]] = load i32, ptr [[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, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[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]]
|
|
;
|
|
ptr %array.2, i32 %length.2,
|
|
ptr %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, ptr %array.1, i64 %i.i64
|
|
%array.1.i = load i32, ptr %array.1.i.ptr, align 4
|
|
%loop.acc.1 = add i32 %loop.acc, %array.1.i
|
|
|
|
%array.2.i.ptr = getelementptr inbounds i32, ptr %array.2, i64 %i.i64
|
|
%array.2.i = load i32, ptr %array.2.i.ptr, align 4
|
|
%loop.acc.2 = add i32 %loop.acc.1, %array.2.i
|
|
|
|
%array.3.i.ptr = getelementptr inbounds i32, ptr %array.3, i64 %i.i64
|
|
%array.3.i = load i32, ptr %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(ptr %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:%.*]] = freeze i1 [[TMP2]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[N]], [[LENGTH_2:%.*]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 0, [[LENGTH_2]]
|
|
; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP4]]
|
|
; CHECK-NEXT: [[TMP7:%.*]] = freeze i1 [[TMP6]]
|
|
; CHECK-NEXT: [[TMP8:%.*]] = icmp ule i32 [[N]], [[LENGTH_3:%.*]]
|
|
; CHECK-NEXT: [[TMP9:%.*]] = icmp ult i32 0, [[LENGTH_3]]
|
|
; CHECK-NEXT: [[TMP10:%.*]] = and i1 [[TMP9]], [[TMP8]]
|
|
; CHECK-NEXT: [[TMP11:%.*]] = freeze i1 [[TMP10]]
|
|
; 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_1:%.*]] = icmp ult i32 [[I]], [[LENGTH_1]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS_1]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS_2:%.*]] = icmp ult i32 [[I]], [[LENGTH_2]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP7]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS_2]])
|
|
; CHECK-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_2_I:%.*]] = load i32, ptr [[ARRAY_2_I_PTR]], align 4
|
|
; CHECK-NEXT: [[LOOP_ACC_2:%.*]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS_3:%.*]] = icmp ult i32 [[I]], [[LENGTH_3]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP11]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS_3]])
|
|
; CHECK-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[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]]
|
|
;
|
|
ptr %array.2, i32 %length.2,
|
|
ptr %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, ptr %array.1, i64 %i.i64
|
|
%array.1.i = load i32, ptr %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, ptr %array.2, i64 %i.i64
|
|
%array.2.i = load i32, ptr %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, ptr %array.3, i64 %i.i64
|
|
%array.3.i = load i32, ptr %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(ptr %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: [[TMP3:%.*]] = freeze i1 [[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]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: [[UNRELATED_COND:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
|
|
; CHECK-NEXT: [[GUARD_COND:%.*]] = and i1 [[WITHIN_BOUNDS]], [[UNRELATED_COND]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = and i1 [[UNRELATED_COND]], [[TMP3]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[GUARD_COND]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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: [[TMP4:%.*]] = freeze i1 [[TMP3]]
|
|
; 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:%.*]] = zext i16 [[LENGTH_I16]] to i32
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %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:%.*]]
|
|
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH_UDIV]]
|
|
; 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: [[TMP3:%.*]] = freeze i1 [[TMP2]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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(ptr %array, ptr %length.ptr) {
|
|
; CHECK-LABEL: @provably_taken(
|
|
; CHECK-NEXT: loop.preheader:
|
|
; CHECK-NEXT: [[LENGTH:%.*]] = load i32, ptr [[LENGTH_PTR:%.*]], align 4, !range [[RNG1:![0-9]+]]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], false
|
|
; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[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: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
|
|
; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
|
|
; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[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, ptr %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, ptr %array, i64 %i.i64
|
|
%array.i = load i32, ptr %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
|
|
}
|
|
|
|
; NE Check (as produced by LFTR) where we can prove Start < End via simple
|
|
; instruction analysis
|
|
define i32 @ne_latch_zext(ptr %array, i32 %length, i16 %n16) {
|
|
; CHECK-LABEL: @ne_latch_zext(
|
|
; CHECK-NEXT: loop.preheader:
|
|
; CHECK-NEXT: [[N:%.*]] = zext i16 [[N16:%.*]] to i32
|
|
; CHECK-NEXT: [[NPLUS1:%.*]] = add nuw nsw i32 [[N]], 1
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[NPLUS1]], [[LENGTH:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = freeze i1 [[TMP2]]
|
|
; 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 [[TMP3]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[NPLUS1]]
|
|
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
loop.preheader:
|
|
%n = zext i16 %n16 to i32
|
|
%nplus1 = add nsw nuw i32 %n, 1
|
|
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 nsw nuw i32 %i, 1
|
|
%continue = icmp ne i32 %i.next, %nplus1
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
; Same as previous, but with a pre-increment test since this is easier to match
|
|
define i32 @ne_latch_zext_preinc(ptr %array, i32 %length, i16 %n16) {
|
|
; CHECK-LABEL: @ne_latch_zext_preinc(
|
|
; CHECK-NEXT: loop.preheader:
|
|
; CHECK-NEXT: [[N:%.*]] = zext i16 [[N16:%.*]] to i32
|
|
; 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: [[TMP4:%.*]] = freeze i1 [[TMP3]]
|
|
; 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 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; 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
|
|
}
|
|
|
|
; 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(ptr %array, i32 %length, i32 %n) {
|
|
; CHECK-LABEL: @ne_latch_dom_check(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
|
|
; CHECK-NEXT: [[NPLUS1:%.*]] = add nuw i32 [[N]], 1
|
|
; 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"() ]
|
|
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[NPLUS1]]
|
|
; 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
|
|
%nplus1 = add nuw i32 %n, 1
|
|
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 nsw nuw i32 %i, 1
|
|
%continue = icmp ne i32 %i.next, %nplus1
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
; Same as previous, but easier to match
|
|
define i32 @ne_latch_dom_check_preinc(ptr %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:
|
|
; 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: [[TMP4:%.*]] = freeze i1 [[TMP3]]
|
|
; 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 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; 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
|
|
}
|
|
|
|
; Same as previous, except swapped br/cmp
|
|
define i32 @eq_latch_dom_check_preinc(ptr %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: [[TMP4:%.*]] = freeze i1 [[TMP3]]
|
|
; 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 [[TMP4]], i32 9) [ "deopt"() ]
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
|
|
; 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
|
|
}
|
|
|
|
|
|
; 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(ptr %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
|
|
; 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 i32 %i, 3
|
|
%continue = icmp ne i32 %i, %n
|
|
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(ptr %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
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], 400
|
|
; 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
|
|
%continue = icmp ne i32 %i, 400
|
|
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(ptr %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
|
|
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], 0
|
|
; 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
|
|
%continue = icmp ne i32 %i, 0
|
|
br i1 %continue, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
; 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(ptr %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, ptr [[A:%.*]], align 4
|
|
; 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, ptr %a
|
|
%i.next = add i32 %i, 1
|
|
br label %loop
|
|
}
|