[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