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

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 18 06:19:05 PDT 2024


Author: Yingwei Zheng
Date: 2024-10-18T21:19:02+08:00
New Revision: c89d731c5dc48e34ec4d081fce7e0c94e212b2f0

URL: https://github.com/llvm/llvm-project/commit/c89d731c5dc48e34ec4d081fce7e0c94e212b2f0
DIFF: https://github.com/llvm/llvm-project/commit/c89d731c5dc48e34ec4d081fce7e0c94e212b2f0.diff

LOG: [LVI] Infer non-zero from equality icmp (#112838)

This following pattern is common in loop headers:
```
  %101 = sub nuw i64 %78, %98
  %103 = icmp eq i64 %78, %98
  br i1 %103, label %.thread.i.i, label %.preheader.preheader.i.i

.preheader.preheader.i.i:
  %invariant.umin.i.i = call i64 @llvm.umin.i64(i64 %101, i64 9)
  %umax.i = call i64 @llvm.umax.i64(i64 %invariant.umin.i.i, i64 1)
  br label %.preheader.i.i

.preheader.i.i:
  ...
  %116 = add nuw nsw i64 %.011.i.i, 1
  %exitcond.not.i = icmp eq i64 %116, %umax.i
  br i1 %exitcond.not.i, label %.critedge.i.i, label %.preheader.i.i
```
As `%78` is not equal to `%98` in BB `.preheader.preheader.i.i`, we can
prove `%101` is non-zero. Then we can simplify the loop exit condition.

Addresses regression introduced by
https://github.com/llvm/llvm-project/pull/112742.

Added: 
    llvm/test/Transforms/CorrelatedValuePropagation/umax.ll

Modified: 
    llvm/lib/Analysis/LazyValueInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 10ad4708596cb3..42b04046ce10d3 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1188,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
new file mode 100644
index 00000000000000..4fca708c183815
--- /dev/null
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/umax.ll
@@ -0,0 +1,168 @@
+; 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:    ret i32 1
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+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_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_ptr
diff (ptr %x, ptr %y) {
+; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_ptr
diff (
+; 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:    ret i32 1
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %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
+}
+
+; 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