Index: lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp =================================================================== --- lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp +++ lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp @@ -919,22 +919,21 @@ // can be handled (i.e. with known constant step), and if yes, calculate its // step and identify whether it is increasing or decreasing. auto IsInductionVar = [&](const SCEVAddRecExpr *AR, bool &IsIncreasing, - ConstantInt *&StepCI) { + ConstantInt *&StepCI, bool IsSigned) { if (!AR->isAffine()) return false; // Currently we only work with induction variables that have been proved to // not wrap. This restriction can potentially be lifted in the future. + if (HasNoSignedWrap(AR) || + (!IsSigned && AR->hasNoUnsignedWrap())) { - if (!HasNoSignedWrap(AR)) - return false; - - if (const SCEVConstant *StepExpr = - dyn_cast(AR->getStepRecurrence(SE))) { - StepCI = StepExpr->getValue(); - assert(!StepCI->isZero() && "Zero step?"); - IsIncreasing = !StepCI->isNegative(); - return true; + if (auto *StepExpr = dyn_cast(AR->getStepRecurrence(SE))) { + StepCI = StepExpr->getValue(); + assert(!StepCI->isZero() && "Zero step?"); + IsIncreasing = !StepCI->isNegative(); + return true; + } } return false; @@ -945,9 +944,9 @@ const SCEVAddRecExpr *IndVarBase = cast(LeftSCEV); bool IsIncreasing = false; - bool IsSignedPredicate = true; + bool IsSignedPredicate = ICmpInst::isSigned(Pred); ConstantInt *StepCI; - if (!IsInductionVar(IndVarBase, IsIncreasing, StepCI)) { + if (!IsInductionVar(IndVarBase, IsIncreasing, StepCI, IsSignedPredicate)) { FailureReason = "LHS in icmp not induction variable"; return None; } @@ -962,7 +961,7 @@ bool DecreasedRightValueByOne = false; if (StepCI->isOne()) { // Try to turn eq/ne predicates to those we can work with. - if (Pred == ICmpInst::ICMP_NE && LatchBrExitIdx == 1) + if (Pred == ICmpInst::ICMP_NE && LatchBrExitIdx == 1) { // while (++i != len) { while (++i < len) { // ... ---> ... // } } @@ -974,7 +973,7 @@ Pred = ICmpInst::ICMP_ULT; else Pred = ICmpInst::ICMP_SLT; - else if (Pred == ICmpInst::ICMP_EQ && LatchBrExitIdx == 0) { + } else if (Pred == ICmpInst::ICMP_EQ && LatchBrExitIdx == 0) { // while (true) { while (true) { // if (++i == len) ---> if (++i > len - 1) // break; break; Index: test/Transforms/IRCE/variable-loop-bounds.ll =================================================================== --- test/Transforms/IRCE/variable-loop-bounds.ll +++ test/Transforms/IRCE/variable-loop-bounds.ll @@ -9,6 +9,10 @@ ; CHECK: irce: in function signed_var_imm_dec_sge: constrained Loop at depth 1 containing: %for.body
,%if.else,%for.inc ; CHECK: irce: in function signed_var_imm_dec_ne: constrained Loop at depth 1 containing: %for.body
,%if.else,%for.inc ; CHECK-NOT: irce: in function signed_var_imm_dec_eq: constrained Loop at depth 1 containing: %for.body
,%if.else,%for.inc +; CHECK: irce: in function test_inc_eq_var_nuw: constrained Loop at depth 1 containing: %for.body
,%if.else,%if.then,%for.inc +; CHECK-NOT: irce: in function test_inc_ne_var_nuw: constrained Loop at depth 1 containing: %for.body
,%if.else,%if.then,%for.inc +; CHECK: irce: in function test_inc_ult_var_nuw: constrained Loop at depth 1 containing: %for.body
,%if.else,%if.then,%for.inc +; CHECK: irce: in function test_dec_ult_ugt_var_imm_nuw: constrained Loop at depth 1 containing: %for.body
,%if.else,%if.then,%for.inc ; CHECK-LABEL: test_inc_eq( ; CHECK: main.exit.selector: @@ -321,6 +325,7 @@ br i1 %cmp, label %for.body, label %for.cond.cleanup } +; CHECK-LABEL: signed_var_imm_dec_eq define void @signed_var_imm_dec_eq(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %M) { entry: %cmp14 = icmp slt i32 %M, 1024 @@ -352,3 +357,168 @@ %cmp = icmp eq i32 %dec, %M br i1 %cmp, label %for.cond.cleanup, label %for.body } + +; CHECK-LABEL: test_inc_eq_var_nuw( +; CHECK: main.exit.selector: +; CHECK: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %inc, %for.inc ] +; CHECK: [[COND:%[^ ]+]] = icmp ult i32 [[PSEUDO_PHI]], %N +; CHECK: br i1 [[COND]], label %main.pseudo.exit, label %for.cond.cleanup.loopexit +define void @test_inc_eq_var_nuw(i32* %a, i32* %b, i32* %c, i32 %N, i32 %M) { +entry: + %cmp16 = icmp ugt i32 %N, 0 + br i1 %cmp16, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: + ret void + +for.body: + %i.017 = phi i32 [ %inc, %for.inc ], [ 0, %entry ] + %cmp1 = icmp ult i32 %i.017, %M + %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.017 + %0 = load i32, i32* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds i32, i32* %c, i32 %i.017 + %1 = load i32, i32* %arrayidx2, align 4 + br i1 %cmp1, label %if.then, label %if.else + +if.then: + %sub = sub i32 %0, %1 + %arrayidx3 = getelementptr inbounds i32, i32* %a, i32 %i.017 + %2 = load i32, i32* %arrayidx3, align 4 + %add = add nsw i32 %sub, %2 + store i32 %add, i32* %arrayidx3, align 4 + br label %for.inc + +if.else: + %add6 = add nsw i32 %1, %0 + %arrayidx7 = getelementptr inbounds i32, i32* %a, i32 %i.017 + store i32 %add6, i32* %arrayidx7, align 4 + br label %for.inc + +for.inc: + %inc = add nuw i32 %i.017, 1 + %exitcond = icmp eq i32 %inc, %N + br i1 %exitcond, label %for.cond.cleanup, label %for.body +} + +; CHECK-LABEL: test_inc_ne_var_nuw +; TODO Don't know why eq works but ne doesn't. +define void @test_inc_ne_var_nuw(i32* %a, i32* %b, i32* %c, i32 %N, i32 %M) { +entry: + %cmp16 = icmp ugt i32 %N, 0 + br i1 %cmp16, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: + ret void + +for.body: + %i.017 = phi i32 [ %inc, %for.inc ], [ 0, %entry ] + %cmp1 = icmp ult i32 %i.017, %M + %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.017 + %0 = load i32, i32* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds i32, i32* %c, i32 %i.017 + %1 = load i32, i32* %arrayidx2, align 4 + br i1 %cmp1, label %if.then, label %if.else + +if.then: + %sub = sub i32 %0, %1 + %arrayidx3 = getelementptr inbounds i32, i32* %a, i32 %i.017 + %2 = load i32, i32* %arrayidx3, align 4 + %add = add nsw i32 %sub, %2 + store i32 %add, i32* %arrayidx3, align 4 + br label %for.inc + +if.else: + %add6 = add nsw i32 %1, %0 + %arrayidx7 = getelementptr inbounds i32, i32* %a, i32 %i.017 + store i32 %add6, i32* %arrayidx7, align 4 + br label %for.inc + +for.inc: + %inc = add nuw i32 %i.017, 1 + %exitcond = icmp ne i32 %inc, %N + br i1 %exitcond, label %for.body, label %for.cond.cleanup +} + +; CHECK-LABEL: test_inc_ult_var_nuw +; CHECK: main.exit.selector: +; CHECK: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %inc, %for.inc ] +; CHECK: [[COND:%[^ ]+]] = icmp ult i32 [[PSEUDO_PHI]], %N +; CHECK: br i1 [[COND]], label %main.pseudo.exit, label %for.cond.cleanup.loopexit +define void @test_inc_ult_var_nuw(i32* %a, i32* %b, i32* %c, i32 %N, i32 %M) { +entry: + %cmp16 = icmp ugt i32 %N, 0 + br i1 %cmp16, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: + ret void + +for.body: + %i.017 = phi i32 [ %inc, %for.inc ], [ 0, %entry ] + %cmp1 = icmp ult i32 %i.017, %M + %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.017 + %0 = load i32, i32* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds i32, i32* %c, i32 %i.017 + %1 = load i32, i32* %arrayidx2, align 4 + br i1 %cmp1, label %if.then, label %if.else + +if.then: + %sub = sub i32 %0, %1 + %arrayidx3 = getelementptr inbounds i32, i32* %a, i32 %i.017 + %2 = load i32, i32* %arrayidx3, align 4 + %add = add nsw i32 %sub, %2 + store i32 %add, i32* %arrayidx3, align 4 + br label %for.inc + +if.else: + %add6 = add nsw i32 %1, %0 + %arrayidx7 = getelementptr inbounds i32, i32* %a, i32 %i.017 + store i32 %add6, i32* %arrayidx7, align 4 + br label %for.inc + +for.inc: + %inc = add nuw i32 %i.017, 1 + %exitcond = icmp ult i32 %inc, %N + br i1 %exitcond, label %for.body, label %for.cond.cleanup +} + +; CHECK-LABEL: test_dec_ult_ugt_var_imm_nuw( +; CHECK: for.body: +; CHECK: [[IV:%[^ ]+]] = phi i32 [ %inc, %for.inc ], [ %i.017.preloop.copy, %mainloop ] +; CHECK: [[COND:%[^ ]+]] = icmp ult i32 [[IV]], %M +; CHECK: br i1 true, label %if.then, label %if.else +define void @test_dec_ult_ugt_var_imm_nuw(i32* %a, i32* %b, i32* %c, i32 %N, i32 %M) { +entry: + br label %for.body + +for.cond.cleanup: + ret void + +for.body: + %i.017 = phi i32 [ %inc, %for.inc ], [ 1024, %entry ] + %cmp1 = icmp ult i32 %i.017, %M + %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.017 + %0 = load i32, i32* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds i32, i32* %c, i32 %i.017 + %1 = load i32, i32* %arrayidx2, align 4 + br i1 %cmp1, label %if.then, label %if.else + +if.then: + %sub = sub i32 %0, %1 + %arrayidx3 = getelementptr inbounds i32, i32* %a, i32 %i.017 + %2 = load i32, i32* %arrayidx3, align 4 + %add = add nsw i32 %sub, %2 + store i32 %add, i32* %arrayidx3, align 4 + br label %for.inc + +if.else: + %add6 = add nsw i32 %1, %0 + %arrayidx7 = getelementptr inbounds i32, i32* %a, i32 %i.017 + store i32 %add6, i32* %arrayidx7, align 4 + br label %for.inc + +for.inc: + %inc = add nuw i32 %i.017, -1 + %exitcond = icmp ugt i32 %inc, 0 + br i1 %exitcond, label %for.body, label %for.cond.cleanup +} +