[llvm] r225282 - This patch teaches IndVarSimplify to add nuw and nsw to certain kinds
Sanjoy Das
sanjoy at playingwithpointers.com
Tue Jan 6 12:16:51 PST 2015
That is what I tried initially, but OverflowingBinaryOperator is not a
BinaryOperator (AFAICT OverflowingBinaryOperator is an Operator while
BinaryOperator is an Instruction) or vice versa, so I'd have to check
for both independently anyway -- being one does not imply being the
other.
Operationally, checking for an OBO is pointless, because
strengthenOverflowingOperation will bail out if the opcode isn't Add
or Sub. But semantically I wanted to preserve the invariant that
strengthenOverflowingOperation is called only with instructions that
may overflow.
On Tue, Jan 6, 2015 at 11:42 AM, David Majnemer
<david.majnemer at gmail.com> wrote:
>
>
> 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
>
>
More information about the llvm-commits
mailing list