[ValueTracking] Improve mul handling in isKnownNonEqual()
authorNikita Popov <nikita.ppv@gmail.com>
Sun, 21 Mar 2021 17:36:20 +0000 (18:36 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Sun, 21 Mar 2021 17:41:35 +0000 (18:41 +0100)
X != X * C is true if:
 * C is not 0 or 1
 * X is not 0
 * mul is nsw or nuw

Proof: https://alive2.llvm.org/ce/z/uwF29z

This is motivated by one of the cases in D98422.

llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Analysis/ValueTracking/known-non-equal.ll

index 79399cf..b2f105f 100644 (file)
@@ -2530,6 +2530,19 @@ static bool isAddOfNonZero(const Value *V1, const Value *V2, unsigned Depth,
   return isKnownNonZero(Op, Depth + 1, Q);
 }
 
+/// Return true if V2 == V1 * C, where V1 is known non-zero, C is not 0/1 and
+/// the multiplication is nuw or nsw.
+static bool isNonEqualMul(const Value *V1, const Value *V2, unsigned Depth,
+                          const Query &Q) {
+  if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(V2)) {
+    const APInt *C;
+    return match(OBO, m_Mul(m_Specific(V1), m_APInt(C))) &&
+           (OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap()) &&
+           !C->isNullValue() && !C->isOneValue() &&
+           isKnownNonZero(V1, Depth + 1, Q);
+  }
+  return false;
+}
 
 /// Return true if it is known that V1 != V2.
 static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
@@ -2591,6 +2604,9 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
   if (isAddOfNonZero(V1, V2, Depth, Q) || isAddOfNonZero(V2, V1, Depth, Q))
     return true;
 
+  if (isNonEqualMul(V1, V2, Depth, Q) || isNonEqualMul(V2, V1, Depth, Q))
+    return true;
+
   if (V1->getType()->isIntOrIntVectorTy()) {
     // Are any known bits in V1 contradictory to known bits in V2? If V1
     // has a known zero where V2 has a known one, they must not be equal.
index bd50f60..362db26 100644 (file)
@@ -216,10 +216,7 @@ define i1 @mul_constantexpr(i16 %a) {
 
 define i1 @mul_nuw(i16 %x) {
 ; CHECK-LABEL: @mul_nuw(
-; CHECK-NEXT:    [[NZ:%.*]] = or i16 [[X:%.*]], 2
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[NZ]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[NZ]], [[MUL]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
   %nz = or i16 %x, 2
   %mul = mul nuw i16 %nz, 2
@@ -229,10 +226,7 @@ define i1 @mul_nuw(i16 %x) {
 
 define i1 @mul_nuw_comm(i16 %x) {
 ; CHECK-LABEL: @mul_nuw_comm(
-; CHECK-NEXT:    [[NZ:%.*]] = or i16 [[X:%.*]], 2
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[NZ]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[MUL]], [[NZ]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
   %nz = or i16 %x, 2
   %mul = mul nuw i16 %nz, 2
@@ -242,10 +236,7 @@ define i1 @mul_nuw_comm(i16 %x) {
 
 define i1 @mul_nsw(i16 %x) {
 ; CHECK-LABEL: @mul_nsw(
-; CHECK-NEXT:    [[NZ:%.*]] = or i16 [[X:%.*]], 2
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[NZ]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[NZ]], [[MUL]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
   %nz = or i16 %x, 2
   %mul = mul nsw i16 %nz, 2
@@ -255,10 +246,7 @@ define i1 @mul_nsw(i16 %x) {
 
 define i1 @mul_nsw_comm(i16 %x) {
 ; CHECK-LABEL: @mul_nsw_comm(
-; CHECK-NEXT:    [[NZ:%.*]] = or i16 [[X:%.*]], 2
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[NZ]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[MUL]], [[NZ]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
   %nz = or i16 %x, 2
   %mul = mul nsw i16 %nz, 2