[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