Commit 42158f3e authored by David Majnemer's avatar David Majnemer
Browse files

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
parent 298f6380
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+18 −0
Original line number Diff line number Diff line
@@ -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;
}
+13 −1
Original line number Diff line number Diff line
@@ -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]]
}