[llvm] [ValueTracking] Handle range attributes (PR #85143)
Andreas Jonson via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 19 14:18:48 PDT 2024
https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/85143
>From 87d14b1bae3c02e2747ad004a6007e565aed294b Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 16 Mar 2024 15:39:25 +0100
Subject: [PATCH 1/5] Add helper functions to get range attribute
---
llvm/include/llvm/IR/Argument.h | 7 +++++++
llvm/include/llvm/IR/InstrTypes.h | 7 ++++++-
llvm/lib/Analysis/InstructionSimplify.cpp | 13 ++++---------
llvm/lib/IR/Function.cpp | 8 ++++++++
llvm/lib/IR/Instructions.cpp | 8 ++++++++
5 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/IR/Argument.h b/llvm/include/llvm/IR/Argument.h
index f0c0ce75d2b7e1..3349f1306970eb 100644
--- a/llvm/include/llvm/IR/Argument.h
+++ b/llvm/include/llvm/IR/Argument.h
@@ -16,9 +16,12 @@
#include "llvm/ADT/Twine.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Value.h"
+#include <optional>
namespace llvm {
+class ConstantRange;
+
/// This class represents an incoming formal argument to a Function. A formal
/// argument, since it is ``formal'', does not contain an actual value but
/// instead represents the type, argument number, and attributes of an argument
@@ -67,6 +70,10 @@ class Argument final : public Value {
/// disallowed floating-point values. Otherwise, fcNone is returned.
FPClassTest getNoFPClass() const;
+ /// If this argument has a range attribute, return the value range of the
+ /// argument. Otherwise, std::nullopt is returned.
+ std::optional<ConstantRange> getRange() const;
+
/// Return true if this argument has the byval attribute.
bool hasByValAttr() const;
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index fed21b992e3d10..e8c2cba8418dc8 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -43,6 +43,7 @@ namespace llvm {
class StringRef;
class Type;
class Value;
+class ConstantRange;
namespace Intrinsic {
typedef unsigned ID;
@@ -1917,7 +1918,7 @@ class CallBase : public Instruction {
// Look at the callee, if available.
if (const Function *F = getCalledFunction())
- return F->getAttributes().getRetAttr(Kind);
+ return F->getRetAttribute(Kind);
return Attribute();
}
@@ -2154,6 +2155,10 @@ class CallBase : public Instruction {
/// parameter.
FPClassTest getParamNoFPClass(unsigned i) const;
+ /// If this return value has a range attribute, return the value range of the
+ /// argument. Otherwise, std::nullopt is returned.
+ std::optional<ConstantRange> getRange() const;
+
/// Return true if the return value is known to be not null.
/// This may be because it has the nonnull attribute, or because at least
/// one byte is dereferenceable and the pointer is in addrspace(0).
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 06283cb4bb934b..7a37ae86c7f3c0 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3736,15 +3736,10 @@ static std::optional<ConstantRange> getRange(Value *V,
if (MDNode *MD = IIQ.getMetadata(I, LLVMContext::MD_range))
return getConstantRangeFromMetadata(*MD);
- Attribute Range;
- if (const Argument *A = dyn_cast<Argument>(V)) {
- Range = A->getAttribute(llvm::Attribute::Range);
- } else if (const CallBase *CB = dyn_cast<CallBase>(V)) {
- Range = CB->getRetAttr(llvm::Attribute::Range);
- }
-
- if (Range.isValid())
- return Range.getRange();
+ if (const Argument *A = dyn_cast<Argument>(V))
+ return A->getRange();
+ else if (const CallBase *CB = dyn_cast<CallBase>(V))
+ return CB->getRange();
return std::nullopt;
}
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index d22e1c12311189..eb126f182eadcb 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -24,6 +24,7 @@
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
+#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
@@ -256,6 +257,13 @@ FPClassTest Argument::getNoFPClass() const {
return getParent()->getParamNoFPClass(getArgNo());
}
+std::optional<ConstantRange> Argument::getRange() const {
+ const Attribute RangeAttr = getAttribute(llvm::Attribute::Range);
+ if (RangeAttr.isValid())
+ return RangeAttr.getRange();
+ return std::nullopt;
+}
+
bool Argument::hasNestAttr() const {
if (!getType()->isPointerTy()) return false;
return hasAttribute(Attribute::Nest);
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index c55d6cff84ed55..494d50f89e374c 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -19,6 +19,7 @@
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
+#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
@@ -395,6 +396,13 @@ FPClassTest CallBase::getParamNoFPClass(unsigned i) const {
return Mask;
}
+std::optional<ConstantRange> CallBase::getRange() const {
+ const Attribute RangeAttr = getRetAttr(llvm::Attribute::Range);
+ if (RangeAttr.isValid())
+ return RangeAttr.getRange();
+ return std::nullopt;
+}
+
bool CallBase::isReturnNonNull() const {
if (hasRetAttr(Attribute::NonNull))
return true;
>From 7180453bfa318677a64c483a5bc0f2b124086dbe Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 17 Mar 2024 12:03:32 +0100
Subject: [PATCH 2/5] pre-commit tests for range attributes in valuetracking
---
.../Analysis/ValueTracking/known-non-zero.ll | 159 ++++++++++++++++++
.../Transforms/InstSimplify/icmp-constant.ll | 134 +++++++++++++++
.../InstSimplify/shift-knownbits.ll | 144 ++++++++++++++++
3 files changed, 437 insertions(+)
diff --git a/llvm/test/Analysis/ValueTracking/known-non-zero.ll b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
index 30d340dc725a3e..a15a787353abc1 100644
--- a/llvm/test/Analysis/ValueTracking/known-non-zero.ll
+++ b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
@@ -1303,4 +1303,163 @@ define <2 x i1> @range_metadata_vec(ptr %p, <2 x i32> %x) {
ret <2 x i1> %cmp
}
+define i1 @range_attr(i8 range(i8 1, 0) %x, i8 %y) {
+; CHECK-LABEL: @range_attr(
+; CHECK-NEXT: [[I:%.*]] = or i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %or = or i8 %y, %x
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+}
+
+define i1 @neg_range_attr(i8 range(i8 -1, 1) %x, i8 %y) {
+; CHECK-LABEL: @neg_range_attr(
+; CHECK-NEXT: [[I:%.*]] = or i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %or = or i8 %y, %x
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+}
+
+declare range(i8 1, 0) i8 @returns_non_zero_range_helper()
+declare range(i8 -1, 1) i8 @returns_contain_zero_range_helper()
+
+define i1 @range_return(i8 %y) {
+; CHECK-LABEL: @range_return(
+; CHECK-NEXT: [[I:%.*]] = call i8 @returns_non_zero_range_helper()
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %x = call i8 @returns_non_zero_range_helper()
+ %or = or i8 %y, %x
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+}
+
+define i1 @neg_range_return(i8 %y) {
+; CHECK-LABEL: @neg_range_return(
+; CHECK-NEXT: [[I:%.*]] = call i8 @returns_contain_zero_range_helper()
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %x = call i8 @returns_contain_zero_range_helper()
+ %or = or i8 %y, %x
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+}
+
+declare i8 @returns_i8_helper()
+
+define i1 @range_call(i8 %y) {
+; CHECK-LABEL: @range_call(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 1, 0) i8 @returns_i8_helper()
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %x = call range(i8 1, 0) i8 @returns_i8_helper()
+ %or = or i8 %y, %x
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+}
+
+define i1 @neg_range_call(i8 %y) {
+; CHECK-LABEL: @neg_range_call(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 -1, 1) i8 @returns_i8_helper()
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %x = call range(i8 -1, 1) i8 @returns_i8_helper()
+ %or = or i8 %y, %x
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+}
+
+define <2 x i1> @range_attr_vec(<2 x i8> range(i8 1, 0) %x, <2 x i8> %y) {
+; CHECK-LABEL: @range_attr_vec(
+; 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]]
+;
+ %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_attr_vec(<2 x i8> range(i8 -1, 1) %x, <2 x i8> %y) {
+; CHECK-LABEL: @neg_range_attr_vec(
+; 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]]
+;
+ %or = or <2 x i8> %y, %x
+ %cmp = icmp ne <2 x i8> %or, zeroinitializer
+ ret <2 x i1> %cmp
+}
+
+declare range(i8 1, 0) <2 x i8> @returns_non_zero_range_helper_vec()
+declare range(i8 -1, 1) <2 x i8> @returns_contain_zero_range_helper_vec()
+
+define <2 x i1> @range_return_vec(<2 x i8> %y) {
+; CHECK-LABEL: @range_return_vec(
+; CHECK-NEXT: [[I:%.*]] = call <2 x i8> @returns_non_zero_range_helper_vec()
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %x = call <2 x i8> @returns_non_zero_range_helper_vec()
+ %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_return_vec(<2 x i8> %y) {
+; CHECK-LABEL: @neg_range_return_vec(
+; CHECK-NEXT: [[I:%.*]] = call <2 x i8> @returns_contain_zero_range_helper_vec()
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %x = call <2 x i8> @returns_contain_zero_range_helper_vec()
+ %or = or <2 x i8> %y, %x
+ %cmp = icmp ne <2 x i8> %or, zeroinitializer
+ ret <2 x i1> %cmp
+}
+
+declare <2 x i8> @returns_i8_helper_vec()
+
+define <2 x i1> @range_call_vec(<2 x i8> %y) {
+; CHECK-LABEL: @range_call_vec(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 1, 0) <2 x i8> @returns_i8_helper_vec()
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %x = call range(i8 1, 0) <2 x i8> @returns_i8_helper_vec()
+ %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_call_vec(<2 x i8> %y) {
+; CHECK-LABEL: @neg_range_call_vec(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 -1, 1) <2 x i8> @returns_i8_helper_vec()
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[I]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %x = call range(i8 -1, 1) <2 x i8> @returns_i8_helper_vec()
+ %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/icmp-constant.ll b/llvm/test/Transforms/InstSimplify/icmp-constant.ll
index 04261f6f40b7c3..b3d9bc5532f20a 100644
--- a/llvm/test/Transforms/InstSimplify/icmp-constant.ll
+++ b/llvm/test/Transforms/InstSimplify/icmp-constant.ll
@@ -1140,3 +1140,137 @@ define <2 x i1> @heterogeneous_constvector(<2 x i8> %x) {
%c = icmp ult <2 x i8> %x, <i8 undef, i8 poison>
ret <2 x i1> %c
}
+
+define i1 @icmp_eq_constant_range_attr(i8 range(i8 0, 10) %i) {
+; CHECK-LABEL: @icmp_eq_constant_range_attr(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I:%.*]], 10
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %cmp = icmp eq i8 %i, 10
+ ret i1 %cmp
+}
+
+define i1 @neg_icmp_eq_constant_range_attr(i8 range(i8 0, 11) %i) {
+; CHECK-LABEL: @neg_icmp_eq_constant_range_attr(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I:%.*]], 10
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %cmp = icmp eq i8 %i, 10
+ ret i1 %cmp
+}
+
+declare range(i8 1, 0) i8 @returns_non_ten_range_helper()
+declare range(i8 -1, 1) i8 @returns_contain_ten_range_helper()
+
+define i1 @icmp_eq_constant_range_return() {
+; CHECK-LABEL: @icmp_eq_constant_range_return(
+; CHECK-NEXT: [[I:%.*]] = call i8 @returns_non_ten_range_helper()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 10
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %i = call i8 @returns_non_ten_range_helper()
+ %cmp = icmp eq i8 %i, 10
+ ret i1 %cmp
+}
+
+define i1 @neg_icmp_eq_constant_range_return() {
+; CHECK-LABEL: @neg_icmp_eq_constant_range_return(
+; CHECK-NEXT: [[I:%.*]] = call i8 @returns_contain_ten_range_helper()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 10
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %i = call i8 @returns_contain_ten_range_helper()
+ %cmp = icmp eq i8 %i, 10
+ ret i1 %cmp
+}
+
+declare i8 @returns_i8_helper()
+
+define i1 @icmp_eq_constant_range_call() {
+; CHECK-LABEL: @icmp_eq_constant_range_call(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 0, 10) i8 @returns_i8_helper()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 10
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %i = call range(i8 0, 10) i8 @returns_i8_helper()
+ %cmp = icmp eq i8 %i, 10
+ ret i1 %cmp
+}
+
+define i1 @neg_icmp_eq_constant_range_call() {
+; CHECK-LABEL: @neg_icmp_eq_constant_range_call(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 0, 11) i8 @returns_i8_helper()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 10
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %i = call range(i8 0, 11) i8 @returns_i8_helper()
+ %cmp = icmp eq i8 %i, 10
+ ret i1 %cmp
+}
+
+define <2 x i1> @icmp_eq_constant_range_attr_vec(<2 x i8> range(i8 0, 10) %i) {
+; CHECK-LABEL: @icmp_eq_constant_range_attr_vec(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I:%.*]], <i8 10, i8 10>
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @neg_icmp_eq_constant_range_attr_vec(<2 x i8> range(i8 0, 11) %i) {
+; CHECK-LABEL: @neg_icmp_eq_constant_range_attr_vec(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I:%.*]], <i8 10, i8 10>
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
+ ret <2 x i1> %cmp
+}
+
+declare range(i8 0, 10) <2 x i8> @returns_non_ten_range_helper_vec()
+declare range(i8 0, 11) <2 x i8> @returns_contain_ten_range_helper_vec()
+
+define <2 x i1> @icmp_eq_constant_range_return_vec() {
+; CHECK-LABEL: @icmp_eq_constant_range_return_vec(
+; CHECK-NEXT: [[I:%.*]] = call <2 x i8> @returns_non_ten_range_helper_vec()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I]], <i8 10, i8 10>
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %i = call <2 x i8> @returns_non_ten_range_helper_vec()
+ %cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @neg_icmp_eq_constant_range_return_vec() {
+; CHECK-LABEL: @neg_icmp_eq_constant_range_return_vec(
+; CHECK-NEXT: [[I:%.*]] = call <2 x i8> @returns_contain_ten_range_helper_vec()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I]], <i8 10, i8 10>
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %i = call <2 x i8> @returns_contain_ten_range_helper_vec()
+ %cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
+ ret <2 x i1> %cmp
+}
+
+declare <2 x i8> @returns_i8_helper_vec()
+
+define <2 x i1> @icmp_eq_constant_range_call_vec() {
+; CHECK-LABEL: @icmp_eq_constant_range_call_vec(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 0, 10) <2 x i8> @returns_i8_helper_vec()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I]], <i8 10, i8 10>
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %i = call range(i8 0, 10) <2 x i8> @returns_i8_helper_vec()
+ %cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @neg_icmp_eq_constant_range_call_vec() {
+; CHECK-LABEL: @neg_icmp_eq_constant_range_call_vec(
+; CHECK-NEXT: [[I:%.*]] = call range(i8 0, 11) <2 x i8> @returns_i8_helper_vec()
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I]], <i8 10, i8 10>
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %i = call range(i8 0, 11) <2 x i8> @returns_i8_helper_vec()
+ %cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
+ ret <2 x i1> %cmp
+}
diff --git a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
index c2256f4b14af83..7c3375e9482a13 100644
--- a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
+++ b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
@@ -14,6 +14,150 @@ define i32 @shl_amount_is_known_bogus(i32 %a, i32 %b) {
ret i32 %shl
}
+define i32 @shl_amount_is_known_bogus_range_attr(i32 %a, i32 range(i32 32, 64) %b) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr(
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: ret i32 [[SHL]]
+;
+ %shl = shl i32 %a, %b
+ ret i32 %shl
+}
+
+define i32 @neg_shl_amount_is_known_bogus_range_attr(i32 %a, i32 range(i32 0, 32) %b) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_attr(
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: ret i32 [[SHL]]
+;
+ %shl = shl i32 %a, %b
+ ret i32 %shl
+}
+
+declare range(i32 32, 64) i32 @returns_out_of_range_helper()
+declare range(i32 0, 32) i32 @returns_in_range_helper()
+
+define i32 @shl_amount_is_known_bogus_range_return(i32 %a) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_return(
+; CHECK-NEXT: [[B:%.*]] = call i32 @returns_out_of_range_helper()
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
+; CHECK-NEXT: ret i32 [[SHL]]
+;
+ %b = call i32 @returns_out_of_range_helper()
+ %shl = shl i32 %a, %b
+ ret i32 %shl
+}
+
+define i32 @neg_shl_amount_is_known_bogus_range_return(i32 %a) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_return(
+; CHECK-NEXT: [[B:%.*]] = call i32 @returns_in_range_helper()
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
+; CHECK-NEXT: ret i32 [[SHL]]
+;
+ %b = call i32 @returns_in_range_helper()
+ %shl = shl i32 %a, %b
+ ret i32 %shl
+}
+
+declare i32 @returns_i32_helper()
+
+define i32 @shl_amount_is_known_bogus_range_call(i32 %a) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_call(
+; CHECK-NEXT: [[B:%.*]] = call range(i32 32, 64) i32 @returns_i32_helper()
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
+; CHECK-NEXT: ret i32 [[SHL]]
+;
+ %b = call range(i32 32, 64) i32 @returns_i32_helper()
+ %shl = shl i32 %a, %b
+ ret i32 %shl
+}
+
+define i32 @neg_shl_amount_is_known_bogus_range_call(i32 %a) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_call(
+; CHECK-NEXT: [[B:%.*]] = call range(i32 0, 32) i32 @returns_i32_helper()
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
+; CHECK-NEXT: ret i32 [[SHL]]
+;
+ %b = call range(i32 0, 32) i32 @returns_i32_helper()
+ %shl = shl i32 %a, %b
+ ret i32 %shl
+}
+
+define <2 x i32> @shl_amount_is_known_bogus_range_attr_vec(<2 x i32> %a, <2 x i32> range(i32 32, 64) %b) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr_vec(
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: ret <2 x i32> [[SHL]]
+;
+ %shl = shl <2 x i32> %a, %b
+ ret <2 x i32> %shl
+}
+
+define <2 x i32> @neg_shl_amount_is_known_bogus_range_attr_vec(<2 x i32> %a, <2 x i32> range(i32 0, 32) %b) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_attr_vec(
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: ret <2 x i32> [[SHL]]
+;
+ %shl = shl <2 x i32> %a, %b
+ ret <2 x i32> %shl
+}
+
+declare range(i32 32, 64) <2 x i32> @returns_out_of_range_helper_vec()
+declare range(i32 0, 32) <2 x i32> @returns_in_range_helper_vec()
+
+define <2 x i32> @shl_amount_is_known_bogus_range_return_vec(<2 x i32> %a) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_return_vec(
+; CHECK-NEXT: [[B:%.*]] = call <2 x i32> @returns_out_of_range_helper_vec()
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
+; CHECK-NEXT: ret <2 x i32> [[SHL]]
+;
+ %b = call <2 x i32> @returns_out_of_range_helper_vec()
+ %shl = shl <2 x i32> %a, %b
+ ret <2 x i32> %shl
+}
+
+define <2 x i32> @neg_shl_amount_is_known_bogus_range_return_vec(<2 x i32> %a) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_return_vec(
+; CHECK-NEXT: [[B:%.*]] = call <2 x i32> @returns_in_range_helper_vec()
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
+; CHECK-NEXT: ret <2 x i32> [[SHL]]
+;
+ %b = call <2 x i32> @returns_in_range_helper_vec()
+ %shl = shl <2 x i32> %a, %b
+ ret <2 x i32> %shl
+}
+
+declare <2 x i32> @returns_i32_helper_vec()
+
+define <2 x i32> @shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) {
+; CHECK-LABEL: @shl_amount_is_known_bogus_range_call_vec(
+; CHECK-NEXT: [[B:%.*]] = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec()
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
+; CHECK-NEXT: ret <2 x i32> [[SHL]]
+;
+ %b = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec()
+ %shl = shl <2 x i32> %a, %b
+ ret <2 x i32> %shl
+}
+
+define <2 x i32> @neg_shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) {
+; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_call_vec(
+; CHECK-NEXT: [[B:%.*]] = call range(i32 0, 32) <2 x i32> @returns_i32_helper_vec()
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
+; CHECK-NEXT: ret <2 x i32> [[SHL]]
+;
+ %b = call range(i32 0, 32) <2 x i32> @returns_i32_helper_vec()
+ %shl = shl <2 x i32> %a, %b
+ ret <2 x i32> %shl
+}
+
+define i32 @shl_amount_is_not_known_bogus_range_call_and_range_metadata(i32 %a) {
+; CHECK-LABEL: @shl_amount_is_not_known_bogus_range_call_and_range_metadata(
+; CHECK-NEXT: [[B:%.*]] = call range(i32 0, 32) i32 @returns_i32_helper(), !range [[RNG0:![0-9]+]]
+; CHECK-NEXT: ret i32 poison
+;
+ %b = call range(i32 0, 32) i32 @returns_i32_helper(), !range !{ i32 32, i32 64 }
+ %shl = shl i32 %a, %b
+ ret i32 %shl
+}
+
; Check some weird types and the other shift ops.
define i31 @lshr_amount_is_known_bogus(i31 %a, i31 %b) {
>From 14b871fcfc7b13dc30b2b747b258c57d70d20f32 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 17 Mar 2024 12:13:45 +0100
Subject: [PATCH 3/5] handle range attribute in isKnownNonZero
---
llvm/lib/Analysis/ValueTracking.cpp | 12 ++++++++++
.../Analysis/ValueTracking/known-non-zero.ll | 24 +++++--------------
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8be17b506af5b8..046075743881e5 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2783,6 +2783,11 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
} else {
if (MDNode *Ranges = Q.IIQ.getMetadata(Call, LLVMContext::MD_range))
return rangeMetadataExcludesValue(Ranges, APInt::getZero(BitWidth));
+ if (std::optional<ConstantRange> Range = Call->getRange()) {
+ const APInt ZeroValue(Range->getBitWidth(), 0);
+ if (!Range->contains(ZeroValue))
+ return true;
+ }
if (const Value *RV = Call->getReturnedArgOperand())
if (RV->getType() == I->getType() && isKnownNonZero(RV, Depth, Q))
return true;
@@ -2921,6 +2926,13 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts, unsigned Depth,
return false;
}
+ if (const auto *A = dyn_cast<Argument>(V))
+ if (std::optional<ConstantRange> Range = A->getRange()) {
+ const APInt ZeroValue(Range->getBitWidth(), 0);
+ if (!Range->contains(ZeroValue))
+ return true;
+ }
+
if (!isa<Constant>(V) && isKnownNonZeroFromAssume(V, Q))
return true;
diff --git a/llvm/test/Analysis/ValueTracking/known-non-zero.ll b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
index a15a787353abc1..0159050d925c3e 100644
--- a/llvm/test/Analysis/ValueTracking/known-non-zero.ll
+++ b/llvm/test/Analysis/ValueTracking/known-non-zero.ll
@@ -1305,9 +1305,7 @@ define <2 x i1> @range_metadata_vec(ptr %p, <2 x i32> %x) {
define i1 @range_attr(i8 range(i8 1, 0) %x, i8 %y) {
; CHECK-LABEL: @range_attr(
-; CHECK-NEXT: [[I:%.*]] = or i8 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 0
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%or = or i8 %y, %x
%cmp = icmp eq i8 %or, 0
@@ -1331,9 +1329,7 @@ declare range(i8 -1, 1) i8 @returns_contain_zero_range_helper()
define i1 @range_return(i8 %y) {
; CHECK-LABEL: @range_return(
; CHECK-NEXT: [[I:%.*]] = call i8 @returns_non_zero_range_helper()
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], [[I]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%x = call i8 @returns_non_zero_range_helper()
%or = or i8 %y, %x
@@ -1359,9 +1355,7 @@ declare i8 @returns_i8_helper()
define i1 @range_call(i8 %y) {
; CHECK-LABEL: @range_call(
; CHECK-NEXT: [[I:%.*]] = call range(i8 1, 0) i8 @returns_i8_helper()
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], [[I]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%x = call range(i8 1, 0) i8 @returns_i8_helper()
%or = or i8 %y, %x
@@ -1384,9 +1378,7 @@ define i1 @neg_range_call(i8 %y) {
define <2 x i1> @range_attr_vec(<2 x i8> range(i8 1, 0) %x, <2 x i8> %y) {
; CHECK-LABEL: @range_attr_vec(
-; 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>
;
%or = or <2 x i8> %y, %x
%cmp = icmp ne <2 x i8> %or, zeroinitializer
@@ -1410,9 +1402,7 @@ declare range(i8 -1, 1) <2 x i8> @returns_contain_zero_range_helper_vec()
define <2 x i1> @range_return_vec(<2 x i8> %y) {
; CHECK-LABEL: @range_return_vec(
; CHECK-NEXT: [[I:%.*]] = call <2 x i8> @returns_non_zero_range_helper_vec()
-; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[I]]
-; 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>
;
%x = call <2 x i8> @returns_non_zero_range_helper_vec()
%or = or <2 x i8> %y, %x
@@ -1438,9 +1428,7 @@ declare <2 x i8> @returns_i8_helper_vec()
define <2 x i1> @range_call_vec(<2 x i8> %y) {
; CHECK-LABEL: @range_call_vec(
; CHECK-NEXT: [[I:%.*]] = call range(i8 1, 0) <2 x i8> @returns_i8_helper_vec()
-; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[Y:%.*]], [[I]]
-; 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>
;
%x = call range(i8 1, 0) <2 x i8> @returns_i8_helper_vec()
%or = or <2 x i8> %y, %x
>From 7d0668ac8207dd37032b8c0be5876849f2596d29 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 17 Mar 2024 12:29:22 +0100
Subject: [PATCH 4/5] handle range attribute in computeConstantRange
---
llvm/lib/Analysis/ValueTracking.cpp | 11 +++++++++--
.../Transforms/InstSimplify/icmp-constant.ll | 18 ++++++------------
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 046075743881e5..9ad6b4d3ea935f 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9143,12 +9143,19 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
// TODO: Return ConstantRange.
setLimitForFPToI(cast<Instruction>(V), Lower, Upper);
CR = ConstantRange::getNonEmpty(Lower, Upper);
- }
+ } else if (const auto *A = dyn_cast<Argument>(V))
+ if (std::optional<ConstantRange> Range = A->getRange())
+ CR = *Range;
- if (auto *I = dyn_cast<Instruction>(V))
+ if (auto *I = dyn_cast<Instruction>(V)) {
if (auto *Range = IIQ.getMetadata(I, LLVMContext::MD_range))
CR = CR.intersectWith(getConstantRangeFromMetadata(*Range));
+ if (const auto *CB = dyn_cast<CallBase>(V))
+ if (std::optional<ConstantRange> Range = CB->getRange())
+ CR = CR.intersectWith(*Range);
+ }
+
if (CtxI && AC) {
// Try to restrict the range based on information from assumptions.
for (auto &AssumeVH : AC->assumptionsFor(V)) {
diff --git a/llvm/test/Transforms/InstSimplify/icmp-constant.ll b/llvm/test/Transforms/InstSimplify/icmp-constant.ll
index b3d9bc5532f20a..99bf11bd4e8c47 100644
--- a/llvm/test/Transforms/InstSimplify/icmp-constant.ll
+++ b/llvm/test/Transforms/InstSimplify/icmp-constant.ll
@@ -1143,8 +1143,7 @@ define <2 x i1> @heterogeneous_constvector(<2 x i8> %x) {
define i1 @icmp_eq_constant_range_attr(i8 range(i8 0, 10) %i) {
; CHECK-LABEL: @icmp_eq_constant_range_attr(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I:%.*]], 10
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%cmp = icmp eq i8 %i, 10
ret i1 %cmp
@@ -1176,8 +1175,7 @@ define i1 @icmp_eq_constant_range_return() {
define i1 @neg_icmp_eq_constant_range_return() {
; CHECK-LABEL: @neg_icmp_eq_constant_range_return(
; CHECK-NEXT: [[I:%.*]] = call i8 @returns_contain_ten_range_helper()
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 10
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%i = call i8 @returns_contain_ten_range_helper()
%cmp = icmp eq i8 %i, 10
@@ -1189,8 +1187,7 @@ declare i8 @returns_i8_helper()
define i1 @icmp_eq_constant_range_call() {
; CHECK-LABEL: @icmp_eq_constant_range_call(
; CHECK-NEXT: [[I:%.*]] = call range(i8 0, 10) i8 @returns_i8_helper()
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[I]], 10
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%i = call range(i8 0, 10) i8 @returns_i8_helper()
%cmp = icmp eq i8 %i, 10
@@ -1210,8 +1207,7 @@ define i1 @neg_icmp_eq_constant_range_call() {
define <2 x i1> @icmp_eq_constant_range_attr_vec(<2 x i8> range(i8 0, 10) %i) {
; CHECK-LABEL: @icmp_eq_constant_range_attr_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I:%.*]], <i8 10, i8 10>
-; CHECK-NEXT: ret <2 x i1> [[CMP]]
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
ret <2 x i1> %cmp
@@ -1232,8 +1228,7 @@ declare range(i8 0, 11) <2 x i8> @returns_contain_ten_range_helper_vec()
define <2 x i1> @icmp_eq_constant_range_return_vec() {
; CHECK-LABEL: @icmp_eq_constant_range_return_vec(
; CHECK-NEXT: [[I:%.*]] = call <2 x i8> @returns_non_ten_range_helper_vec()
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I]], <i8 10, i8 10>
-; CHECK-NEXT: ret <2 x i1> [[CMP]]
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%i = call <2 x i8> @returns_non_ten_range_helper_vec()
%cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
@@ -1256,8 +1251,7 @@ declare <2 x i8> @returns_i8_helper_vec()
define <2 x i1> @icmp_eq_constant_range_call_vec() {
; CHECK-LABEL: @icmp_eq_constant_range_call_vec(
; CHECK-NEXT: [[I:%.*]] = call range(i8 0, 10) <2 x i8> @returns_i8_helper_vec()
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[I]], <i8 10, i8 10>
-; CHECK-NEXT: ret <2 x i1> [[CMP]]
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%i = call range(i8 0, 10) <2 x i8> @returns_i8_helper_vec()
%cmp = icmp eq <2 x i8> %i, <i8 10, i8 10>
>From e2d269b058cd2c8b73cc97a40151805248a22b1f Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 17 Mar 2024 12:43:46 +0100
Subject: [PATCH 5/5] handle range attribute in computeKnownBits
---
llvm/lib/Analysis/ValueTracking.cpp | 15 +++++++++++--
.../InstSimplify/shift-knownbits.ll | 21 +++++++------------
2 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 9ad6b4d3ea935f..2e5c6464f66325 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1500,14 +1500,20 @@ static void computeKnownBitsFromOperator(const Operator *I,
break;
}
case Instruction::Call:
- case Instruction::Invoke:
+ case Instruction::Invoke: {
// If range metadata is attached to this call, set known bits from that,
// and then intersect with known bits based on other properties of the
// function.
if (MDNode *MD =
Q.IIQ.getMetadata(cast<Instruction>(I), LLVMContext::MD_range))
computeKnownBitsFromRangeMetadata(*MD, Known);
- if (const Value *RV = cast<CallBase>(I)->getReturnedArgOperand()) {
+
+ const auto *CB = cast<CallBase>(I);
+
+ if (std::optional<ConstantRange> Range = CB->getRange())
+ Known = Known.unionWith(Range->toKnownBits());
+
+ if (const Value *RV = CB->getReturnedArgOperand()) {
if (RV->getType() == I->getType()) {
computeKnownBits(RV, Known2, Depth + 1, Q);
Known = Known.unionWith(Known2);
@@ -1679,6 +1685,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
}
}
break;
+ }
case Instruction::ShuffleVector: {
auto *Shuf = dyn_cast<ShuffleVectorInst>(I);
// FIXME: Do we need to handle ConstantExpr involving shufflevectors?
@@ -1933,6 +1940,10 @@ void computeKnownBits(const Value *V, const APInt &DemandedElts,
// assumptions. Confirm that we've handled them all.
assert(!isa<ConstantData>(V) && "Unhandled constant data!");
+ if (const auto *A = dyn_cast<Argument>(V))
+ if (std::optional<ConstantRange> Range = A->getRange())
+ Known = Range->toKnownBits();
+
// All recursive calls that increase depth must come after this.
if (Depth == MaxAnalysisRecursionDepth)
return;
diff --git a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
index 7c3375e9482a13..6bf03779379ec7 100644
--- a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
+++ b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll
@@ -16,8 +16,7 @@ define i32 @shl_amount_is_known_bogus(i32 %a, i32 %b) {
define i32 @shl_amount_is_known_bogus_range_attr(i32 %a, i32 range(i32 32, 64) %b) {
; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr(
-; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: ret i32 [[SHL]]
+; CHECK-NEXT: ret i32 poison
;
%shl = shl i32 %a, %b
ret i32 %shl
@@ -38,8 +37,7 @@ declare range(i32 0, 32) i32 @returns_in_range_helper()
define i32 @shl_amount_is_known_bogus_range_return(i32 %a) {
; CHECK-LABEL: @shl_amount_is_known_bogus_range_return(
; CHECK-NEXT: [[B:%.*]] = call i32 @returns_out_of_range_helper()
-; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
-; CHECK-NEXT: ret i32 [[SHL]]
+; CHECK-NEXT: ret i32 poison
;
%b = call i32 @returns_out_of_range_helper()
%shl = shl i32 %a, %b
@@ -62,8 +60,7 @@ declare i32 @returns_i32_helper()
define i32 @shl_amount_is_known_bogus_range_call(i32 %a) {
; CHECK-LABEL: @shl_amount_is_known_bogus_range_call(
; CHECK-NEXT: [[B:%.*]] = call range(i32 32, 64) i32 @returns_i32_helper()
-; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
-; CHECK-NEXT: ret i32 [[SHL]]
+; CHECK-NEXT: ret i32 poison
;
%b = call range(i32 32, 64) i32 @returns_i32_helper()
%shl = shl i32 %a, %b
@@ -83,8 +80,7 @@ define i32 @neg_shl_amount_is_known_bogus_range_call(i32 %a) {
define <2 x i32> @shl_amount_is_known_bogus_range_attr_vec(<2 x i32> %a, <2 x i32> range(i32 32, 64) %b) {
; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr_vec(
-; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: ret <2 x i32> [[SHL]]
+; CHECK-NEXT: ret <2 x i32> poison
;
%shl = shl <2 x i32> %a, %b
ret <2 x i32> %shl
@@ -105,8 +101,7 @@ declare range(i32 0, 32) <2 x i32> @returns_in_range_helper_vec()
define <2 x i32> @shl_amount_is_known_bogus_range_return_vec(<2 x i32> %a) {
; CHECK-LABEL: @shl_amount_is_known_bogus_range_return_vec(
; CHECK-NEXT: [[B:%.*]] = call <2 x i32> @returns_out_of_range_helper_vec()
-; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
-; CHECK-NEXT: ret <2 x i32> [[SHL]]
+; CHECK-NEXT: ret <2 x i32> poison
;
%b = call <2 x i32> @returns_out_of_range_helper_vec()
%shl = shl <2 x i32> %a, %b
@@ -129,8 +124,7 @@ declare <2 x i32> @returns_i32_helper_vec()
define <2 x i32> @shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) {
; CHECK-LABEL: @shl_amount_is_known_bogus_range_call_vec(
; CHECK-NEXT: [[B:%.*]] = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec()
-; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
-; CHECK-NEXT: ret <2 x i32> [[SHL]]
+; CHECK-NEXT: ret <2 x i32> poison
;
%b = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec()
%shl = shl <2 x i32> %a, %b
@@ -151,7 +145,8 @@ define <2 x i32> @neg_shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) {
define i32 @shl_amount_is_not_known_bogus_range_call_and_range_metadata(i32 %a) {
; CHECK-LABEL: @shl_amount_is_not_known_bogus_range_call_and_range_metadata(
; CHECK-NEXT: [[B:%.*]] = call range(i32 0, 32) i32 @returns_i32_helper(), !range [[RNG0:![0-9]+]]
-; CHECK-NEXT: ret i32 poison
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
+; CHECK-NEXT: ret i32 [[SHL]]
;
%b = call range(i32 0, 32) i32 @returns_i32_helper(), !range !{ i32 32, i32 64 }
%shl = shl i32 %a, %b
More information about the llvm-commits
mailing list