From 87d14b1bae3c02e2747ad004a6007e565aed294b Mon Sep 17 00:00:00 2001 From: Andreas Jonson 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 f0c0ce75d2b7e..3349f1306970e 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 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 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 fed21b992e3d1..e8c2cba8418dc 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 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 06283cb4bb934..7a37ae86c7f3c 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -3736,15 +3736,10 @@ static std::optional getRange(Value *V, if (MDNode *MD = IIQ.getMetadata(I, LLVMContext::MD_range)) return getConstantRangeFromMetadata(*MD); - Attribute Range; - if (const Argument *A = dyn_cast(V)) { - Range = A->getAttribute(llvm::Attribute::Range); - } else if (const CallBase *CB = dyn_cast(V)) { - Range = CB->getRetAttr(llvm::Attribute::Range); - } - - if (Range.isValid()) - return Range.getRange(); + if (const Argument *A = dyn_cast(V)) + return A->getRange(); + else if (const CallBase *CB = dyn_cast(V)) + return CB->getRange(); return std::nullopt; } diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index d22e1c1231118..eb126f182eadc 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 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 c55d6cff84ed5..494d50f89e374 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 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 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 30d340dc725a3..a15a787353abc 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 04261f6f40b7c..b3d9bc5532f20 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, 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:%.*]], +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %cmp = icmp eq <2 x i8> %i, + 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:%.*]], +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %cmp = icmp eq <2 x i8> %i, + 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]], +; 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, + 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]], +; 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, + 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]], +; 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, + 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]], +; 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, + ret <2 x i1> %cmp +} diff --git a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll index c2256f4b14af8..7c3375e9482a1 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 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 8be17b506af5b..046075743881e 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 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(V)) + if (std::optional Range = A->getRange()) { + const APInt ZeroValue(Range->getBitWidth(), 0); + if (!Range->contains(ZeroValue)) + return true; + } + if (!isa(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 a15a787353abc..0159050d925c3 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> ; %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> ; %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> ; %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 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 046075743881e..9ad6b4d3ea935 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(V), Lower, Upper); CR = ConstantRange::getNonEmpty(Lower, Upper); - } + } else if (const auto *A = dyn_cast(V)) + if (std::optional Range = A->getRange()) + CR = *Range; - if (auto *I = dyn_cast(V)) + if (auto *I = dyn_cast(V)) { if (auto *Range = IIQ.getMetadata(I, LLVMContext::MD_range)) CR = CR.intersectWith(getConstantRangeFromMetadata(*Range)); + if (const auto *CB = dyn_cast(V)) + if (std::optional 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 b3d9bc5532f20..99bf11bd4e8c4 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:%.*]], -; CHECK-NEXT: ret <2 x i1> [[CMP]] +; CHECK-NEXT: ret <2 x i1> zeroinitializer ; %cmp = icmp eq <2 x i8> %i, 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]], -; 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, @@ -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]], -; 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, From e2d269b058cd2c8b73cc97a40151805248a22b1f Mon Sep 17 00:00:00 2001 From: Andreas Jonson 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 9ad6b4d3ea935..2e5c6464f6632 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(I), LLVMContext::MD_range)) computeKnownBitsFromRangeMetadata(*MD, Known); - if (const Value *RV = cast(I)->getReturnedArgOperand()) { + + const auto *CB = cast(I); + + if (std::optional 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(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(V) && "Unhandled constant data!"); + if (const auto *A = dyn_cast(V)) + if (std::optional 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 7c3375e9482a1..6bf03779379ec 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