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 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_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: 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 +}