<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 6, 2015 at 11:02 AM, Sanjoy Das <span dir="ltr"><<a href="mailto:sanjoy@playingwithpointers.com" target="_blank">sanjoy@playingwithpointers.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: sanjoy<br>
Date: Tue Jan 6 13:02:56 2015<br>
New Revision: 225282<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=225282&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=225282&view=rev</a><br>
Log:<br>
This patch teaches IndVarSimplify to add nuw and nsw to certain kinds<br>
of operations that provably don't overflow. For example, we can prove<br>
%civ.inc below does not sign-overflow. With this change,<br>
IndVarSimplify changes %civ.inc to an add nsw.<br>
<br>
define i32 @foo(i32* %array, i32* %length_ptr, i32 %init) {<br>
entry:<br>
%length = load i32* %length_ptr, !range !0<br>
%len.sub.1 = sub i32 %length, 1<br>
%upper = icmp slt i32 %init, %len.sub.1<br>
br i1 %upper, label %loop, label %exit<br>
<br>
loop:<br>
%civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
%civ.inc = add i32 %civ, 1<br>
%cmp = icmp slt i32 %civ.inc, %length<br>
br i1 %cmp, label %latch, label %break<br>
<br>
latch:<br>
store i32 0, i32* %array<br>
%check = icmp slt i32 %civ.inc, %len.sub.1<br>
br i1 %check, label %loop, label %break<br>
<br>
break:<br>
ret i32 %civ.inc<br>
<br>
exit:<br>
ret i32 42<br>
}<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D6748" target="_blank">http://reviews.llvm.org/D6748</a><br>
<br>
<br>
Added:<br>
llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll<br>
Modified:<br>
llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp<br>
llvm/trunk/test/Transforms/BBVectorize/loop1.ll<br>
llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll<br>
<br>
Modified: llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp?rev=225282&r1=225281&r2=225282&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp?rev=225282&r1=225281&r2=225282&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp Tue Jan 6 13:02:56 2015<br>
@@ -80,6 +80,7 @@ namespace {<br>
void eliminateIVComparison(ICmpInst *ICmp, Value *IVOperand);<br>
void eliminateIVRemainder(BinaryOperator *Rem, Value *IVOperand,<br>
bool IsSigned);<br>
+ bool strengthenOverflowingOperation(BinaryOperator *OBO, Value *IVOperand);<br>
<br>
Instruction *splitOverflowIntrinsic(Instruction *IVUser,<br>
const DominatorTree *DT);<br>
@@ -271,6 +272,120 @@ bool SimplifyIndvar::eliminateIVUser(Ins<br>
return true;<br>
}<br>
<br>
+/// Annotate BO with nsw / nuw if it provably does not signed-overflow /<br>
+/// unsigned-overflow. Returns true if anything changed, false otherwise.<br>
+bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO,<br>
+ Value *IVOperand) {<br>
+<br>
+ // Currently we only handle instructions of the form "add <indvar> <value>"<br>
+ // and "sub <indvar> <value>".<br>
+ unsigned Op = BO->getOpcode();<br>
+ if (!(Op == Instruction::Add || Op == Instruction::Sub))<br>
+ return false;<br>
+<br>
+ // If BO is already both nuw and nsw then there is nothing left to do<br>
+ if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())<br>
+ return false;<br>
+<br>
+ IntegerType *IT = cast<IntegerType>(IVOperand->getType());<br>
+ Value *OtherOperand = nullptr;<br>
+ int OtherOperandIdx = -1;<br>
+ if (BO->getOperand(0) == IVOperand) {<br>
+ OtherOperand = BO->getOperand(1);<br>
+ OtherOperandIdx = 1;<br>
+ } else {<br>
+ assert(BO->getOperand(1) == IVOperand && "only other use!");<br>
+ OtherOperand = BO->getOperand(0);<br>
+ OtherOperandIdx = 0;<br>
+ }<br>
+<br>
+ bool Changed = false;<br>
+ const SCEV *OtherOpSCEV = SE->getSCEV(OtherOperand);<br>
+ if (OtherOpSCEV == SE->getCouldNotCompute())<br>
+ return false;<br>
+<br>
+ if (Op == Instruction::Sub) {<br>
+ // If the subtraction is of the form "sub <indvar>, <op>", then pretend it<br>
+ // is "add <indvar>, -<op>" and continue, else bail out.<br>
+ if (OtherOperandIdx != 1)<br>
+ return false;<br>
+<br>
+ OtherOpSCEV = SE->getNegativeSCEV(OtherOpSCEV);<br>
+ }<br>
+<br>
+ const SCEV *IVOpSCEV = SE->getSCEV(IVOperand);<br>
+ const SCEV *ZeroSCEV = SE->getConstant(IVOpSCEV->getType(), 0);<br>
+<br>
+ if (!BO->hasNoSignedWrap()) {<br>
+ // Upgrade the add to an "add nsw" if we can prove that it will never<br>
+ // sign-overflow or sign-underflow.<br>
+<br>
+ const SCEV *SignedMax =<br>
+ SE->getConstant(APInt::getSignedMaxValue(IT->getBitWidth()));<br>
+ const SCEV *SignedMin =<br>
+ SE->getConstant(APInt::getSignedMinValue(IT->getBitWidth()));<br>
+<br>
+ // The addition "IVOperand + OtherOp" does not sign-overflow if the result<br>
+ // is sign-representable in 2's complement in the given bit-width.<br>
+ //<br>
+ // If OtherOp is SLT 0, then for an IVOperand in [SignedMin - OtherOp,<br>
+ // SignedMax], "IVOperand + OtherOp" is in [SignedMin, SignedMax + OtherOp].<br>
+ // Everything in [SignedMin, SignedMax + OtherOp] is representable since<br>
+ // SignedMax + OtherOp is at least -1.<br>
+ //<br>
+ // If OtherOp is SGE 0, then for an IVOperand in [SignedMin, SignedMax -<br>
+ // OtherOp], "IVOperand + OtherOp" is in [SignedMin + OtherOp, SignedMax].<br>
+ // Everything in [SignedMin + OtherOp, SignedMax] is representable since<br>
+ // SignedMin + OtherOp is at most -1.<br>
+ //<br>
+ // It follows that for all values of IVOperand in [SignedMin - smin(0,<br>
+ // OtherOp), SignedMax - smax(0, OtherOp)] the result of the add is<br>
+ // representable (i.e. there is no sign-overflow).<br>
+<br>
+ const SCEV *UpperDelta = SE->getSMaxExpr(ZeroSCEV, OtherOpSCEV);<br>
+ const SCEV *UpperLimit = SE->getMinusSCEV(SignedMax, UpperDelta);<br>
+<br>
+ bool NeverSignedOverflows =<br>
+ SE->isKnownPredicate(ICmpInst::ICMP_SLE, IVOpSCEV, UpperLimit);<br>
+<br>
+ if (NeverSignedOverflows) {<br>
+ const SCEV *LowerDelta = SE->getSMinExpr(ZeroSCEV, OtherOpSCEV);<br>
+ const SCEV *LowerLimit = SE->getMinusSCEV(SignedMin, LowerDelta);<br>
+<br>
+ bool NeverSignedUnderflows =<br>
+ SE->isKnownPredicate(ICmpInst::ICMP_SGE, IVOpSCEV, LowerLimit);<br>
+ if (NeverSignedUnderflows) {<br>
+ BO->setHasNoSignedWrap(true);<br>
+ Changed = true;<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+ if (!BO->hasNoUnsignedWrap()) {<br>
+ // Upgrade the add computing "IVOperand + OtherOp" to an "add nuw" if we can<br>
+ // prove that it will never unsigned-overflow (i.e. the result will always<br>
+ // be representable in the given bit-width).<br>
+ //<br>
+ // "IVOperand + OtherOp" is unsigned-representable in 2's complement iff it<br>
+ // does not produce a carry. "IVOperand + OtherOp" produces no carry iff<br>
+ // IVOperand ULE (UnsignedMax - OtherOp).<br>
+<br>
+ const SCEV *UnsignedMax =<br>
+ SE->getConstant(APInt::getMaxValue(IT->getBitWidth()));<br>
+ const SCEV *UpperLimit = SE->getMinusSCEV(UnsignedMax, OtherOpSCEV);<br>
+<br>
+ bool NeverUnsignedOverflows =<br>
+ SE->isKnownPredicate(ICmpInst::ICMP_ULE, IVOpSCEV, UpperLimit);<br>
+<br>
+ if (NeverUnsignedOverflows) {<br>
+ BO->setHasNoUnsignedWrap(true);<br>
+ Changed = true;<br>
+ }<br>
+ }<br>
+<br>
+ return Changed;<br>
+}<br>
+<br>
/// \brief Split sadd.with.overflow into add + sadd.with.overflow to allow<br>
/// analysis and optimization.<br>
///<br>
@@ -430,6 +545,16 @@ void SimplifyIndvar::simplifyUsers(PHINo<br>
pushIVUsers(IVOperand, Simplified, SimpleIVUsers);<br>
continue;<br>
}<br>
+<br>
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(UseOper.first)) {<br>
+ if (isa<OverflowingBinaryOperator>(BO) &&<br>
+ strengthenOverflowingOperation(BO, IVOperand)) {<br></blockquote><div><br></div><div><div>Any reason why you don't just do:</div><div>if (const auto *OBO = dyn_cast<OverflowingBinaryOperator>(BO))</div></div><div> if (strengthenOverflowingOperation(OBO, IVOperand))</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+ // re-queue uses of the now modified binary operator and fall<br>
+ // through to the checks that remain.<br>
+ pushIVUsers(IVOperand, Simplified, SimpleIVUsers);<br>
+ }<br>
+ }<br>
+<br>
CastInst *Cast = dyn_cast<CastInst>(UseOper.first);<br>
if (V && Cast) {<br>
V->visitCast(Cast);<br>
<br>
Modified: llvm/trunk/test/Transforms/BBVectorize/loop1.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BBVectorize/loop1.ll?rev=225282&r1=225281&r2=225282&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BBVectorize/loop1.ll?rev=225282&r1=225281&r2=225282&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/BBVectorize/loop1.ll (original)<br>
+++ llvm/trunk/test/Transforms/BBVectorize/loop1.ll Tue Jan 6 13:02:56 2015<br>
@@ -83,7 +83,7 @@ for.body:<br>
; CHECK-UNRL: %add12 = fadd <2 x double> %add7, %mul11<br>
; CHECK-UNRL: %4 = bitcast double* %arrayidx14 to <2 x double>*<br>
; CHECK-UNRL: store <2 x double> %add12, <2 x double>* %4, align 8<br>
-; CHECK-UNRL: %indvars.iv.next.1 = add i64 %indvars.iv, 2<br>
+; CHECK-UNRL: %indvars.iv.next.1 = add nsw i64 %indvars.iv, 2<br>
; CHECK-UNRL: %lftr.wideiv.1 = trunc i64 %indvars.iv.next.1 to i32<br>
; CHECK-UNRL: %exitcond.1 = icmp eq i32 %lftr.wideiv.1, 10<br>
; CHECK-UNRL: br i1 %exitcond.1, label %for.end, label %for.body<br>
<br>
Modified: llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll<br>
URL: <a href="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" target="_blank">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</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll (original)<br>
+++ llvm/trunk/test/Transforms/IndVarSimplify/2011-09-10-widen-nsw.ll Tue Jan 6 13:02:56 2015<br>
@@ -17,7 +17,7 @@ for.body11:<br>
for.body153: ; preds = %for.body153, %for.body11<br>
br i1 undef, label %for.body170, label %for.body153<br>
<br>
-; CHECK: add nsw i64 %indvars.iv, 1<br>
+; CHECK: add nuw nsw i64 %indvars.iv, 1<br>
; CHECK: sub nsw i64 %indvars.iv, 2<br>
; CHECK: sub nsw i64 4, %indvars.iv<br>
; CHECK: mul nsw i64 %indvars.iv, 8<br>
<br>
Added: llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll?rev=225282&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll?rev=225282&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll (added)<br>
+++ llvm/trunk/test/Transforms/IndVarSimplify/strengthen-overflow.ll Tue Jan 6 13:02:56 2015<br>
@@ -0,0 +1,214 @@<br>
+; RUN: opt < %s -indvars -S | FileCheck %s<br>
+<br>
+define i32 @test.signed.add.0(i32* %array, i32 %length, i32 %init) {<br>
+; CHECK-LABEL: @test.signed.add.0<br>
+ entry:<br>
+ %upper = icmp slt i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = add i32 %civ, 1<br>
+; CHECK: %civ.inc = add nsw i32 %civ, 1<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp slt i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+define i32 @test.signed.add.1(i32* %array, i32 %length, i32 %init) {<br>
+; CHECK-LABEL: @test.signed.add.1<br>
+ entry:<br>
+ %upper = icmp sle i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = add i32 %civ, 1<br>
+; CHECK: %civ.inc = add i32 %civ, 1<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp slt i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+define i32 @test.signed.sub.0(i32* %array, i32 %length, i32 %init) {<br>
+; CHECK-LABEL: @test.signed.sub.0<br>
+ entry:<br>
+ %upper = icmp sgt i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = sub i32 %civ, 1<br>
+; CHECK: %civ.inc = sub nsw i32 %civ, 1<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp sgt i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+define i32 @test.signed.sub.1(i32* %array, i32 %length, i32 %init) {<br>
+; CHECK-LABEL: @test.signed.sub.1<br>
+ entry:<br>
+ %upper = icmp sgt i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = sub i32 %civ, 1<br>
+; CHECK: %civ.inc = sub i32 %civ, 1<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp sge i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+define i32 @test.unsigned.add.0(i32* %array, i32 %length, i32 %init) {<br>
+; CHECK-LABEL: @test.unsigned.add.0<br>
+ entry:<br>
+ %upper = icmp ult i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = add i32 %civ, 1<br>
+; CHECK: %civ.inc = add nuw i32 %civ, 1<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp ult i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+define i32 @test.unsigned.add.1(i32* %array, i32 %length, i32 %init) {<br>
+; CHECK-LABEL: @test.unsigned.add.1<br>
+ entry:<br>
+ %upper = icmp ule i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = add i32 %civ, 1<br>
+; CHECK: %civ.inc = add i32 %civ, 1<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp ult i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+define i32 @test.unsigned.sub.0(i32* %array, i32* %length_ptr, i32 %init) {<br>
+; CHECK-LABEL: @test.unsigned.sub.0<br>
+ entry:<br>
+ %length = load i32* %length_ptr, !range !0<br>
+ %upper = icmp ult i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = sub i32 %civ, 2<br>
+; CHECK: %civ.inc = sub nuw i32 %civ, 2<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp ult i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+define i32 @test.unsigned.sub.1(i32* %array, i32* %length_ptr, i32 %init) {<br>
+; CHECK-LABEL: @test.unsigned.sub.1<br>
+ entry:<br>
+ %length = load i32* %length_ptr, !range !1<br>
+ %upper = icmp ult i32 %init, %length<br>
+ br i1 %upper, label %loop, label %exit<br>
+<br>
+ loop:<br>
+; CHECK-LABEL: loop<br>
+ %civ = phi i32 [ %init, %entry ], [ %civ.inc, %latch ]<br>
+ %civ.inc = sub i32 %civ, 2<br>
+; CHECK: %civ.inc = sub i32 %civ, 2<br>
+ %cmp = icmp slt i32 %civ.inc, %length<br>
+ br i1 %cmp, label %latch, label %break<br>
+<br>
+ latch:<br>
+ store i32 0, i32* %array<br>
+ %check = icmp ult i32 %civ.inc, %length<br>
+ br i1 %check, label %loop, label %break<br>
+<br>
+ break:<br>
+ ret i32 %civ.inc<br>
+<br>
+ exit:<br>
+ ret i32 42<br>
+}<br>
+<br>
+!0 = !{i32 0, i32 2}<br>
+!1 = !{i32 0, i32 42}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>