[llvm] af656a8 - [LVI] Learn value ranges from ctpop results (#121945)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 15 00:53:35 PST 2025


Author: Stephen Senran Zhang
Date: 2025-01-15T09:53:31+01:00
New Revision: af656a8d4245069f70f5b5e1f654ec9291d3b0a3

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

LOG: [LVI] Learn value ranges from ctpop results (#121945)

Fixes #115751.

Added: 
    llvm/test/Transforms/CorrelatedValuePropagation/ctpop-range.ll

Modified: 
    llvm/lib/Analysis/LazyValueInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 349a0a1a2d3c42..20f69a0955f51c 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1159,6 +1159,27 @@ getRangeViaSLT(CmpInst::Predicate Pred, APInt RHS,
   return std::nullopt;
 }
 
+/// Get value range for a "ctpop(Val) Pred RHS" condition.
+static ValueLatticeElement getValueFromICmpCtpop(ICmpInst::Predicate Pred,
+                                                 Value *RHS) {
+  unsigned BitWidth = RHS->getType()->getScalarSizeInBits();
+
+  auto *RHSConst = dyn_cast<ConstantInt>(RHS);
+  if (!RHSConst)
+    return ValueLatticeElement::getOverdefined();
+
+  ConstantRange ResValRange =
+      ConstantRange::makeExactICmpRegion(Pred, RHSConst->getValue());
+
+  unsigned ResMin = ResValRange.getUnsignedMin().getLimitedValue(BitWidth);
+  unsigned ResMax = ResValRange.getUnsignedMax().getLimitedValue(BitWidth);
+
+  APInt ValMin = APInt::getLowBitsSet(BitWidth, ResMin);
+  APInt ValMax = APInt::getHighBitsSet(BitWidth, ResMax);
+  return ValueLatticeElement::getRange(
+      ConstantRange::getNonEmpty(std::move(ValMin), ValMax + 1));
+}
+
 std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
     Value *Val, ICmpInst *ICI, bool isTrueDest, bool UseBlockValue) {
   Value *LHS = ICI->getOperand(0);
@@ -1192,6 +1213,9 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
     return getValueFromSimpleICmpCondition(SwappedPred, LHS, Offset, ICI,
                                            UseBlockValue);
 
+  if (match(LHS, m_Intrinsic<Intrinsic::ctpop>(m_Specific(Val))))
+    return getValueFromICmpCtpop(EdgePred, RHS);
+
   const APInt *Mask, *C;
   if (match(LHS, m_And(m_Specific(Val), m_APInt(Mask))) &&
       match(RHS, m_APInt(C))) {

diff  --git a/llvm/test/Transforms/CorrelatedValuePropagation/ctpop-range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/ctpop-range.ll
new file mode 100644
index 00000000000000..7101244dff4c45
--- /dev/null
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/ctpop-range.ll
@@ -0,0 +1,142 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=correlated-propagation %s | FileCheck %s
+
+declare void @use(i1)
+
+define void @ctpop1(i8 %v) {
+; CHECK-LABEL: define void @ctpop1(
+; CHECK-SAME: i8 [[V:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[RES:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[V]])
+; CHECK-NEXT:    [[C0_0:%.*]] = icmp samesign uge i8 [[RES]], 3
+; CHECK-NEXT:    [[C0_1:%.*]] = icmp samesign ule i8 [[RES]], 7
+; CHECK-NEXT:    [[C0:%.*]] = and i1 [[C0_0]], [[C0_1]]
+; CHECK-NEXT:    br i1 [[C0]], label %[[RANGE_3_8:.*]], label %[[ED:.*]]
+; CHECK:       [[RANGE_3_8]]:
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 [[V]], 8
+; CHECK-NEXT:    call void @use(i1 [[CMP1]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp ule i8 [[V]], -3
+; CHECK-NEXT:    call void @use(i1 [[CMP3]])
+; CHECK-NEXT:    ret void
+; CHECK:       [[ED]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %res = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 %v)
+  %c0.0 = icmp uge i8 %res, 3
+  %c0.1 = icmp ule i8 %res, 7
+  %c0 = and i1 %c0.0, %c0.1
+  br i1 %c0, label %range.3.8, label %ed
+
+range.3.8:
+  %cmp0 = icmp uge i8 %v, 7
+  call void @use(i1 %cmp0) ; true
+  %cmp1 = icmp uge i8 %v, 8
+  call void @use(i1 %cmp1) ; unknown
+  %cmp2 = icmp ule i8 %v, 254
+  call void @use(i1 %cmp2) ; true
+  %cmp3 = icmp ule i8 %v, 253
+  call void @use(i1 %cmp3) ; unknown
+  ret void
+
+ed:
+  ret void
+}
+
+define void @ctpop2(i8 %v) {
+; CHECK-LABEL: define void @ctpop2(
+; CHECK-SAME: i8 [[V:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[RES:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[V]])
+; CHECK-NEXT:    [[C2_0:%.*]] = icmp samesign uge i8 [[RES]], 1
+; CHECK-NEXT:    [[C2_1:%.*]] = icmp samesign ule i8 [[RES]], 4
+; CHECK-NEXT:    [[C2:%.*]] = and i1 [[C2_0]], [[C2_1]]
+; CHECK-NEXT:    br i1 [[C2]], label %[[RANGE_1_5:.*]], label %[[ED:.*]]
+; CHECK:       [[RANGE_1_5]]:
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[CMP9:%.*]] = icmp uge i8 [[V]], 2
+; CHECK-NEXT:    call void @use(i1 [[CMP9]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[CMP11:%.*]] = icmp ule i8 [[V]], -17
+; CHECK-NEXT:    call void @use(i1 [[CMP11]])
+; CHECK-NEXT:    ret void
+; CHECK:       [[ED]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %res = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 %v)
+  %c2.0 = icmp uge i8 %res, 1
+  %c2.1 = icmp ule i8 %res, 4
+  %c2 = and i1 %c2.0, %c2.1
+  br i1 %c2, label %range.1.5, label %ed
+
+range.1.5:
+  %cmp8 = icmp uge i8 %v, 1
+  call void @use(i1 %cmp8) ; true
+  %cmp9 = icmp uge i8 %v, 2
+  call void @use(i1 %cmp9) ; unknown
+  %cmp10 = icmp ule i8 %v, 240
+  call void @use(i1 %cmp10) ; true
+  %cmp11 = icmp ule i8 %v, 239
+  call void @use(i1 %cmp11) ; unknown
+  ret void
+
+ed:
+  ret void
+}
+
+define void @ctpop3(i8 %v) {
+; CHECK-LABEL: define void @ctpop3(
+; CHECK-SAME: i8 [[V:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[RES:%.*]] = call i8 @llvm.ctpop.i8(i8 [[V]])
+; CHECK-NEXT:    [[C3:%.*]] = icmp samesign uge i8 [[RES]], 8
+; CHECK-NEXT:    br i1 [[C3]], label %[[RANGE_8_9:.*]], label %[[ED:.*]]
+; CHECK:       [[RANGE_8_9]]:
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    ret void
+; CHECK:       [[ED]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %res = call i8 @llvm.ctpop.i8(i8 %v)
+  %c3 = icmp uge i8 %res, 8
+  br i1 %c3, label %range.8.9, label %ed
+
+range.8.9:
+  %cmp4 = icmp eq i8 %v, -1
+  call void @use(i1 %cmp4) ; true
+  ret void
+
+ed:
+  ret void
+}
+
+define void @ctpop4(i8 %v) {
+; CHECK-LABEL: define void @ctpop4(
+; CHECK-SAME: i8 [[V:%.*]]) {
+; CHECK-NEXT:  [[TEST4:.*:]]
+; CHECK-NEXT:    [[RES:%.*]] = call i8 @llvm.ctpop.i8(i8 [[V]])
+; CHECK-NEXT:    [[C4:%.*]] = icmp eq i8 [[RES]], 0
+; CHECK-NEXT:    br i1 [[C4]], label %[[RANGE_0_1:.*]], label %[[ED:.*]]
+; CHECK:       [[RANGE_0_1]]:
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    ret void
+; CHECK:       [[ED]]:
+; CHECK-NEXT:    ret void
+;
+test4:
+  %res = call i8 @llvm.ctpop.i8(i8 %v)
+  %c4 = icmp eq i8 %res, 0
+  br i1 %c4, label %range.0.1, label %ed
+
+range.0.1:
+  %cmp5 = icmp eq i8 %v, 0
+  call void @use(i1 %cmp5) ; true
+  ret void
+
+ed:
+  ret void
+}


        


More information about the llvm-commits mailing list