[llvm] r225282 - This patch teaches IndVarSimplify to add nuw and nsw to certain kinds

David Majnemer david.majnemer at gmail.com
Tue Jan 6 11:42:41 PST 2015


On Tue, Jan 6, 2015 at 11:02 AM, Sanjoy Das <sanjoy at playingwithpointers.com>
wrote:

> Author: sanjoy
> Date: Tue Jan  6 13:02:56 2015
> New Revision: 225282
>
> URL: http://llvm.org/viewvc/llvm-project?rev=225282&view=rev
> Log:
> This patch teaches IndVarSimplify to add nuw and nsw to certain kinds
> of operations that provably don't overflow. For example, we can prove
> %civ.inc below does not sign-overflow. With this change,
> IndVarSimplify changes %civ.inc to an add nsw.
>
>   define i32 @foo(i32* %array, i32* %length_ptr, i32 %init) {
>    entry:
>     %length = load i32* %length_ptr, !range !0
>     %len.sub.1 = sub i32 %length, 1
>     %upper = icmp slt i32 %init, %len.sub.1
>     br i1 %upper, label %loop, label %exit
>
>    loop:
>     %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
>     %civ.inc = add i32 %civ, 1
>     %cmp = icmp slt i32 %civ.inc, %length
>     br i1 %cmp, label %latch, label %break
>
>    latch:
>     store i32 0, i32* %array
>     %check = icmp slt i32 %civ.inc, %len.sub.1
>     br i1 %check, label %loop, label %break
>
>    break:
>     ret i32 %civ.inc
>
>    exit:
>     ret i32 42
>   }
>
> Differential Revision: http://reviews.llvm.org/D6748
>
>
> Added:
>     llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll
> Modified:
>     llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp
>     llvm/trunk/test/Transforms/BBVectorize/loop1.ll
>     llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll
>
> Modified: llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp?rev=225282&r1=225281&r2=225282&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp (original)
> +++ llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp Tue Jan  6 13:02:56
> 2015
> @@ -80,6 +80,7 @@ namespace {
>      void eliminateIVComparison(ICmpInst *ICmp, Value *IVOperand);
>      void eliminateIVRemainder(BinaryOperator *Rem, Value *IVOperand,
>                                bool IsSigned);
> +    bool strengthenOverflowingOperation(BinaryOperator *OBO, Value
> *IVOperand);
>
>      Instruction *splitOverflowIntrinsic(Instruction *IVUser,
>                                          const DominatorTree *DT);
> @@ -271,6 +272,120 @@ bool SimplifyIndvar::eliminateIVUser(Ins
>    return true;
>  }
>
> +/// Annotate BO with nsw / nuw if it provably does not signed-overflow /
> +/// unsigned-overflow.  Returns true if anything changed, false otherwise.
> +bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO,
> +                                                    Value *IVOperand) {
> +
> +  // Currently we only handle instructions of the form "add <indvar>
> <value>"
> +  // and "sub <indvar> <value>".
> +  unsigned Op = BO->getOpcode();
> +  if (!(Op == Instruction::Add || Op == Instruction::Sub))
> +    return false;
> +
> +  // If BO is already both nuw and nsw then there is nothing left to do
> +  if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
> +    return false;
> +
> +  IntegerType *IT = cast<IntegerType>(IVOperand->getType());
> +  Value *OtherOperand = nullptr;
> +  int OtherOperandIdx = -1;
> +  if (BO->getOperand(0) == IVOperand) {
> +    OtherOperand = BO->getOperand(1);
> +    OtherOperandIdx = 1;
> +  } else {
> +    assert(BO->getOperand(1) == IVOperand && "only other use!");
> +    OtherOperand = BO->getOperand(0);
> +    OtherOperandIdx = 0;
> +  }
> +
> +  bool Changed = false;
> +  const SCEV *OtherOpSCEV = SE->getSCEV(OtherOperand);
> +  if (OtherOpSCEV == SE->getCouldNotCompute())
> +    return false;
> +
> +  if (Op == Instruction::Sub) {
> +    // If the subtraction is of the form "sub <indvar>, <op>", then
> pretend it
> +    // is "add <indvar>, -<op>" and continue, else bail out.
> +    if (OtherOperandIdx != 1)
> +      return false;
> +
> +    OtherOpSCEV = SE->getNegativeSCEV(OtherOpSCEV);
> +  }
> +
> +  const SCEV *IVOpSCEV = SE->getSCEV(IVOperand);
> +  const SCEV *ZeroSCEV = SE->getConstant(IVOpSCEV->getType(), 0);
> +
> +  if (!BO->hasNoSignedWrap()) {
> +    // Upgrade the add to an "add nsw" if we can prove that it will never
> +    // sign-overflow or sign-underflow.
> +
> +    const SCEV *SignedMax =
> +      SE->getConstant(APInt::getSignedMaxValue(IT->getBitWidth()));
> +    const SCEV *SignedMin =
> +      SE->getConstant(APInt::getSignedMinValue(IT->getBitWidth()));
> +
> +    // The addition "IVOperand + OtherOp" does not sign-overflow if the
> result
> +    // is sign-representable in 2's complement in the given bit-width.
> +    //
> +    // If OtherOp is SLT 0, then for an IVOperand in [SignedMin - OtherOp,
> +    // SignedMax], "IVOperand + OtherOp" is in [SignedMin, SignedMax +
> OtherOp].
> +    // Everything in [SignedMin, SignedMax + OtherOp] is representable
> since
> +    // SignedMax + OtherOp is at least -1.
> +    //
> +    // If OtherOp is SGE 0, then for an IVOperand in [SignedMin,
> SignedMax -
> +    // OtherOp], "IVOperand + OtherOp" is in [SignedMin + OtherOp,
> SignedMax].
> +    // Everything in [SignedMin + OtherOp, SignedMax] is representable
> since
> +    // SignedMin + OtherOp is at most -1.
> +    //
> +    // It follows that for all values of IVOperand in [SignedMin - smin(0,
> +    // OtherOp), SignedMax - smax(0, OtherOp)] the result of the add is
> +    // representable (i.e. there is no sign-overflow).
> +
> +    const SCEV *UpperDelta = SE->getSMaxExpr(ZeroSCEV, OtherOpSCEV);
> +    const SCEV *UpperLimit = SE->getMinusSCEV(SignedMax, UpperDelta);
> +
> +    bool NeverSignedOverflows =
> +      SE->isKnownPredicate(ICmpInst::ICMP_SLE, IVOpSCEV, UpperLimit);
> +
> +    if (NeverSignedOverflows) {
> +      const SCEV *LowerDelta = SE->getSMinExpr(ZeroSCEV, OtherOpSCEV);
> +      const SCEV *LowerLimit = SE->getMinusSCEV(SignedMin, LowerDelta);
> +
> +      bool NeverSignedUnderflows =
> +        SE->isKnownPredicate(ICmpInst::ICMP_SGE, IVOpSCEV, LowerLimit);
> +      if (NeverSignedUnderflows) {
> +        BO->setHasNoSignedWrap(true);
> +        Changed = true;
> +      }
> +    }
> +  }
> +
> +  if (!BO->hasNoUnsignedWrap()) {
> +    // Upgrade the add computing "IVOperand + OtherOp" to an "add nuw" if
> we can
> +    // prove that it will never unsigned-overflow (i.e. the result will
> always
> +    // be representable in the given bit-width).
> +    //
> +    // "IVOperand + OtherOp" is unsigned-representable in 2's complement
> iff it
> +    // does not produce a carry.  "IVOperand + OtherOp" produces no carry
> iff
> +    // IVOperand ULE (UnsignedMax - OtherOp).
> +
> +    const SCEV *UnsignedMax =
> +      SE->getConstant(APInt::getMaxValue(IT->getBitWidth()));
> +    const SCEV *UpperLimit = SE->getMinusSCEV(UnsignedMax, OtherOpSCEV);
> +
> +    bool NeverUnsignedOverflows =
> +        SE->isKnownPredicate(ICmpInst::ICMP_ULE, IVOpSCEV, UpperLimit);
> +
> +    if (NeverUnsignedOverflows) {
> +      BO->setHasNoUnsignedWrap(true);
> +      Changed = true;
> +    }
> +  }
> +
> +  return Changed;
> +}
> +
>  /// \brief Split sadd.with.overflow into add + sadd.with.overflow to allow
>  /// analysis and optimization.
>  ///
> @@ -430,6 +545,16 @@ void SimplifyIndvar::simplifyUsers(PHINo
>        pushIVUsers(IVOperand, Simplified, SimpleIVUsers);
>        continue;
>      }
> +
> +    if (BinaryOperator *BO = dyn_cast<BinaryOperator>(UseOper.first)) {
> +      if (isa<OverflowingBinaryOperator>(BO) &&
> +          strengthenOverflowingOperation(BO, IVOperand)) {
>

Any reason why you don't just do:
if (const auto *OBO = dyn_cast<OverflowingBinaryOperator>(BO))
  if (strengthenOverflowingOperation(OBO, IVOperand))



> +        // re-queue uses of the now modified binary operator and fall
> +        // through to the checks that remain.
> +        pushIVUsers(IVOperand, Simplified, SimpleIVUsers);
> +      }
> +    }
> +
>      CastInst *Cast = dyn_cast<CastInst>(UseOper.first);
>      if (V && Cast) {
>        V->visitCast(Cast);
>
> Modified: llvm/trunk/test/Transforms/BBVectorize/loop1.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BBVectorize/loop1.ll?rev=225282&r1=225281&r2=225282&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Transforms/BBVectorize/loop1.ll (original)
> +++ llvm/trunk/test/Transforms/BBVectorize/loop1.ll Tue Jan  6 13:02:56
> 2015
> @@ -83,7 +83,7 @@ for.body:
>  ; CHECK-UNRL: %add12 = fadd <2 x double> %add7, %mul11
>  ; CHECK-UNRL: %4 = bitcast double* %arrayidx14 to <2 x double>*
>  ; CHECK-UNRL: store <2 x double> %add12, <2 x double>* %4, align 8
> -; CHECK-UNRL: %indvars.iv.next.1 = add i64 %indvars.iv, 2
> +; CHECK-UNRL: %indvars.iv.next.1 = add nsw i64 %indvars.iv, 2
>  ; CHECK-UNRL: %lftr.wideiv.1 = trunc i64 %indvars.iv.next.1 to i32
>  ; CHECK-UNRL: %exitcond.1 = icmp eq i32 %lftr.wideiv.1, 10
>  ; CHECK-UNRL: br i1 %exitcond.1, label %for.end, label %for.body
>
> Modified: llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll?rev=225282&r1=225281&r2=225282&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll
> (original)
> +++ llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll Tue
> Jan  6 13:02:56 2015
> @@ -17,7 +17,7 @@ for.body11:
>  for.body153:                                      ; preds = %for.body153,
> %for.body11
>    br i1 undef, label %for.body170, label %for.body153
>
> -; CHECK: add nsw i64 %indvars.iv, 1
> +; CHECK: add nuw nsw i64 %indvars.iv, 1
>  ; CHECK: sub nsw i64 %indvars.iv, 2
>  ; CHECK: sub nsw i64 4, %indvars.iv
>  ; CHECK: mul nsw i64 %indvars.iv, 8
>
> Added: llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll?rev=225282&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll
> (added)
> +++ llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll Tue
> Jan  6 13:02:56 2015
> @@ -0,0 +1,214 @@
> +; RUN: opt < %s -indvars -S | FileCheck %s
> +
> +define i32 @test.signed.add.0(i32* %array, i32 %length, i32 %init) {
> +; CHECK-LABEL: @test.signed.add.0
> + entry:
> +  %upper = icmp slt i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = add i32 %civ, 1
> +; CHECK: %civ.inc = add nsw i32 %civ, 1
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp slt i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +define i32 @test.signed.add.1(i32* %array, i32 %length, i32 %init) {
> +; CHECK-LABEL: @test.signed.add.1
> + entry:
> +  %upper = icmp sle i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = add i32 %civ, 1
> +; CHECK: %civ.inc = add i32 %civ, 1
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp slt i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +define i32 @test.signed.sub.0(i32* %array, i32 %length, i32 %init) {
> +; CHECK-LABEL: @test.signed.sub.0
> + entry:
> +  %upper = icmp sgt i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = sub i32 %civ, 1
> +; CHECK: %civ.inc = sub nsw i32 %civ, 1
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp sgt i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +define i32 @test.signed.sub.1(i32* %array, i32 %length, i32 %init) {
> +; CHECK-LABEL: @test.signed.sub.1
> + entry:
> +  %upper = icmp sgt i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = sub i32 %civ, 1
> +; CHECK: %civ.inc = sub i32 %civ, 1
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp sge i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +define i32 @test.unsigned.add.0(i32* %array, i32 %length, i32 %init) {
> +; CHECK-LABEL: @test.unsigned.add.0
> + entry:
> +  %upper = icmp ult i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = add i32 %civ, 1
> +; CHECK: %civ.inc = add nuw i32 %civ, 1
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp ult i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +define i32 @test.unsigned.add.1(i32* %array, i32 %length, i32 %init) {
> +; CHECK-LABEL: @test.unsigned.add.1
> + entry:
> +  %upper = icmp ule i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = add i32 %civ, 1
> +; CHECK: %civ.inc = add i32 %civ, 1
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp ult i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +define i32 @test.unsigned.sub.0(i32* %array, i32* %length_ptr, i32 %init)
> {
> +; CHECK-LABEL: @test.unsigned.sub.0
> + entry:
> +  %length = load i32* %length_ptr, !range !0
> +  %upper = icmp ult i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = sub i32 %civ, 2
> +; CHECK: %civ.inc = sub nuw i32 %civ, 2
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp ult i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +define i32 @test.unsigned.sub.1(i32* %array, i32* %length_ptr, i32 %init)
> {
> +; CHECK-LABEL: @test.unsigned.sub.1
> + entry:
> +  %length = load i32* %length_ptr, !range !1
> +  %upper = icmp ult i32 %init, %length
> +  br i1 %upper, label %loop, label %exit
> +
> + loop:
> +; CHECK-LABEL: loop
> +  %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]
> +  %civ.inc = sub i32 %civ, 2
> +; CHECK: %civ.inc = sub i32 %civ, 2
> +  %cmp = icmp slt i32 %civ.inc, %length
> +  br i1 %cmp, label %latch, label %break
> +
> + latch:
> +  store i32 0, i32* %array
> +  %check = icmp ult i32 %civ.inc, %length
> +  br i1 %check, label %loop, label %break
> +
> + break:
> +  ret i32 %civ.inc
> +
> + exit:
> +  ret i32 42
> +}
> +
> +!0 = !{i32 0, i32 2}
> +!1 = !{i32 0, i32 42}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150106/bbe12dcc/attachment.html>


More information about the llvm-commits mailing list