diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index e71e7eeb8ef1e..1eb7e481d43cd 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -889,6 +889,26 @@ void State::addInfoForInductions(BasicBlock &BB) { else return; + // Handle negative steps. + if (StepOffset.isNegative()) { + // TODO: Extend to allow steps > -1. + if (!(-StepOffset).isOne()) + return; + + // AR may wrap. + // Add StartValue >= PN conditional on B <= StartValue which guarantees that + // the loop exits before wrapping with a step of -1. + WorkList.push_back(FactOrCheck::getConditionFact( + DTN, CmpInst::ICMP_UGE, StartValue, PN, + ConditionTy(CmpInst::ICMP_ULE, B, StartValue))); + // Add PN > B conditional on B <= StartValue which guarantees that the loop + // exits when reaching B with a step of -1. + WorkList.push_back(FactOrCheck::getConditionFact( + DTN, CmpInst::ICMP_UGT, PN, B, + ConditionTy(CmpInst::ICMP_ULE, B, StartValue))); + return; + } + // Make sure AR either steps by 1 or that the value we compare against is a // GEP based on the same start value and all offsets are a multiple of the // step size, to guarantee that the induction will reach the value. diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll index 4ebbae54965a4..155423d33a69a 100644 --- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll +++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll @@ -14,8 +14,7 @@ define void @add_rec_decreasing_cond_true_constant(i8 noundef %len) { ; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i8 [[K_0]], 0 ; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]] ; CHECK: loop.latch: -; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i8 [[K_0]], 5 -; CHECK-NEXT: call void @use(i1 [[CMP_NOT_I]]) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[K_DEC]] = add i8 [[K_0]], -1 ; CHECK-NEXT: br label [[LOOP_HEADER]] ; CHECK: exit: @@ -87,8 +86,7 @@ define void @add_rec_decreasing_cond_true_start_signed_positive(i8 noundef %star ; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i8 [[K_0]], 0 ; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]] ; CHECK: loop.latch: -; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i8 [[K_0]], [[START]] -; CHECK-NEXT: call void @use(i1 [[CMP_NOT_I]]) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[K_DEC]] = add i8 [[K_0]], -1 ; CHECK-NEXT: br label [[LOOP_HEADER]] ; CHECK: exit: diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-nested-loops.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-nested-loops.ll index e5d101f7fdea1..11fb48ff007f5 100644 --- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-nested-loops.ll +++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-nested-loops.ll @@ -117,8 +117,7 @@ define void @inner_add_rec_decreasing(i32 noundef %len) { ; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i32 [[K_0]], 0 ; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[OUTER_LATCH]], label [[INNER_LATCH]] ; CHECK: inner.latch: -; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i32 [[K_0]], [[LEN]] -; CHECK-NEXT: call void @use(i1 [[CMP_NOT_I]]) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[K_DEC]] = add i32 [[K_0]], -1 ; CHECK-NEXT: br label [[INNER_HEADER]] ; CHECK: outer.latch: diff --git a/llvm/test/Transforms/PhaseOrdering/loop-access-checks.ll b/llvm/test/Transforms/PhaseOrdering/loop-access-checks.ll index b5895fac28ab0..fcf1afce80ec0 100644 --- a/llvm/test/Transforms/PhaseOrdering/loop-access-checks.ll +++ b/llvm/test/Transforms/PhaseOrdering/loop-access-checks.ll @@ -270,7 +270,7 @@ declare void @abort() define void @monkey(ptr noundef %arr, i32 noundef %len) { ; CHECK-LABEL: define void @monkey -; CHECK-SAME: (ptr nocapture noundef [[ARR:%.*]], i32 noundef [[LEN:%.*]]) local_unnamed_addr { +; CHECK-SAME: (ptr nocapture noundef [[ARR:%.*]], i32 noundef [[LEN:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP8:%.*]] = icmp ugt i32 [[LEN]], 1 ; CHECK-NEXT: br i1 [[CMP8]], label [[FOR_BODY4_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]] @@ -284,13 +284,7 @@ define void @monkey(ptr noundef %arr, i32 noundef %len) { ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[LEN]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY4_PREHEADER]], label [[FOR_COND_CLEANUP]] ; CHECK: for.body4: -; CHECK-NEXT: [[K_07:%.*]] = phi i32 [ [[DEC:%.*]], [[AT_EXIT:%.*]] ], [ [[I_09]], [[FOR_BODY4_PREHEADER]] ] -; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i32 [[K_07]], [[LEN]] -; CHECK-NEXT: br i1 [[CMP_NOT_I]], label [[AT_EXIT]], label [[IF_THEN_I:%.*]] -; CHECK: if.then.i: -; CHECK-NEXT: tail call void @abort() -; CHECK-NEXT: unreachable -; CHECK: at.exit: +; CHECK-NEXT: [[K_07:%.*]] = phi i32 [ [[DEC:%.*]], [[FOR_BODY4]] ], [ [[I_09]], [[FOR_BODY4_PREHEADER]] ] ; CHECK-NEXT: [[IDX_EXT_I:%.*]] = zext i32 [[K_07]] to i64 ; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds i32, ptr [[ARR]], i64 [[IDX_EXT_I]] ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ADD_PTR_I]], align 4