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

Sanjoy Das sanjoy at playingwithpointers.com
Wed Mar 4 16:40:48 PST 2015


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