[ValueTracking] Use ConstantRange based overflow check for signed sub
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 21 Mar 2019 17:23:51 +0000 (17:23 +0000)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 21 Mar 2019 17:23:51 +0000 (17:23 +0000)
This is D59450, but for signed sub. This case is not NFC, because
the overflow logic in ConstantRange is more powerful than the existing
check. This resolves the TODO in the function.

I've added two tests to show that this indeed catches more cases than
the previous logic, but the main correctness test coverage here is in
the existing ConstantRange unit tests.

Differential Revision: https://reviews.llvm.org/D59617

llvm-svn: 356685

llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/InstCombine/sub.ll

index 52328b174b4405806db90e4d06c757223089b9ed..e31ddf0d646915cd1044396ae34e9d94cbec5861 100644 (file)
@@ -4190,17 +4190,12 @@ OverflowResult llvm::computeOverflowForSignedSub(const Value *LHS,
     return OverflowResult::NeverOverflows;
 
   KnownBits LHSKnown = computeKnownBits(LHS, DL, 0, AC, CxtI, DT);
-
   KnownBits RHSKnown = computeKnownBits(RHS, DL, 0, AC, CxtI, DT);
-
-  // Subtraction of two 2's complement numbers having identical signs will
-  // never overflow.
-  if ((LHSKnown.isNegative() && RHSKnown.isNegative()) ||
-      (LHSKnown.isNonNegative() && RHSKnown.isNonNegative()))
-    return OverflowResult::NeverOverflows;
-
-  // TODO: implement logic similar to checkRippleForAdd
-  return OverflowResult::MayOverflow;
+  ConstantRange LHSRange =
+      ConstantRange::fromKnownBits(LHSKnown, /*signed*/ true);
+  ConstantRange RHSRange =
+      ConstantRange::fromKnownBits(RHSKnown, /*signed*/ true);
+  return mapOverflowResult(LHSRange.signedSubMayOverflow(RHSRange));
 }
 
 bool llvm::isOverflowIntrinsicNoWrap(const IntrinsicInst *II,
index 9b10017b86e74f773caafd563e06c07430e66cca..2a9aa09cbbd38cc5e1ffe1ff20b9697281c7dadf 100644 (file)
@@ -1271,7 +1271,7 @@ define i32 @nsw_inference1(i32 %x, i32 %y) {
 ; CHECK-LABEL: @nsw_inference1(
 ; CHECK-NEXT:    [[X2:%.*]] = or i32 [[X:%.*]], 1024
 ; CHECK-NEXT:    [[Y2:%.*]] = and i32 [[Y:%.*]], 1
-; CHECK-NEXT:    [[Z:%.*]] = sub nuw i32 [[X2]], [[Y2]]
+; CHECK-NEXT:    [[Z:%.*]] = sub nuw nsw i32 [[X2]], [[Y2]]
 ; CHECK-NEXT:    ret i32 [[Z]]
 ;
   %x2 = or i32 %x, 1024
@@ -1284,7 +1284,7 @@ define i32 @nsw_inference2(i32 %x, i32 %y) {
 ; CHECK-LABEL: @nsw_inference2(
 ; CHECK-NEXT:    [[X2:%.*]] = and i32 [[X:%.*]], -1025
 ; CHECK-NEXT:    [[Y2:%.*]] = or i32 [[Y:%.*]], -2
-; CHECK-NEXT:    [[Z:%.*]] = sub i32 [[X2]], [[Y2]]
+; CHECK-NEXT:    [[Z:%.*]] = sub nsw i32 [[X2]], [[Y2]]
 ; CHECK-NEXT:    ret i32 [[Z]]
 ;
   %x2 = and i32 %x, -1025