
When adding constraints for induction variables, if the step is not one, we need to make sure that (end-start) is a multiple of step, otherwise we might step over the end value. Currently this only supports one specific pattern for pointers, where the end is a gep of the start with an appropriate offset. Generalize this by using SCEV to check for multiples, which also makes this work for integer IVs.
286 lines
9.1 KiB
LLVM
286 lines
9.1 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
|
|
; RUN: opt -S -passes=constraint-elimination < %s | FileCheck %s
|
|
|
|
define void @multiple_pow2(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_pow2(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[END:%.*]] = shl i64 [[COUNT]], 2
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 4
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%end = shl i64 %count, 2
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %entry ]
|
|
%iv.next = add i64 %iv, 4
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @multiple_pow2_larger_than_needed(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_pow2_larger_than_needed(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[END:%.*]] = shl i64 [[COUNT]], 3
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 4
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%end = shl i64 %count, 3
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %entry ]
|
|
%iv.next = add i64 %iv, 4
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @multiple_pow2_too_small(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_pow2_too_small(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[END:%.*]] = shl i64 [[COUNT]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 4
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[CMP2_I_I:%.*]] = icmp ult i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP2_I_I]], label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%end = shl i64 %count, 1
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %entry ]
|
|
%iv.next = add i64 %iv, 4
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @multiple_pow2_start_offset(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_pow2_start_offset(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[END:%.*]] = shl i64 [[COUNT]], 2
|
|
; CHECK-NEXT: [[PRECOND:%.*]] = icmp ugt i64 [[END]], 4
|
|
; CHECK-NEXT: br i1 [[PRECOND]], label [[LOOP:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 4, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 4
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%end = shl i64 %count, 2
|
|
%precond = icmp ugt i64 %end, 4
|
|
br i1 %precond, label %loop, label %exit
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 4, %entry ]
|
|
%iv.next = add i64 %iv, 4
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @multiple_pow2_wrong_start_offset(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_pow2_wrong_start_offset(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[END:%.*]] = shl i64 [[COUNT]], 2
|
|
; CHECK-NEXT: [[PRECOND:%.*]] = icmp ugt i64 [[END]], 1
|
|
; CHECK-NEXT: br i1 [[PRECOND]], label [[LOOP:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 1, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 4
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[CMP2_I_I:%.*]] = icmp ult i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP2_I_I]], label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%end = shl i64 %count, 2
|
|
%precond = icmp ugt i64 %end, 1
|
|
br i1 %precond, label %loop, label %exit
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 1, %entry ]
|
|
%iv.next = add i64 %iv, 4
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @multiple_pow2_start_offset_dynamic(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_pow2_start_offset_dynamic(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[COUNT]], 2
|
|
; CHECK-NEXT: [[END:%.*]] = add i64 [[SHL]], 1
|
|
; CHECK-NEXT: [[PRECOND:%.*]] = icmp ne i64 [[END]], 0
|
|
; CHECK-NEXT: br i1 [[PRECOND]], label [[LOOP:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 1, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 4
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%shl = shl i64 %count, 2
|
|
%end = add i64 %shl, 1
|
|
%precond = icmp ne i64 %end, 0
|
|
br i1 %precond, label %loop, label %exit
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 1, %entry ]
|
|
%iv.next = add i64 %iv, 4
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @multiple_non_pow2_nuw(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_non_pow2_nuw(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[END:%.*]] = mul nuw i64 [[COUNT]], 3
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 3
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%end = mul nuw i64 %count, 3
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %entry ]
|
|
%iv.next = add i64 %iv, 3
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @multiple_non_pow2_missing_nuw(i64 %count) {
|
|
; CHECK-LABEL: define void @multiple_non_pow2_missing_nuw(
|
|
; CHECK-SAME: i64 [[COUNT:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[END:%.*]] = mul i64 [[COUNT]], 3
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 3
|
|
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[CMP2_I_I:%.*]] = icmp ult i64 [[IV]], [[END]]
|
|
; CHECK-NEXT: br i1 [[CMP2_I_I]], label [[LOOP]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%end = mul i64 %count, 3
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %entry ]
|
|
%iv.next = add i64 %iv, 3
|
|
%cmp.i.not = icmp eq i64 %iv, %end
|
|
br i1 %cmp.i.not, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%cmp2.i.i = icmp ult i64 %iv, %end
|
|
br i1 %cmp2.i.i, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|