This is an archive of the discontinued LLVM Phabricator instance.

Make ScalarEvolution::isKnownPredicate a little smarter
ClosedPublic

Authored by hfinkel on Aug 17 2015, 12:41 AM.

Details

Reviewers
atrick
sanjoy
Summary

First, the motivation for this patch is to allow LLVM to optimize this code as one might hope:

void foo (int *a, int *b, int n) {
  for (int i = 0; i < n; ++i) {
    if (i > n)
      a[i] = b[i] + 1;
  }
}

As i is less than n in the loop, the conditional (i > n) can be folded to false.

With this relatively-simple change, we can perform the simplification in the default pipeline: indvars can perform the folding using SCEV.

Now the obvious question is: is it correct? For now, I've XFAIL'ed two tests:

I believe that the test/Transforms/IndVarSimplify/backedge-on-min-max.ll changes are legitimate (some of the loops in those tests are actually infinite loops, this change causes indvars to make that explicit instead of making other changes - unfortunately, I've been unable to fix the tests to serve their original purpose).

The test/Transforms/LoopStrengthReduce/X86/pr17473.ll changes look more dubious, and I'd certainly appreciate a second opinion. I'll attach some screen shots with the diffs.

Diff Detail

Event Timeline

hfinkel updated this revision to Diff 32272.Aug 17 2015, 12:41 AM
hfinkel retitled this revision from to Make ScalarEvolution::isKnownPredicate a little smarter.
hfinkel updated this object.
hfinkel added reviewers: sanjoy, atrick.
hfinkel set the repository for this revision to rL LLVM.
hfinkel added a subscriber: llvm-commits.

To hopefully make things easier, I've attached screenshots of the diffs of the changed tests.

-Hal

  • Original Message -----

From: hfinkel@anl.gov
To: hfinkel@anl.gov, sanjoy@playingwithpointers.com, atrick@apple.com
Cc: llvm-commits@lists.llvm.org
Sent: Monday, August 17, 2015 2:41:38 AM
Subject: [PATCH] D12073: Make ScalarEvolution::isKnownPredicate a little smarter

hfinkel created this revision.
hfinkel added reviewers: sanjoy, atrick.
hfinkel added a subscriber: llvm-commits.
hfinkel set the repository for this revision to rL LLVM.
Herald added a subscriber: sanjoy.

First, the motivation for this patch is to allow LLVM to optimize
this code as one might hope:

void foo (int *a, int *b, int n) {
  for (int i = 0; i < n; ++i) {
    if (i > n)
      a[i] = b[i] + 1;
  }
}

As i is less than n in the loop, the conditional (i > n) can be
folded to false.

With this relatively-simple change, we can perform the simplification
in the default pipeline: indvars can perform the folding using SCEV.

Now the obvious question is: is it correct? For now, I've XFAIL'ed
two tests:

I believe that the
test/Transforms/IndVarSimplify/backedge-on-min-max.ll changes are
legitimate (some of the loops in those tests are actually infinite
loops, this change causes indvars to make that explicit instead of
making other changes - unfortunately, I've been unable to fix the
tests to serve their original purpose).

The test/Transforms/LoopStrengthReduce/X86/pr17473.ll changes look
more dubious, and I'd certainly appreciate a second opinion. I'll
attach some screen shots with the diffs.

Repository:

rL LLVM

http://reviews.llvm.org/D12073

Files:

lib/Analysis/ScalarEvolution.cpp
test/Transforms/IndVarSimplify/backedge-on-min-max.ll
test/Transforms/IndVarSimplify/bec-cmp.ll
test/Transforms/LoopStrengthReduce/X86/pr17473.ll

sanjoy edited edge metadata.Aug 17 2015, 9:40 AM

I'd solve this differently -- if I understand the problem correctly, you should really only need to teach SCEV that {0,+,1}<nsw> is slt {1,+,1}<nsw> (or something similar to that) in isImpliedCondOperandsHelper.

lib/Analysis/ScalarEvolution.cpp
6873

This should probably live in ScalarEvolution::isKnownPredicate or ScalarEvolution::isImpliedCondOperandsHelper, not here.

6892

I'm not sure this is sound w.r.t. overflow. For instance, if LHS = i8 127 and RHS = i8 -1 then !(LHS < RHS) but LHS - RHS = i8 128 < 0

6909

Same comment as above on overflow.

I'd solve this differently -- if I understand the problem correctly, you should really only need to teach SCEV that {0,+,1}<nsw> is slt {1,+,1}<nsw> (or something similar to that) in isImpliedCondOperandsHelper.

That's correct (but it triggers in some other cases too); I need to look at this in more detail, but a quick check reveals that for this code:

$ cat /tmp/t.c
void foo (int *a, int *b, int n) {
  for (int i = 0; i < n; ++i) {
    if (i > n)
      a[i] = b[i] + 1;
  }
}

these statements trigger to do the following:

  • proving that {0,+,1}<nuw><nsw><%for.body> sle {1,+,1}<nuw><nsw><%for.body> (the subtraction simplifies to -1)
  • proving that (sext i32 %n to i64) sle (1 + (sext i32 %n to i64))<nsw> (again, the subtraction simplifies to -1)

for this code (which differs from the above only by the +4):

$ cat /tmp/t4.c
void foo (int *a, int *b, int n) {
  for (int i = 0; i < n; ++i) {
    if (i > n + 4)
      a[i] = b[i] + 1;
  }
}

this code is used to:

  • prove that %n sle (4 + %n) (the subtraction simplifies to -4)
  • prove that {0,+,1}<nuw><nsw><%for.body> sle {1,+,1}<nuw><nsw><%for.body> (the subtraction simplifies to -1)

In the pr17473.ll test case, the statements trigger to:

  • prove that 0 sle {1,+,1}<%for.body> (the subtraction simplifies to {-1,+,-1}<%for.body>
  • prove that 127 sle {-2,+,-1}<%for.body> (the subtraction simplifies to {-127,+,1}<%for.body>)

That last one does indeed seem wrong (certainly justifying your point below).

lib/Analysis/ScalarEvolution.cpp
6873

I put these here as they exactly mirror the check done below as part of the ICmpInst::ICMP_NE case below (which could certainly also be moved if we'd like).

6892

This is precisely what was worrying me w.r.t. to correctness, and given the output, it seems this is exactly what happens. Sign-extending first would fix that, right?

To look at this a bit more (i.e. why does this actually make the test case pass), we have this:

SimplifyIndvar::eliminateIVComparison has this code:

} else if (SE->isKnownPredicate(ICmpInst::getInversePredicate(Pred), S, X)) {
  ICmp->replaceAllUsesWith(ConstantInt::getFalse(ICmp->getContext()));
  DeadInsts.emplace_back(ICmp);
  DEBUG(dbgs() << "INDVARS: Eliminated comparison: " << *ICmp << '\n');

Pred is CmpInst::ICMP_SGT, so the inverse predicate is ICMP_SLE.

And is calling it with:

S = {0,+,1}<nuw><nsw><%for.body> and X = %n

ScalarEvolution::isKnownPredicate first calls SimplifyICmpOperands, which rewrites LHS and RHS to be:

LHS = {-1,+,1}<nsw><%for.body>, RHS = %n, and sets Pred = CmpInst::ICMP_SLT

ScalarEvolution::isKnownPredicate then ends of here:

if (LAR) {
  const Loop *L = LAR->getLoop();
  if (isLoopEntryGuardedByCond(L, Pred, LAR->getStart(), RHS) &&
      isLoopBackedgeGuardedByCond(L, Pred, LAR->getPostIncExpr(*this), RHS)) {
    if (!RAR) return true;

(where RAR is nullptr here because %n is not an AddRec).

At this point, we end up in ScalarEvolution::isLoopBackedgeGuardedByCond where
we have:

Pred = CmpInst::ICMP_SLT, LHS = {0,+,1}<nuw><nsw><%for.body> and RHS = %n

ScalarEvolution::isLoopBackedgeGuardedByCond finds the loop backedge predicate:

br i1 %cmp, label %for.body, label %for.cond.for.cond.cleanup_crit_edge

being fed by:

%cmp = icmp slt i32 %inc, %n

and calls ScalarEvolution::isImpliedCond, and that calls ScalarEvolution::isImpliedCondOperands with:

FoundLHS = {1,+,1}<nuw><nsw><%for.body>, FoundRHS = %n

where we still have:

LHS = {0,+,1}<nuw><nsw><%for.body>, RHS = %n

that calls ScalarEvolution::isImpliedCondOperandsHelper, and that ends up here:

case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_SLE:
  if (IsKnownPredicateFull(ICmpInst::ICMP_SLE, LHS, FoundLHS) &&
      IsKnownPredicateFull(ICmpInst::ICMP_SGE, RHS, FoundRHS))
    return true;

IsKnownPredicateFull is this lambda function:

auto IsKnownPredicateFull =
  [this](ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS) {
    return isKnownPredicateWithRanges(Pred, LHS, RHS) ||
           IsKnownPredicateViaMinOrMax(*this, Pred, LHS, RHS);
};

and it is this call to ScalarEvolution::isKnownPredicateWithRanges, with:

LHS = {0,+,1}<nuw><nsw><%for.body> and RHS = {1,+,1}<nuw><nsw><%for.body> that the code added in this patch triggers to provide an answer we could not previously provide.

And so, yes, you're right, putting this logic in isImpliedCondOperandsHelper seems like a practical place.

lib/Analysis/ScalarEvolution.cpp
6892

As it turns out, sign extending works, but can't be used here. The problem is that, under certain circumstances, getSignExtendExpr calls isLoopBackedgeGuardedByCond, and that calls isKnownPredicateWithRanges (yielding an infinite recursion).

hfinkel updated this revision to Diff 32347.Aug 17 2015, 3:26 PM
hfinkel edited edge metadata.
hfinkel removed rL LLVM as the repository for this revision.

As suggested, move logic into ScalarEvolution::isImpliedCondOperandsHelper, and sign-extend before the subtraction to deal with potential overflow in the subtraction.

There are now three failing tests, mostly due to IV widening that now does not happen. The new known-predicate results are:

test/Transforms/IndVarSimplify/elim-extend.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>
  • {(sext i32 %init to i64),+,1}<nsw><%loop> sle {(1 + (sext i32 %init to i64)),+,1}<nsw><%loop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><%outerloop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><nsw><%outerloop>

test/Transforms/IndVarSimplify/iv-sext.ll:

  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><%bb>
  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><nsw><%bb>

test/Transforms/IndVarSimplify/strengthen-overflow.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>

These look right, but some consumer of the information seems to make a worse no-wrap deductions as a result (thus, this patch is still WIP).

There are now three failing tests, mostly due to IV widening that now does not happen. The new known-predicate results are:

test/Transforms/IndVarSimplify/elim-extend.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>
  • {(sext i32 %init to i64),+,1}<nsw><%loop> sle {(1 + (sext i32 %init to i64)),+,1}<nsw><%loop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><%outerloop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><nsw><%outerloop>

test/Transforms/IndVarSimplify/iv-sext.ll:

  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><%bb>
  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><nsw><%bb>

test/Transforms/IndVarSimplify/strengthen-overflow.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>

These look right, but some consumer of the information seems to make a worse no-wrap deductions as a result (thus, this patch is still WIP).

I suspect (haven't verified) this is due to SCEV's caching mechanism. You end up creating a "Sext(LHS)" too soon, before proving all of the things needed to show that LHS is nsw. Then this suboptimal result gets cached.

In other words, I suspect the stack trace looks like this (youngest frame at top) initially:

== false because of PendingLoopPredicates, set in frame (A)
getImpliedCond(...)  // ends up looking at VAL
getLoopBackedgeCount(...)
getSignExtend(VAL)  // due to your change
getImpliedCond(...)  // ends up looking at VAL .. (A)
getLoopBackedgeCount(...)
getSignExtend(VAL)

This goes on as

  getSignExtend(VAL)  ==> no simplification, and we end up with
        UniqueSCEVs[(SignExtend, VAL)] = SignExtendExpr VAL, and
	does not set the <nsw> bit in VAL
  getImpliedCond(...)  // ends up looking at VAL .. (A)
  getLoopBackedgeCount(...)
  getSignExtend(VAL)

And then finally the oldest frame returns:

getSignExtend(VAL)  // this returns a widened version of VAL (instead of
  an explicit sign extend), and also set VAL's nsw bit

However, the damage has been done since UniqueSCEVs[(SignExtend, VAL)] == (SignExtendExpr VAL) and that's the value ScalarEvolution::getSignExtendExpr will return from now on.

If you implement your check without actually creating a sign extend, but by directly inferring no-overflow from the nsw or nuw flags, then I suspect this won't happen.

lib/Analysis/ScalarEvolution.cpp
7355

I think this change would be cleaner if SignedDiff took explicit LHS and RHS arguments.

hfinkel added a comment.EditedAug 17 2015, 11:51 PM

There are now three failing tests, mostly due to IV widening that now does not happen. The new known-predicate results are:

test/Transforms/IndVarSimplify/elim-extend.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>
  • {(sext i32 %init to i64),+,1}<nsw><%loop> sle {(1 + (sext i32 %init to i64)),+,1}<nsw><%loop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><%outerloop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><nsw><%outerloop>

test/Transforms/IndVarSimplify/iv-sext.ll:

  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><%bb>
  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><nsw><%bb>

test/Transforms/IndVarSimplify/strengthen-overflow.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>

These look right, but some consumer of the information seems to make a worse no-wrap deductions as a result (thus, this patch is still WIP).

I suspect (haven't verified) this is due to SCEV's caching mechanism. You end up creating a "Sext(LHS)" too soon, before proving all of the things needed to show that LHS is nsw. Then this suboptimal result gets cached.

In other words, I suspect the stack trace looks like this (youngest frame at top) initially:

== false because of PendingLoopPredicates, set in frame (A)
getImpliedCond(...)  // ends up looking at VAL
getLoopBackedgeCount(...)
getSignExtend(VAL)  // due to your change
getImpliedCond(...)  // ends up looking at VAL .. (A)
getLoopBackedgeCount(...)
getSignExtend(VAL)

This goes on as

  getSignExtend(VAL)  ==> no simplification, and we end up with
        UniqueSCEVs[(SignExtend, VAL)] = SignExtendExpr VAL, and
	does not set the <nsw> bit in VAL
  getImpliedCond(...)  // ends up looking at VAL .. (A)
  getLoopBackedgeCount(...)
  getSignExtend(VAL)

And then finally the oldest frame returns:

getSignExtend(VAL)  // this returns a widened version of VAL (instead of
  an explicit sign extend), and also set VAL's nsw bit

However, the damage has been done since UniqueSCEVs[(SignExtend, VAL)] == (SignExtendExpr VAL) and that's the value ScalarEvolution::getSignExtendExpr will return from now on.

If you implement your check without actually creating a sign extend, but by directly inferring no-overflow from the nsw or nuw flags, then I suspect this won't happen.

Looking at the test/Transforms/IndVarSimplify/strengthen-overflow.ll test case, for example, here's (in part) what is going on, at least in terms of initial behavior:

SimplifyIndvar::strengthenOverflowingOperation has code that looks like this:

if (!BO->hasNoUnsignedWrap()) {
  const SCEV *ExtendAfterOp = SE->getZeroExtendExpr(SE->getSCEV(BO), WideTy);
  const SCEV *OpAfterExtend = (SE->*GetExprForBO)(
    SE->getZeroExtendExpr(LHS, WideTy), SE->getZeroExtendExpr(RHS, WideTy),
    SCEV::FlagAnyWrap);
  if (ExtendAfterOp == OpAfterExtend) {
    BO->setHasNoUnsignedWrap();
    SE->forgetValue(BO);
    Changed = true;
  }
}

if (!BO->hasNoSignedWrap()) {
  const SCEV *ExtendAfterOp = SE->getSignExtendExpr(SE->getSCEV(BO), WideTy);
  const SCEV *OpAfterExtend = (SE->*GetExprForBO)(
    SE->getSignExtendExpr(LHS, WideTy), SE->getSignExtendExpr(RHS, WideTy),
    SCEV::FlagAnyWrap);
  if (ExtendAfterOp == OpAfterExtend) {
    BO->setHasNoSignedWrap();
    SE->forgetValue(BO);
    Changed = true;
  }
}

Now the fun part is that the new code actually triggers as part of the checks done under if (!BO->hasNoUnsignedWrap()), but we can't prove nuw regardless, but it changes things such that the code under if (!BO->hasNoSignedWrap()) no longer works as well as it did previously.

We start with LHS = {%init,+,1}<%loop>, RHS = 1, and as part of computing OpAfterExtend (in the unsigned case), we hit this part of ScalarEvolution::getSignExtendExpr:

  // If the backedge is guarded by a comparison with the pre-inc value
  // the addrec is safe. Also, if the entry is guarded by a comparison
  // with the start value and the backedge is guarded by a comparison
  // with the post-inc value, the addrec is safe.
  ICmpInst::Predicate Pred;
  const SCEV *OverflowLimit =
      getSignedOverflowLimitForStep(Step, &Pred, this);
  if (OverflowLimit &&
      (isLoopBackedgeGuardedByCond(L, Pred, AR, OverflowLimit) ||
       (isLoopEntryGuardedByCond(L, Pred, Start, OverflowLimit) &&
        isLoopBackedgeGuardedByCond(L, Pred, AR->getPostIncExpr(*this),
                                    OverflowLimit)))) {
    // Cache knowledge of AR NSW, then propagate NSW to the wide AddRec.
    const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNSW);
    return getAddRecExpr(
        getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),
        getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
  }
}

and this cached nsw flag ends up on our RHS, so we now have:

LHS = {%init,+,1}<nsw><%loop>, RHS = 1

and so the call to SE->getSignExtendExpr(LHS, WideTy) now returns:

(sext i32 {%init,+,1}<nsw><%loop> to i64)

instead of returning:

{(sext i32 %init to i64),+,1}<nsw><%loop> (as it does without this patch).

as a result, we get:

ExtendAfterOp == {(1 + (sext i32 %init to i64)),+,1}<nsw><%loop>
OpAfterExtend == (1 + (sext i32 {%init,+,1}<nsw><%loop> to i64))

instead of:

ExtendAfterOp == OpAfterExtend == {(1 + (sext i32 %init to i64)),+,1}<nsw><%loop>

interestingly, the results in the nuw case are also slightly different (although in neither case are equal because we can't provide nuw regardless). With the patch we get this:

ExtendAfterOp == (zext i32 {(1 + %init),+,1}<nsw><%loop> to i64)
OpAfterExtend == (1 + (zext i32 {%init,+,1}<nsw><%loop> to i64))

whereas currently we get:

ExtendAfterOp == (zext i32 {(1 + %init),+,1}<%loop> to i64)
OpAfterExtend == (1 + (zext i32 {%init,+,1}<%loop> to i64))

(so we get some extra <nsw>s for our trouble)

If you implement your check without actually creating a sign extend, but by directly inferring no-overflow from the nsw or nuw flags, then I suspect this won't happen.

If both LHS and RHS are AddRecs, and both are nsw and both have the same stride, then comparing the starting values seems as though it would be sufficient. Is there a straightforward way to do any better than that?

There are now three failing tests, mostly due to IV widening that now does not happen. The new known-predicate results are:

test/Transforms/IndVarSimplify/elim-extend.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>
  • {(sext i32 %init to i64),+,1}<nsw><%loop> sle {(1 + (sext i32 %init to i64)),+,1}<nsw><%loop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><%outerloop>
  • {-1,+,1}<nsw><%outerloop> sle {1,+,1}<nuw><nsw><%outerloop>

test/Transforms/IndVarSimplify/iv-sext.ll:

  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><%bb>
  • {-1,+,1}<nsw><%bb> sle {1,+,1}<nuw><nsw><%bb>

test/Transforms/IndVarSimplify/strengthen-overflow.ll:

  • {%init,+,1}<nsw><%loop> sle {(1 + %init),+,1}<nsw><%loop>

These look right, but some consumer of the information seems to make a worse no-wrap deductions as a result (thus, this patch is still WIP).

I suspect (haven't verified) this is due to SCEV's caching mechanism. You end up creating a "Sext(LHS)" too soon, before proving all of the things needed to show that LHS is nsw. Then this suboptimal result gets cached.

In other words, I suspect the stack trace looks like this (youngest frame at top) initially:

== false because of PendingLoopPredicates, set in frame (A)
getImpliedCond(...)  // ends up looking at VAL
getLoopBackedgeCount(...)
getSignExtend(VAL)  // due to your change
getImpliedCond(...)  // ends up looking at VAL .. (A)
getLoopBackedgeCount(...)
getSignExtend(VAL)

This goes on as

  getSignExtend(VAL)  ==> no simplification, and we end up with
        UniqueSCEVs[(SignExtend, VAL)] = SignExtendExpr VAL, and
	does not set the <nsw> bit in VAL
  getImpliedCond(...)  // ends up looking at VAL .. (A)
  getLoopBackedgeCount(...)
  getSignExtend(VAL)

And then finally the oldest frame returns:

getSignExtend(VAL)  // this returns a widened version of VAL (instead of
  an explicit sign extend), and also set VAL's nsw bit

However, the damage has been done since UniqueSCEVs[(SignExtend, VAL)] == (SignExtendExpr VAL) and that's the value ScalarEvolution::getSignExtendExpr will return from now on.

If you implement your check without actually creating a sign extend, but by directly inferring no-overflow from the nsw or nuw flags, then I suspect this won't happen.

After looking at this more, your hypothesis is correct. We end up recursing on getSignExtendExpr {%init,+,1}<%loop>, which is broken by something (PendingLoopPredicates makes sense), and thus we cache a bad answer for the sign extension. Later, we retrieve the bad answer from the cache. Thus the problem. Thanks!

hfinkel updated this revision to Diff 32433.Aug 18 2015, 11:35 AM

Update the patch to deal more-manually with AddRec expressions where we have wrapping guarantees on both sides and can otherwise reduce the problem to a comparison on the recursion starting values. As Sanjoy hypothesized, in writing it this way, there is no longer collateral damage to other regression tests.

hfinkel updated this revision to Diff 32434.Aug 18 2015, 11:43 AM

We actually don't need to check the positivity of the recursion step because we're checking for equality (so both addrecs move in lock-step and it does not matter in which direction since neither will wrap).

sanjoy requested changes to this revision.Aug 18 2015, 1:01 PM
sanjoy edited edge metadata.
sanjoy added inline comments.
lib/Analysis/ScalarEvolution.cpp
7357

Optional: I'd have just folded the null checks into this condition.

7367

I'd use CmpInst::isSigned(Pred) here.

7368

Why not return AR->getNoWrapFlags(SCEV::FlagNSW); here, and return AR->getNoWrapFlags(SCEV::FlagNUW); in the else block?

This revision now requires changes to proceed.Aug 18 2015, 1:01 PM
hfinkel marked 2 inline comments as done.Aug 18 2015, 3:44 PM
hfinkel added inline comments.
lib/Analysis/ScalarEvolution.cpp
7357

I did not do that so that I could easily avoid the second dyn_cast should the first one fail.

7367

Good suggestion.

7368

Also a good suggestion.

hfinkel updated this revision to Diff 32466.Aug 18 2015, 3:46 PM
hfinkel edited edge metadata.
hfinkel marked 2 inline comments as done.

Implemented Sanjoy's suggestions.

sanjoy accepted this revision.Aug 18 2015, 3:51 PM
sanjoy edited edge metadata.

lgtm.

This revision is now accepted and ready to land.Aug 18 2015, 3:51 PM
hfinkel closed this revision.Aug 18 2015, 7:03 PM

r245400, thanks!