InstCombine: Annotate sub with nuw when we prove it's safe

We can prove that a 'sub' can be a 'sub nuw' if the left-hand side is
negative and the right-hand side is non-negative.

llvm-svn: 216045
This commit is contained in:
David Majnemer 2014-08-20 07:17:31 +00:00
parent 298f63803b
commit 42158f3eea
3 changed files with 32 additions and 1 deletions

View File

@ -251,6 +251,7 @@ private:
bool WillNotOverflowSignedAdd(Value *LHS, Value *RHS);
bool WillNotOverflowUnsignedAdd(Value *LHS, Value *RHS);
bool WillNotOverflowSignedSub(Value *LHS, Value *RHS);
bool WillNotOverflowUnsignedSub(Value *LHS, Value *RHS);
Value *EmitGEPOffset(User *GEP);
Instruction *scalarizePHI(ExtractElementInst &EI, PHINode *PN);
Value *EvaluateInDifferentElementOrder(Value *V, ArrayRef<int> Mask);

View File

@ -988,6 +988,20 @@ bool InstCombiner::WillNotOverflowSignedSub(Value *LHS, Value *RHS) {
return false;
}
/// \brief Return true if we can prove that:
/// (sub LHS, RHS) === (sub nuw LHS, RHS)
bool InstCombiner::WillNotOverflowUnsignedSub(Value *LHS, Value *RHS) {
// If the LHS is negative and the RHS is non-negative, no unsigned wrap.
bool LHSKnownNonNegative, LHSKnownNegative;
bool RHSKnownNonNegative, RHSKnownNegative;
ComputeSignBit(LHS, LHSKnownNonNegative, LHSKnownNegative, DL, 0);
ComputeSignBit(RHS, RHSKnownNonNegative, RHSKnownNegative, DL, 0);
if (LHSKnownNegative && RHSKnownNonNegative)
return true;
return false;
}
// Checks if any operand is negative and we can convert add to sub.
// This function checks for following negative patterns
// ADD(XOR(OR(Z, NOT(C)), C)), 1) == NEG(AND(Z, C))
@ -1660,6 +1674,10 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
Changed = true;
I.setHasNoSignedWrap(true);
}
if (!I.hasNoUnsignedWrap() && WillNotOverflowUnsignedSub(Op0, Op1)) {
Changed = true;
I.setHasNoUnsignedWrap(true);
}
return Changed ? &I : nullptr;
}

View File

@ -506,6 +506,18 @@ define i4 @test42(i4 %x, i4 %y) {
; CHECK-LABEL: @test42(
; CHECK-NEXT: [[AND:%.*]] = and i4 %y, 7
; CHECK-NEXT: [[AND1:%.*]] = and i4 %x, 7
; CHECK-NEXT: [[RET:%.*]] = sub nsw i4 %a, %b
; CHECK-NEXT: [[RET:%.*]] = sub nsw i4 [[AND]], [[AND1]]
; CHECK: ret i4 [[RET]]
}
define i4 @test43(i4 %x, i4 %y) {
%a = or i4 %x, -8
%b = and i4 %y, 7
%c = sub i4 %a, %b
ret i4 %c
; CHECK-LABEL: @test43(
; CHECK-NEXT: [[OR:%.*]] = or i4 %x, -8
; CHECK-NEXT: [[AND:%.*]] = and i4 %y, 7
; CHECK-NEXT: [[RET:%.*]] = sub nuw i4 [[OR]], [[AND]]
; CHECK: ret i4 [[RET]]
}