[llvm] r231305 - [SCEV] make SCEV smarter about proving no-wrap.

Sanjoy Das sanjoy at playingwithpointers.com
Wed Mar 4 17:12:19 PST 2015


This should be fixed in r231331.

On Wed, Mar 4, 2015 at 4:40 PM, Sanjoy Das
<sanjoy at playingwithpointers.com> wrote:
> Thanks for notifying.  I'm looking at the errors,  I'll either fix or
> revert shortly.
>
> On Wed, Mar 4, 2015 at 4:33 PM, Kostya Serebryany <kcc at google.com> wrote:
>> This seems to have broken gcc builds:
>> http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fuzzer/builds/679/steps/build%20clang/logs/stdio
>>
>> On Wed, Mar 4, 2015 at 2:24 PM, Sanjoy Das <sanjoy at playingwithpointers.com>
>> wrote:
>>>
>>> Author: sanjoy
>>> Date: Wed Mar  4 16:24:17 2015
>>> New Revision: 231305
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=231305&view=rev
>>> Log:
>>> [SCEV] make SCEV smarter about proving no-wrap.
>>>
>>> Summary:
>>> Teach SCEV to prove no overflow for an add recurrence by proving
>>> something about the range of another add recurrence a loop-invariant
>>> distance away from it.
>>>
>>> Reviewers: atrick, hfinkel
>>>
>>> Subscribers: llvm-commits
>>>
>>> Differential Revision: http://reviews.llvm.org/D7980
>>>
>>> Added:
>>>     llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll
>>> Modified:
>>>     llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
>>>     llvm/trunk/lib/Analysis/ScalarEvolution.cpp
>>>
>>> Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolution.h?rev=231305&r1=231304&r2=231305&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/include/llvm/Analysis/ScalarEvolution.h (original)
>>> +++ llvm/trunk/include/llvm/Analysis/ScalarEvolution.h Wed Mar  4 16:24:17
>>> 2015
>>> @@ -561,6 +561,15 @@ namespace llvm {
>>>      /// pointer.
>>>      bool checkValidity(const SCEV *S) const;
>>>
>>> +    // Return true if `ExtendOpTy`({`Start`,+,`Step`}) can be proved to
>>> be equal
>>> +    // to {`ExtendOpTy`(`Start`),+,`ExtendOpTy`(`Step`)}.  This is
>>> equivalent to
>>> +    // proving no signed (resp. unsigned) wrap in {`Start`,+,`Step`} if
>>> +    // `ExtendOpTy` is `SCEVSignExtendExpr` (resp. `SCEVZeroExtendExpr`).
>>> +    //
>>> +    template<typename ExtendOpTy>
>>> +    bool proveNoWrapByVaryingStart(const SCEV *Start, const SCEV *Step,
>>> +                                   const Loop *L);
>>> +
>>>    public:
>>>      static char ID; // Pass identification, replacement for typeid
>>>      ScalarEvolution();
>>>
>>> Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=231305&r1=231304&r2=231305&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
>>> +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Wed Mar  4 16:24:17 2015
>>> @@ -1325,6 +1325,85 @@ static const SCEV *getExtendAddRecStart(
>>>                          (SE->*GetExtendExpr)(PreStart, Ty));
>>>  }
>>>
>>> +// Try to prove away overflow by looking at "nearby" add recurrences.  A
>>> +// motivating example for this rule: if we know `{0,+,4}` is `ult` `-1`
>>> and it
>>> +// does not itself wrap then we can conclude that `{1,+,4}` is `nuw`.
>>> +//
>>> +// Formally:
>>> +//
>>> +//     {S,+,X} == {S-T,+,X} + T
>>> +//  => Ext({S,+,X}) == Ext({S-T,+,X} + T)
>>> +//
>>> +// If ({S-T,+,X} + T) does not overflow  ... (1)
>>> +//
>>> +//  RHS == Ext({S-T,+,X} + T) == Ext({S-T,+,X}) + Ext(T)
>>> +//
>>> +// If {S-T,+,X} does not overflow  ... (2)
>>> +//
>>> +//  RHS == Ext({S-T,+,X}) + Ext(T) == {Ext(S-T),+,Ext(X)} + Ext(T)
>>> +//      == {Ext(S-T)+Ext(T),+,Ext(X)}
>>> +//
>>> +// If (S-T)+T does not overflow  ... (3)
>>> +//
>>> +//  RHS == {Ext(S-T)+Ext(T),+,Ext(X)} == {Ext(S-T+T),+,Ext(X)}
>>> +//      == {Ext(S),+,Ext(X)} == LHS
>>> +//
>>> +// Thus, if (1), (2) and (3) are true for some T, then
>>> +//   Ext({S,+,X}) == {Ext(S),+,Ext(X)}
>>> +//
>>> +// (3) is implied by (1) -- "(S-T)+T does not overflow" is simply
>>> "({S-T,+,X}+T)
>>> +// does not overflow" restricted to the 0th iteration.  Therefore we only
>>> need
>>> +// to check for (1) and (2).
>>> +//
>>> +// In the current context, S is `Start`, X is `Step`, Ext is `ExtendOpTy`
>>> and T
>>> +// is `Delta` (defined below).
>>> +//
>>> +template <typename ExtendOpTy>
>>> +bool ScalarEvolution::proveNoWrapByVaryingStart(const SCEV *Start,
>>> +                                                const SCEV *Step,
>>> +                                                const Loop *L) {
>>> +  auto WrapType = ExtendOpTraits<ExtendOpTy>::WrapType;
>>> +
>>> +  // We restrict `Start` to a constant to prevent SCEV from spending too
>>> much
>>> +  // time here.  It is correct (but more expensive) to continue with a
>>> +  // non-constant `Start` and do a general SCEV subtraction to compute
>>> +  // `PreStart` below.
>>> +  //
>>> +  const SCEVConstant *StartC = dyn_cast<SCEVConstant>(Start);
>>> +  if (!StartC)
>>> +    return false;
>>> +
>>> +  APInt StartAI = StartC->getValue()->getValue();
>>> +
>>> +  for (unsigned Delta : {-2, -1, 1, 2}) {
>>> +    const SCEV *PreStart = getConstant(StartAI - Delta);
>>> +
>>> +    // Give up if we don't already have the add recurrence we need
>>> because
>>> +    // actually constructing an add recurrence is relatively expensive.
>>> +    const SCEVAddRecExpr *PreAR = [&]() {
>>> +      FoldingSetNodeID ID;
>>> +      ID.AddInteger(scAddRecExpr);
>>> +      ID.AddPointer(PreStart);
>>> +      ID.AddPointer(Step);
>>> +      ID.AddPointer(L);
>>> +      void *IP = nullptr;
>>> +      return static_cast<SCEVAddRecExpr *>(
>>> +        UniqueSCEVs.FindNodeOrInsertPos(ID, IP));
>>> +    }();
>>> +
>>> +    if (PreAR && PreAR->getNoWrapFlags(WrapType)) {  // proves (2)
>>> +      const SCEV *DeltaS = getConstant(StartC->getType(), Delta);
>>> +      ICmpInst::Predicate Pred = ICmpInst::BAD_ICMP_PREDICATE;
>>> +      const SCEV *Limit =
>>> ExtendOpTraits<ExtendOpTy>::getOverflowLimitForStep(
>>> +          DeltaS, &Pred, this);
>>> +      if (Limit && isKnownPredicate(Pred, PreAR, Limit))  // proves (1)
>>> +        return true;
>>> +    }
>>> +  }
>>> +
>>> +  return false;
>>> +}
>>> +
>>>  const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
>>>                                                 Type *Ty) {
>>>    assert(getTypeSizeInBits(Op->getType()) < getTypeSizeInBits(Ty) &&
>>> @@ -1473,6 +1552,13 @@ const SCEV *ScalarEvolution::getZeroExte
>>>            }
>>>          }
>>>        }
>>> +
>>> +      if (proveNoWrapByVaryingStart<SCEVZeroExtendExpr>(Start, Step, L))
>>> {
>>> +        const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNUW);
>>> +        return getAddRecExpr(
>>> +            getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),
>>> +            getZeroExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
>>> +      }
>>>      }
>>>
>>>    // The cast wasn't folded; create an explicit cast node.
>>> @@ -1664,6 +1750,13 @@ const SCEV *ScalarEvolution::getSignExte
>>>            return getAddExpr(Start, getSignExtendExpr(NewAR, Ty));
>>>          }
>>>        }
>>> +
>>> +      if (proveNoWrapByVaryingStart<SCEVSignExtendExpr>(Start, Step, L))
>>> {
>>> +        const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNSW);
>>> +        return getAddRecExpr(
>>> +            getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),
>>> +            getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
>>> +      }
>>>      }
>>>
>>>    // The cast wasn't folded; create an explicit cast node.
>>>
>>> Added: llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll?rev=231305&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll
>>> (added)
>>> +++ llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll Wed
>>> Mar  4 16:24:17 2015
>>> @@ -0,0 +1,44 @@
>>> +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s
>>> +
>>> +define void @f(i1* %condition) {
>>> +; CHECK-LABEL: Classifying expressions for: @f
>>> + entry:
>>> +  br label %loop
>>> +
>>> + loop:
>>> +  %idx = phi i32 [ 0, %entry ], [ %idx.inc, %loop ]
>>> +  %idx.inc = add nsw i32 %idx, 1
>>> +
>>> +  %idx.inc2 = add i32 %idx.inc, 1
>>> +  %idx.inc2.zext = zext i32 %idx.inc2 to i64
>>> +
>>> +; CHECK: %idx.inc2.zext = zext i32 %idx.inc2 to i64
>>> +; CHECK-NEXT: -->  {2,+,1}<nuw><%loop>
>>> +
>>> +  %c = load volatile i1, i1* %condition
>>> +  br i1 %c, label %loop, label %exit
>>> +
>>> + exit:
>>> +  ret void
>>> +}
>>> +
>>> +define void @g(i1* %condition) {
>>> +; CHECK-LABEL: Classifying expressions for: @g
>>> + entry:
>>> +  br label %loop
>>> +
>>> + loop:
>>> +  %idx = phi i32 [ 0, %entry ], [ %idx.inc, %loop ]
>>> +  %idx.inc = add nsw i32 %idx, 3
>>> +
>>> +  %idx.inc2 = add i32 %idx.inc, -1
>>> +  %idx.inc2.sext = sext i32 %idx.inc2 to i64
>>> +; CHECK: %idx.inc2.sext = sext i32 %idx.inc2 to i64
>>> +; CHECK-NEXT: -->  {2,+,3}<nuw><nsw><%loop>
>>> +
>>> +  %c = load volatile i1, i1* %condition
>>> +  br i1 %c, label %loop, label %exit
>>> +
>>> + exit:
>>> +  ret void
>>> +}
>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>>



More information about the llvm-commits mailing list