[llvm] [LVI] Infer non-zero from equality icmp (PR #112838)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 18 04:15:21 PDT 2024


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/112838

>From c34c8f96074deba1aa89a3f0d60583747e557f88 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 18 Oct 2024 12:44:24 +0800
Subject: [PATCH 1/3] [CVP] Add pre-commit tests. NFC.

---
 .../CorrelatedValuePropagation/umax.ll        | 62 +++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 llvm/test/Transforms/CorrelatedValuePropagation/umax.ll

diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll b/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
new file mode 100644
index 00000000000000..4fbf969c16ca4f
--- /dev/null
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
+
+target datalayout = "p:32:32"
+
+define i32 @infer_range_from_dom_equality(i32 %x, i32 %y) {
+; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX1]]
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX2]]
+;
+entry:
+  %cond = icmp eq i32 %x, %y
+  %sub = sub i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max1
+
+if.else:
+  %max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max2
+}
+
+define i32 @infer_range_from_dom_equality_ptrdiff(ptr %x, ptr %y) {
+; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_ptrdiff(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq ptr [[X]], [[Y]]
+; CHECK-NEXT:    [[XI:%.*]] = ptrtoint ptr [[X]] to i32
+; CHECK-NEXT:    [[YI:%.*]] = ptrtoint ptr [[Y]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[XI]], [[YI]]
+; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX1]]
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX2]]
+;
+  %cond = icmp eq ptr %x, %y
+  %xi = ptrtoint ptr %x to i32
+  %yi = ptrtoint ptr %y to i32
+  %sub = sub i32 %xi, %yi
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max1
+
+if.else:
+  %max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max2
+}

>From cee2b09ed337de5ed9e6b8f90c47372f291831f7 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 18 Oct 2024 12:53:57 +0800
Subject: [PATCH 2/3] [LVI] Infer non-zero from equality icmp

---
 llvm/lib/Analysis/LazyValueInfo.cpp                | 14 ++++++++++++++
 .../Transforms/CorrelatedValuePropagation/umax.ll  | 12 ++++--------
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 10ad4708596cb3..f29777a584772d 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1127,6 +1127,20 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
   if (!Ty->isIntegerTy())
     return ValueLatticeElement::getOverdefined();
 
+  // a - b or ptrtoint(a) - ptrtoint(b) ==/!= 0 if a ==/!= b
+  Value *X, *Y;
+  if (ICI->isEquality() && match(Val, m_Sub(m_Value(X), m_Value(Y)))) {
+    // Peek through ptrtoints
+    match(X, m_PtrToIntSameSize(DL, m_Value(X)));
+    match(Y, m_PtrToIntSameSize(DL, m_Value(Y)));
+    if ((X == LHS && Y == RHS) || (X == RHS && Y == LHS)) {
+      Constant *NullVal = Constant::getNullValue(Val->getType());
+      if (EdgePred == ICmpInst::ICMP_EQ)
+        return ValueLatticeElement::get(NullVal);
+      return ValueLatticeElement::getNot(NullVal);
+    }
+  }
+
   unsigned BitWidth = Ty->getScalarSizeInBits();
   APInt Offset(BitWidth, 0);
   if (matchICmpOperand(Offset, LHS, Val, EdgePred))
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll b/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
index 4fbf969c16ca4f..5cd615e948adbe 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
@@ -11,11 +11,9 @@ define i32 @infer_range_from_dom_equality(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
 ; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
 ; CHECK:       [[IF_THEN]]:
-; CHECK-NEXT:    [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
-; CHECK-NEXT:    ret i32 [[MAX1]]
+; CHECK-NEXT:    ret i32 1
 ; CHECK:       [[IF_ELSE]]:
-; CHECK-NEXT:    [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
-; CHECK-NEXT:    ret i32 [[MAX2]]
+; CHECK-NEXT:    ret i32 [[SUB]]
 ;
 entry:
   %cond = icmp eq i32 %x, %y
@@ -40,11 +38,9 @@ define i32 @infer_range_from_dom_equality_ptrdiff(ptr %x, ptr %y) {
 ; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[XI]], [[YI]]
 ; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
 ; CHECK:       [[IF_THEN]]:
-; CHECK-NEXT:    [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
-; CHECK-NEXT:    ret i32 [[MAX1]]
+; CHECK-NEXT:    ret i32 1
 ; CHECK:       [[IF_ELSE]]:
-; CHECK-NEXT:    [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
-; CHECK-NEXT:    ret i32 [[MAX2]]
+; CHECK-NEXT:    ret i32 [[SUB]]
 ;
   %cond = icmp eq ptr %x, %y
   %xi = ptrtoint ptr %x to i32

>From 2c3e039cdf9e4ea81391e4923f9932e2fe5e6653 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 18 Oct 2024 19:14:51 +0800
Subject: [PATCH 3/3] [LVI] Address review comments.

---
 llvm/lib/Analysis/LazyValueInfo.cpp           |  28 ++---
 .../CorrelatedValuePropagation/umax.ll        | 110 ++++++++++++++++++
 2 files changed, 124 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index f29777a584772d..42b04046ce10d3 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1127,20 +1127,6 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
   if (!Ty->isIntegerTy())
     return ValueLatticeElement::getOverdefined();
 
-  // a - b or ptrtoint(a) - ptrtoint(b) ==/!= 0 if a ==/!= b
-  Value *X, *Y;
-  if (ICI->isEquality() && match(Val, m_Sub(m_Value(X), m_Value(Y)))) {
-    // Peek through ptrtoints
-    match(X, m_PtrToIntSameSize(DL, m_Value(X)));
-    match(Y, m_PtrToIntSameSize(DL, m_Value(Y)));
-    if ((X == LHS && Y == RHS) || (X == RHS && Y == LHS)) {
-      Constant *NullVal = Constant::getNullValue(Val->getType());
-      if (EdgePred == ICmpInst::ICMP_EQ)
-        return ValueLatticeElement::get(NullVal);
-      return ValueLatticeElement::getNot(NullVal);
-    }
-  }
-
   unsigned BitWidth = Ty->getScalarSizeInBits();
   APInt Offset(BitWidth, 0);
   if (matchICmpOperand(Offset, LHS, Val, EdgePred))
@@ -1202,6 +1188,20 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
       return ValueLatticeElement::getRange(*CR);
   }
 
+  // a - b or ptrtoint(a) - ptrtoint(b) ==/!= 0 if a ==/!= b
+  Value *X, *Y;
+  if (ICI->isEquality() && match(Val, m_Sub(m_Value(X), m_Value(Y)))) {
+    // Peek through ptrtoints
+    match(X, m_PtrToIntSameSize(DL, m_Value(X)));
+    match(Y, m_PtrToIntSameSize(DL, m_Value(Y)));
+    if ((X == LHS && Y == RHS) || (X == RHS && Y == LHS)) {
+      Constant *NullVal = Constant::getNullValue(Val->getType());
+      if (EdgePred == ICmpInst::ICMP_EQ)
+        return ValueLatticeElement::get(NullVal);
+      return ValueLatticeElement::getNot(NullVal);
+    }
+  }
+
   return ValueLatticeElement::getOverdefined();
 }
 
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll b/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
index 5cd615e948adbe..4fca708c183815 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
@@ -29,6 +29,58 @@ if.else:
   ret i32 %max2
 }
 
+define i32 @infer_range_from_dom_equality_commuted1(i32 %x, i32 %y) {
+; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_commuted1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[Y]], [[X]]
+; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    ret i32 1
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+entry:
+  %cond = icmp eq i32 %x, %y
+  %sub = sub i32 %y, %x
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max1
+
+if.else:
+  %max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max2
+}
+
+define i32 @infer_range_from_dom_equality_commuted2(i32 %x, i32 %y) {
+; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_commuted2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    ret i32 1
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+entry:
+  %cond = icmp eq i32 %y, %x
+  %sub = sub i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max1
+
+if.else:
+  %max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max2
+}
+
 define i32 @infer_range_from_dom_equality_ptrdiff(ptr %x, ptr %y) {
 ; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_ptrdiff(
 ; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]]) {
@@ -56,3 +108,61 @@ if.else:
   %max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
   ret i32 %max2
 }
+
+; Negative tests
+
+define i32 @infer_range_from_dom_slt(i32 %x, i32 %y) {
+; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_slt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX1]]
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX2]]
+;
+entry:
+  %cond = icmp slt i32 %x, %y
+  %sub = sub i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max1
+
+if.else:
+  %max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max2
+}
+
+define i32 @infer_range_from_dom_equality_not_match(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_not_match(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[X]], [[Z]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX1]]
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
+; CHECK-NEXT:    ret i32 [[MAX2]]
+;
+entry:
+  %cond = icmp eq i32 %x, %z
+  %sub = sub i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max1
+
+if.else:
+  %max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
+  ret i32 %max2
+}



More information about the llvm-commits mailing list