[llvm] Range assume bundles (PR #112758)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 17 11:55:55 PDT 2024


https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/112758

>From e872852412fc225134833899b38520324e0ce4c2 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Wed, 16 Oct 2024 20:04:00 +0200
Subject: [PATCH 1/7] [IR] Allow range assume bundles

---
 llvm/lib/Analysis/AssumeBundleQueries.cpp      | 18 +++++++++++++++---
 llvm/lib/IR/Verifier.cpp                       | 17 +++++++++++++++++
 llvm/test/Verifier/assume-bundles.ll           |  8 ++++++++
 .../Analysis/AssumeBundleQueriesTest.cpp       |  8 +++++---
 4 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/AssumeBundleQueries.cpp b/llvm/lib/Analysis/AssumeBundleQueries.cpp
index 21530693c5f180..229993a49e98ed 100644
--- a/llvm/lib/Analysis/AssumeBundleQueries.cpp
+++ b/llvm/lib/Analysis/AssumeBundleQueries.cpp
@@ -69,8 +69,14 @@ bool llvm::hasAttributeInAssume(AssumeInst &Assume, Value *IsOn,
 
 void llvm::fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result) {
   for (auto &Bundles : Assume.bundle_op_infos()) {
-    std::pair<Value *, Attribute::AttrKind> Key{
-        nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())};
+    Attribute::AttrKind AttrKind =
+        Attribute::getAttrKindFromName(Bundles.Tag->getKey());
+
+    if (!Attribute::isEnumAttrKind(AttrKind) &&
+        !Attribute::isIntAttrKind(AttrKind))
+      continue;
+
+    std::pair<Value *, Attribute::AttrKind> Key{nullptr, AttrKind};
     if (bundleHasArgument(Bundles, ABA_WasOn))
       Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn);
 
@@ -101,8 +107,14 @@ llvm::getKnowledgeFromBundle(AssumeInst &Assume,
   RetainedKnowledge Result;
   if (!DebugCounter::shouldExecute(AssumeQueryCounter))
     return Result;
+  Attribute::AttrKind AttrKind =
+      Attribute::getAttrKindFromName(BOI.Tag->getKey());
+
+  if (!Attribute::isEnumAttrKind(AttrKind) &&
+      !Attribute::isIntAttrKind(AttrKind))
+    return Result;
 
-  Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
+  Result.AttrKind = AttrKind;
   if (bundleHasArgument(BOI, ABA_WasOn))
     Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
   auto GetArgOr1 = [&](unsigned Idx) -> uint64_t {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index f34fe7594c8602..6388c7775e4856 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5416,6 +5416,23 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
                 "third argument should be an integer if present", Call);
         return;
       }
+      if (Kind == Attribute::Range) {
+        Check(ArgCount == 3, "range assumptions should have 3 arguments", Call);
+        Type *FirstType = Call.getOperand(Elem.Begin)->getType();
+        Check(FirstType->isIntOrIntVectorTy(),
+              "first argument should be an integer or vector of integers",
+              Call);
+        Type *ST = FirstType->getScalarType();
+        Check(Call.getOperand(Elem.Begin + 1)->getType() == ST,
+              "second argument should be an integer with same bit width as the "
+              "first argument",
+              Call);
+        Check(Call.getOperand(Elem.Begin + 2)->getType() == ST,
+              "third argument should be an integer with same bit width as the "
+              "first argument",
+              Call);
+        return;
+      }
       Check(ArgCount <= 2, "too many arguments", Call);
       if (Kind == Attribute::None)
         break;
diff --git a/llvm/test/Verifier/assume-bundles.ll b/llvm/test/Verifier/assume-bundles.ll
index afe6cc0ab4c674..717de735cf6538 100644
--- a/llvm/test/Verifier/assume-bundles.ll
+++ b/llvm/test/Verifier/assume-bundles.ll
@@ -28,5 +28,13 @@ define void @func(ptr %P, i32 %P1, ptr %P2, ptr %P3) {
   call void @llvm.assume(i1 true) ["separate_storage"(ptr %P)]
 ; CHECK: arguments to separate_storage assumptions should be pointers
   call void @llvm.assume(i1 true) ["separate_storage"(ptr %P, i32 123)]
+; CHECK: range assumptions should have 3 arguments
+  call void @llvm.assume(i1 true) ["range"(i32 %P1, i32 0)]
+; CHECK: first argument should be an integer or vector of integers
+  call void @llvm.assume(i1 true) ["range"(ptr %P, i32 %P1, i32 4)]
+; CHECK: second argument should be an integer with same bit width as the first argument
+  call void @llvm.assume(i1 true) ["range"(i32 %P1, ptr %P, i32 4)]
+; CHECK: third argument should be an integer with same bit width as the first argument
+  call void @llvm.assume(i1 true) ["range"(i32 %P1, i32 4, i8 10)]
   ret void
 }
diff --git a/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp b/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp
index 8ad15ca41510f2..47c4305c4c7739 100644
--- a/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp
+++ b/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp
@@ -411,8 +411,10 @@ static void RunRandTest(uint64_t Seed, int Size, int MinCount, int MaxCount,
   std::mt19937 Rng(Seed);
   std::uniform_int_distribution<int> DistCount(MinCount, MaxCount);
   std::uniform_int_distribution<unsigned> DistValue(0, MaxValue);
-  std::uniform_int_distribution<unsigned> DistAttr(0,
-                                                   Attribute::EndAttrKinds - 1);
+  std::uniform_int_distribution<unsigned> DistEnumAttr(Attribute::FirstEnumAttr,
+                                                       Attribute::LastEnumAttr);
+  std::uniform_int_distribution<unsigned> DistIntAttr(Attribute::FirstIntAttr,
+                                                      Attribute::LastIntAttr);
 
   std::unique_ptr<Module> Mod = std::make_unique<Module>("AssumeQueryAPI", C);
   if (!Mod)
@@ -449,7 +451,7 @@ static void RunRandTest(uint64_t Seed, int Size, int MinCount, int MaxCount,
   for (int i = 0; i < Size; i++) {
     int count = DistCount(Rng);
     int value = DistValue(Rng);
-    int attr = DistAttr(Rng);
+    int attr = count > 1 ? DistIntAttr(Rng) : DistEnumAttr(Rng);
     std::string str;
     raw_string_ostream ss(str);
     ss << Attribute::getNameFromAttrKind(

>From df32fd97538f20c6ab4dd9c1c9921e60f2e377b4 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Wed, 16 Oct 2024 21:11:39 +0200
Subject: [PATCH 2/7] [ValueTracking] Tests with range assume bundles (NFC)

---
 llvm/test/Analysis/BasicAA/range.ll           | 12 +++++
 .../Analysis/ValueTracking/known-non-zero.ll  | 52 +++++++++++++++++++
 .../InstSimplify/shift-knownbits.ll           | 45 ++++++++++++++++
 3 files changed, 109 insertions(+)

diff --git a/llvm/test/Analysis/BasicAA/range.ll b/llvm/test/Analysis/BasicAA/range.ll
index e5dfb60c8b8784..85a97c44cffba9 100644
--- a/llvm/test/Analysis/BasicAA/range.ll
+++ b/llvm/test/Analysis/BasicAA/range.ll
@@ -271,6 +271,18 @@ entry:
   ret i32 %load_
 }
 
+; CHECK-LABEL: Function: range_assume
+; CHECK: MayAlias: i32* %gep1, i32* %gep2
+define void @range_assume(ptr %s, ptr %q) {
+  %in_array = load i32, ptr %q
+  call void @llvm.assume(i1 true) ["range"(i32 %in_array, i32 0, i32 2)]
+  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 2
+  load i32, ptr %gep1
+  load i32, ptr %gep2
+  ret void
+}
+
 declare void @llvm.assume(i1)
 
 !0 = !{ i32 0, i32 2 }
diff --git a/llvm/test/Analysis/ValueTracking/known-non-zero.ll b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
index db2c4f3a1ed650..4699fdc0c58268 100644
--- a/llvm/test/Analysis/ValueTracking/known-non-zero.ll
+++ b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
@@ -1546,4 +1546,56 @@ define i1 @vec_reverse_non_zero_demanded_fail(<4 x i8> %xx) {
   ret i1 %r
 }
 
+define i1 @range_assume(i8 %x, i8 %y) {
+; CHECK-LABEL: @range_assume(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(i8 [[X:%.*]], i8 1, i8 0) ]
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[Y:%.*]], [[X]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  call void @llvm.assume(i1 true) ["range"(i8 %x, i8 1, i8 0)]
+  %or = or i8 %y, %x
+  %cmp = icmp eq i8 %or, 0
+  ret i1 %cmp
+}
+
+define i1 @neg_range_assum(i8 %x, i8 %y) {
+; CHECK-LABEL: @neg_range_assum(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(i8 [[X:%.*]], i8 -1, i8 1) ]
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[Y:%.*]], [[X]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  call void @llvm.assume(i1 true) ["range"(i8 %x, i8 -1, i8 1)]
+  %or = or i8 %y, %x
+  %cmp = icmp eq i8 %or, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @range_assum_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @range_assum_vec(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(<2 x i8> [[X:%.*]], i8 1, i8 0) ]
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[X]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  call void @llvm.assume(i1 true) ["range"(<2 x i8> %x, i8 1, i8 0)]
+  %or = or <2 x i8> %y, %x
+  %cmp = icmp ne <2 x i8> %or, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @neg_range_assum_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @neg_range_assum_vec(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(<2 x i8> [[X:%.*]], i8 -1, i8 1) ]
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[X]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  call void @llvm.assume(i1 true) ["range"(<2 x i8> %x, i8 -1, i8 1)]
+  %or = or <2 x i8> %y, %x
+  %cmp = icmp ne <2 x i8> %or, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
 declare i32 @llvm.experimental.get.vector.length.i32(i32, i32, i1)
diff --git a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
index 6bf03779379ec7..2c15e7ae2b593c 100644
--- a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
+++ b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
@@ -499,3 +499,48 @@ define <1 x i64> @bitcast_noshift_vector_wrong_type(<2 x float> %v1, <1 x i64> %
   %r = shl <1 x i64> %v2, %b
   ret <1 x i64> %r
 }
+
+define i32 @shl_amount_is_known_bogus_range_assum(i32 %a, i32 %b) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_assum(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(i32 [[B:%.*]], i32 32, i32 64) ]
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
+; CHECK-NEXT:    ret i32 [[SHL]]
+;
+  call void @llvm.assume(i1 true) ["range"(i32 %b, i32 32, i32 64)]
+  %shl = shl i32 %a, %b
+  ret i32 %shl
+}
+
+define i32 @neg_shl_amount_is_known_bogus_range_assum(i32 %a, i32 %b) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_assum(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(i32 [[B:%.*]], i32 0, i32 32) ]
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
+; CHECK-NEXT:    ret i32 [[SHL]]
+;
+  call void @llvm.assume(i1 true) ["range"(i32 %b, i32 0, i32 32)]
+  %shl = shl i32 %a, %b
+  ret i32 %shl
+}
+
+
+define <2 x i32> @shl_amount_is_known_bogus_range_assum_vec(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_assum_vec(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(<2 x i32> [[B:%.*]], i32 32, i32 64) ]
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
+; CHECK-NEXT:    ret <2 x i32> [[SHL]]
+;
+  call void @llvm.assume(i1 true) ["range"(<2 x i32> %b, i32 32, i32 64)]
+  %shl = shl <2 x i32> %a, %b
+  ret <2 x i32> %shl
+}
+
+define <2 x i32> @neg_shl_amount_is_known_bogus_range_assum_vec(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_assum_vec(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(<2 x i32> [[B:%.*]], i32 0, i32 32) ]
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
+; CHECK-NEXT:    ret <2 x i32> [[SHL]]
+;
+  call void @llvm.assume(i1 true) ["range"(<2 x i32> %b, i32 0, i32 32)]
+  %shl = shl <2 x i32> %a, %b
+  ret <2 x i32> %shl
+}

>From d6f1964ab18e9b1eb68f11b7cdfdc4ed9160544d Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Thu, 17 Oct 2024 18:46:17 +0200
Subject: [PATCH 3/7] [ValueTracking] Handle range assume bundles in
 isKnownNonZero

---
 .../llvm/Analysis/AssumeBundleQueries.h       |  5 +++++
 llvm/lib/Analysis/AssumeBundleQueries.cpp     | 19 +++++++++++++++++++
 llvm/lib/Analysis/ValueTracking.cpp           | 13 ++++++++++---
 .../Analysis/ValueTracking/known-non-zero.ll  |  8 ++------
 4 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/Analysis/AssumeBundleQueries.h b/llvm/include/llvm/Analysis/AssumeBundleQueries.h
index f7a893708758c5..56dc52134883f6 100644
--- a/llvm/include/llvm/Analysis/AssumeBundleQueries.h
+++ b/llvm/include/llvm/Analysis/AssumeBundleQueries.h
@@ -16,11 +16,13 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include <optional>
 
 namespace llvm {
 class AssumptionCache;
 class DominatorTree;
 class Instruction;
+class ConstantRange;
 
 /// Index of elements in the operand bundle.
 /// If the element exist it is guaranteed to be what is specified in this enum
@@ -170,6 +172,9 @@ RetainedKnowledge getKnowledgeValidInContext(
 RetainedKnowledge getKnowledgeFromBundle(AssumeInst &Assume,
                                          const CallBase::BundleOpInfo &BOI);
 
+std::optional<ConstantRange>
+getRangeFromBundle(AssumeInst &Assume, const CallBase::BundleOpInfo &BOI);
+
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/Analysis/AssumeBundleQueries.cpp b/llvm/lib/Analysis/AssumeBundleQueries.cpp
index 229993a49e98ed..0a20871d5d59b9 100644
--- a/llvm/lib/Analysis/AssumeBundleQueries.cpp
+++ b/llvm/lib/Analysis/AssumeBundleQueries.cpp
@@ -10,6 +10,7 @@
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/AssumptionCache.h"
 #include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -214,3 +215,21 @@ RetainedKnowledge llvm::getKnowledgeValidInContext(
                                 return isValidAssumeForContext(I, CtxI, DT);
                               });
 }
+
+std::optional<ConstantRange>
+llvm::getRangeFromBundle(AssumeInst &Assume,
+                         const CallBase::BundleOpInfo &BOI) {
+  if (Attribute::getAttrKindFromName(BOI.Tag->getKey()) != Attribute::Range)
+    return std::nullopt;
+
+  assert(BOI.End - BOI.Begin > ABA_Argument + 1 &&
+         "range assumptions should have 3 arguments");
+
+  if (auto *Lower = dyn_cast<ConstantInt>(
+          getValueFromBundleOpInfo(Assume, BOI, ABA_Argument)))
+    if (auto *Upper = dyn_cast<ConstantInt>(
+            getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + 1)))
+      if (Lower->getValue() != Upper->getValue())
+        return ConstantRange(Lower->getValue(), Upper->getValue());
+  return std::nullopt;
+}
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index e9ed8b3c862b55..b7612ff4c74629 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -595,18 +595,25 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
            "Got assumption for the wrong function!");
 
     if (Elem.Index != AssumptionCache::ExprResultIdx) {
-      if (!V->getType()->isPointerTy())
-        continue;
+      if (V->getType()->isPointerTy()) {
       if (RetainedKnowledge RK = getKnowledgeFromBundle(
               *I, I->bundle_op_info_begin()[Elem.Index])) {
         if (RK.WasOn == V &&
             (RK.AttrKind == Attribute::NonNull ||
              (RK.AttrKind == Attribute::Dereferenceable &&
-              !NullPointerIsDefined(Q.CxtI->getFunction(),
+                !NullPointerIsDefined(
+                    Q.CxtI->getFunction(),
                                     V->getType()->getPointerAddressSpace()))) &&
             isValidAssumeForContext(I, Q.CxtI, Q.DT))
           return true;
       }
+      } else if (V->getType()->isIntOrIntVectorTy()) {
+        if (std::optional<ConstantRange> Range =
+                getRangeFromBundle(*I, I->bundle_op_info_begin()[Elem.Index]))
+          if (!Range->contains(APInt::getZero(Range->getBitWidth())) &&
+              isValidAssumeForContext(I, Q.CxtI, Q.DT))
+            return true;
+      }
       continue;
     }
 
diff --git a/llvm/test/Analysis/ValueTracking/known-non-zero.ll b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
index 4699fdc0c58268..9a53bf4c1b1a8a 100644
--- a/llvm/test/Analysis/ValueTracking/known-non-zero.ll
+++ b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
@@ -1549,9 +1549,7 @@ define i1 @vec_reverse_non_zero_demanded_fail(<4 x i8> %xx) {
 define i1 @range_assume(i8 %x, i8 %y) {
 ; CHECK-LABEL: @range_assume(
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(i8 [[X:%.*]], i8 1, i8 0) ]
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[Y:%.*]], [[X]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[OR]], 0
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
   call void @llvm.assume(i1 true) ["range"(i8 %x, i8 1, i8 0)]
   %or = or i8 %y, %x
@@ -1575,9 +1573,7 @@ define i1 @neg_range_assum(i8 %x, i8 %y) {
 define <2 x i1> @range_assum_vec(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @range_assum_vec(
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(<2 x i8> [[X:%.*]], i8 1, i8 0) ]
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[X]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], zeroinitializer
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
 ;
   call void @llvm.assume(i1 true) ["range"(<2 x i8> %x, i8 1, i8 0)]
   %or = or <2 x i8> %y, %x

>From 989ac2d9e884f3412ceb5adbee586cac536358ca Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Thu, 17 Oct 2024 19:15:55 +0200
Subject: [PATCH 4/7] [ValueTracking] Handle range assume bundles in
 computeConstantRange

---
 llvm/lib/Analysis/ValueTracking.cpp | 12 +++++++++---
 llvm/test/Analysis/BasicAA/range.ll |  2 +-
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b7612ff4c74629..16fca9486143ca 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9913,11 +9913,17 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
     for (auto &AssumeVH : AC->assumptionsFor(V)) {
       if (!AssumeVH)
         continue;
-      CallInst *I = cast<CallInst>(AssumeVH);
+      AssumeInst *I = cast<AssumeInst>(AssumeVH);
       assert(I->getParent()->getParent() == CtxI->getParent()->getParent() &&
              "Got assumption for the wrong function!");
-      assert(I->getIntrinsicID() == Intrinsic::assume &&
-             "must be an assume intrinsic");
+
+      if (AssumeVH.Index != AssumptionCache::ExprResultIdx) {
+        if (std::optional<ConstantRange> Range = getRangeFromBundle(
+                *I, I->bundle_op_info_begin()[AssumeVH.Index]))
+          if (isValidAssumeForContext(I, CtxI, DT))
+            CR = CR.intersectWith(*Range);
+        continue;
+      }
 
       if (!isValidAssumeForContext(I, CtxI, DT))
         continue;
diff --git a/llvm/test/Analysis/BasicAA/range.ll b/llvm/test/Analysis/BasicAA/range.ll
index 85a97c44cffba9..760abd52ce6377 100644
--- a/llvm/test/Analysis/BasicAA/range.ll
+++ b/llvm/test/Analysis/BasicAA/range.ll
@@ -272,7 +272,7 @@ entry:
 }
 
 ; CHECK-LABEL: Function: range_assume
-; CHECK: MayAlias: i32* %gep1, i32* %gep2
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
 define void @range_assume(ptr %s, ptr %q) {
   %in_array = load i32, ptr %q
   call void @llvm.assume(i1 true) ["range"(i32 %in_array, i32 0, i32 2)]

>From 3ef8137f37ffebeb9803fbc40a0c922404a45fd7 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Thu, 17 Oct 2024 19:22:09 +0200
Subject: [PATCH 5/7] [ValueTracking] Handle range assume bundles in
 computeKnownBits

---
 llvm/lib/Analysis/ValueTracking.cpp           | 21 ++++++++++++-------
 .../InstSimplify/shift-knownbits.ll           |  6 ++----
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 16fca9486143ca..826d44dad512b8 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -831,17 +831,22 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
            "Got assumption for the wrong function!");
 
     if (Elem.Index != AssumptionCache::ExprResultIdx) {
-      if (!V->getType()->isPointerTy())
-        continue;
-      if (RetainedKnowledge RK = getKnowledgeFromBundle(
-              *I, I->bundle_op_info_begin()[Elem.Index])) {
+      if (V->getType()->isPointerTy()) {
+        if (RetainedKnowledge RK = getKnowledgeFromBundle(
+                *I, I->bundle_op_info_begin()[Elem.Index])) {
         // Allow AllowEphemerals in isValidAssumeForContext, as the CxtI might
         // be the producer of the pointer in the bundle. At the moment, align
         // assumptions aren't optimized away.
-        if (RK.WasOn == V && RK.AttrKind == Attribute::Alignment &&
-            isPowerOf2_64(RK.ArgValue) &&
-            isValidAssumeForContext(I, Q.CxtI, Q.DT, /*AllowEphemerals*/ true))
-          Known.Zero.setLowBits(Log2_64(RK.ArgValue));
+          if (RK.WasOn == V && RK.AttrKind == Attribute::Alignment &&
+              isPowerOf2_64(RK.ArgValue) &&
+              isValidAssumeForContext(I, Q.CxtI, Q.DT, /*AllowEphemerals*/ true))
+            Known.Zero.setLowBits(Log2_64(RK.ArgValue));
+        }
+      } else if (V->getType()->isIntOrIntVectorTy()) {
+        if (std::optional<ConstantRange> Range =
+                getRangeFromBundle(*I, I->bundle_op_info_begin()[Elem.Index]))
+          if (isValidAssumeForContext(I, Q.CxtI, Q.DT))
+            Known = Known.unionWith(Range->toKnownBits());
       }
       continue;
     }
diff --git a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
index 2c15e7ae2b593c..f6063425d86f4a 100644
--- a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
+++ b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
@@ -503,8 +503,7 @@ define <1 x i64> @bitcast_noshift_vector_wrong_type(<2 x float> %v1, <1 x i64> %
 define i32 @shl_amount_is_known_bogus_range_assum(i32 %a, i32 %b) {
 ; CHECK-LABEL: @shl_amount_is_known_bogus_range_assum(
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(i32 [[B:%.*]], i32 32, i32 64) ]
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
-; CHECK-NEXT:    ret i32 [[SHL]]
+; CHECK-NEXT:    ret i32 poison
 ;
   call void @llvm.assume(i1 true) ["range"(i32 %b, i32 32, i32 64)]
   %shl = shl i32 %a, %b
@@ -526,8 +525,7 @@ define i32 @neg_shl_amount_is_known_bogus_range_assum(i32 %a, i32 %b) {
 define <2 x i32> @shl_amount_is_known_bogus_range_assum_vec(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-LABEL: @shl_amount_is_known_bogus_range_assum_vec(
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "range"(<2 x i32> [[B:%.*]], i32 32, i32 64) ]
-; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
-; CHECK-NEXT:    ret <2 x i32> [[SHL]]
+; CHECK-NEXT:    ret <2 x i32> poison
 ;
   call void @llvm.assume(i1 true) ["range"(<2 x i32> %b, i32 32, i32 64)]
   %shl = shl <2 x i32> %a, %b

>From 9e63247b36e35915ead3e62241567c0e751b3f12 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Thu, 17 Oct 2024 20:54:24 +0200
Subject: [PATCH 6/7] fixup! [ValueTracking] Handle range assume bundles in
 isKnownNonZero

---
 llvm/lib/Analysis/ValueTracking.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 826d44dad512b8..1ab944ee68b801 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -596,17 +596,17 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
 
     if (Elem.Index != AssumptionCache::ExprResultIdx) {
       if (V->getType()->isPointerTy()) {
-      if (RetainedKnowledge RK = getKnowledgeFromBundle(
-              *I, I->bundle_op_info_begin()[Elem.Index])) {
-        if (RK.WasOn == V &&
-            (RK.AttrKind == Attribute::NonNull ||
-             (RK.AttrKind == Attribute::Dereferenceable &&
+        if (RetainedKnowledge RK = getKnowledgeFromBundle(
+                *I, I->bundle_op_info_begin()[Elem.Index])) {
+          if (RK.WasOn == V &&
+              (RK.AttrKind == Attribute::NonNull ||
+               (RK.AttrKind == Attribute::Dereferenceable &&
                 !NullPointerIsDefined(
                     Q.CxtI->getFunction(),
-                                    V->getType()->getPointerAddressSpace()))) &&
-            isValidAssumeForContext(I, Q.CxtI, Q.DT))
-          return true;
-      }
+                    V->getType()->getPointerAddressSpace()))) &&
+              isValidAssumeForContext(I, Q.CxtI, Q.DT))
+            return true;
+        }
       } else if (V->getType()->isIntOrIntVectorTy()) {
         if (std::optional<ConstantRange> Range =
                 getRangeFromBundle(*I, I->bundle_op_info_begin()[Elem.Index]))

>From 46fdb5d082352cb1c56846368fcdd0131243c2ad Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Thu, 17 Oct 2024 20:55:37 +0200
Subject: [PATCH 7/7] fixup! [ValueTracking] Handle range assume bundles in
 computeKnownBits

---
 llvm/lib/Analysis/ValueTracking.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 1ab944ee68b801..b9e0ec99285185 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -834,12 +834,13 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
       if (V->getType()->isPointerTy()) {
         if (RetainedKnowledge RK = getKnowledgeFromBundle(
                 *I, I->bundle_op_info_begin()[Elem.Index])) {
-        // Allow AllowEphemerals in isValidAssumeForContext, as the CxtI might
-        // be the producer of the pointer in the bundle. At the moment, align
-        // assumptions aren't optimized away.
+          // Allow AllowEphemerals in isValidAssumeForContext, as the CxtI might
+          // be the producer of the pointer in the bundle. At the moment, align
+          // assumptions aren't optimized away.
           if (RK.WasOn == V && RK.AttrKind == Attribute::Alignment &&
               isPowerOf2_64(RK.ArgValue) &&
-              isValidAssumeForContext(I, Q.CxtI, Q.DT, /*AllowEphemerals*/ true))
+              isValidAssumeForContext(I, Q.CxtI, Q.DT,
+                                      /*AllowEphemerals*/ true))
             Known.Zero.setLowBits(Log2_64(RK.ArgValue));
         }
       } else if (V->getType()->isIntOrIntVectorTy()) {



More information about the llvm-commits mailing list