InstSimplify: Start cleaning up simplifyFCmpInst

Also picks up a few improvements (Some of the fcmp.ll
test names imply they aren't quite testing what was intended.
Checking the sign bit can't be performed with a compare to a 0).

Much of the logic in here is the same as the class detection
logic of fcmpToClassTest. We could unify more with a weaker
version of fcmpToClassTest which returns implied classes rather
than exact class-like compares. Also could unify more with detection
of possible classes in non-splat vectors.

One problem here is we now only perform folds that used
to always work now require a context instruction. This is
because fcmpToClassTest requires the parent function.
Either fcmpToClassTest could tolerate a missing context
function, or we could require passing in one to simplifyFCmpInst.
Without this it's possible to hit the !isNan assert (which feels like
an unnecessary assert). In any case, these cases don't appear in
any tests.

https://reviews.llvm.org/D151887
This commit is contained in:
Matt Arsenault 2023-05-24 12:33:25 +01:00
parent 6012fed6f5
commit ddb3f12c42
8 changed files with 122 additions and 129 deletions

View File

@ -18,6 +18,7 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/FMF.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Intrinsics.h"
#include <cassert>
@ -229,6 +230,10 @@ std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred,
const Function &F, Value *LHS,
Value *RHS,
bool LookThroughSrc = true);
std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred,
const Function &F, Value *LHS,
const APFloat *ConstRHS,
bool LookThroughSrc = true);
struct KnownFPClass {
/// Floating-point classes the value could be one of.
@ -471,6 +476,28 @@ KnownFPClass computeKnownFPClass(
const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr,
bool UseInstrInfo = true);
/// Wrapper to account for known fast math flags at the use instruction.
inline KnownFPClass computeKnownFPClass(
const Value *V, FastMathFlags FMF, const DataLayout &DL,
FPClassTest InterestedClasses = fcAllFlags, unsigned Depth = 0,
const TargetLibraryInfo *TLI = nullptr, AssumptionCache *AC = nullptr,
const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr,
bool UseInstrInfo = true) {
if (FMF.noNaNs())
InterestedClasses &= ~fcNan;
if (FMF.noInfs())
InterestedClasses &= ~fcInf;
KnownFPClass Result = computeKnownFPClass(V, DL, InterestedClasses, Depth,
TLI, AC, CxtI, DT, UseInstrInfo);
if (FMF.noNaNs())
Result.KnownFPClasses &= ~fcNan;
if (FMF.noInfs())
Result.KnownFPClasses &= ~fcInf;
return Result;
}
/// Return true if we can prove that the specified FP value is never equal to
/// -0.0. Users should use caution when considering PreserveSign
/// denormal-fp-math.

View File

@ -4060,19 +4060,6 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
if (Pred == FCmpInst::FCMP_TRUE)
return getTrue(RetTy);
// Fold (un)ordered comparison if we can determine there are no NaNs.
if (Pred == FCmpInst::FCMP_UNO || Pred == FCmpInst::FCMP_ORD)
if (FMF.noNaNs() ||
(isKnownNeverNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT) &&
isKnownNeverNaN(RHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)))
return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD);
// NaN is unordered; NaN is not ordered.
assert((FCmpInst::isOrdered(Pred) || FCmpInst::isUnordered(Pred)) &&
"Comparison must be either ordered or unordered");
if (match(RHS, m_NaN()))
return ConstantInt::get(RetTy, CmpInst::isUnordered(Pred));
// fcmp pred x, poison and fcmp pred poison, x
// fold to poison
if (isa<PoisonValue>(LHS) || isa<PoisonValue>(RHS))
@ -4094,80 +4081,86 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
return getFalse(RetTy);
}
// Handle fcmp with constant RHS.
// TODO: Use match with a specific FP value, so these work with vectors with
// undef lanes.
const APFloat *C;
if (match(RHS, m_APFloat(C))) {
// Check whether the constant is an infinity.
if (C->isInfinity()) {
if (C->isNegative()) {
switch (Pred) {
case FCmpInst::FCMP_OLT:
// No value is ordered and less than negative infinity.
return getFalse(RetTy);
case FCmpInst::FCMP_UGE:
// All values are unordered with or at least negative infinity.
return getTrue(RetTy);
default:
break;
}
} else {
switch (Pred) {
case FCmpInst::FCMP_OGT:
// No value is ordered and greater than infinity.
return getFalse(RetTy);
case FCmpInst::FCMP_ULE:
// All values are unordered with and at most infinity.
return getTrue(RetTy);
default:
break;
}
}
// Fold (un)ordered comparison if we can determine there are no NaNs.
//
// This catches the 2 variable input case, constants are handled below as a
// class-like compare.
if (Pred == FCmpInst::FCMP_ORD || Pred == FCmpInst::FCMP_UNO) {
if (FMF.noNaNs() ||
(isKnownNeverNaN(RHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT) &&
isKnownNeverNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)))
return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD);
}
// LHS == Inf
if (Pred == FCmpInst::FCMP_OEQ &&
isKnownNeverInfinity(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
const APFloat *C = nullptr;
match(RHS, m_APFloatAllowUndef(C));
std::optional<KnownFPClass> FullKnownClassLHS;
// Lazily compute the possible classes for LHS. Avoid computing it twice if
// RHS is a 0.
auto computeLHSClass = [=, &FullKnownClassLHS](FPClassTest InterestedFlags =
fcAllFlags) {
if (FullKnownClassLHS)
return *FullKnownClassLHS;
return computeKnownFPClass(LHS, FMF, Q.DL, InterestedFlags, 0, Q.TLI, Q.AC,
Q.CxtI, Q.DT, Q.IIQ.UseInstrInfo);
};
if (C && Q.CxtI) {
// Fold out compares that express a class test.
//
// FIXME: Should be able to perform folds without context
// instruction. Always pass in the context function?
const Function *ParentF = Q.CxtI->getFunction();
auto [ClassVal, ClassTest] = fcmpToClassTest(Pred, *ParentF, LHS, C);
if (ClassVal) {
FullKnownClassLHS = computeLHSClass();
if ((FullKnownClassLHS->KnownFPClasses & ClassTest) == fcNone)
return getFalse(RetTy);
// LHS != Inf
if (Pred == FCmpInst::FCMP_UNE &&
isKnownNeverInfinity(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
return getTrue(RetTy);
// LHS == Inf || LHS == NaN
if (Pred == FCmpInst::FCMP_UEQ &&
isKnownNeverInfOrNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
return getFalse(RetTy);
// LHS != Inf && LHS != NaN
if (Pred == FCmpInst::FCMP_ONE &&
isKnownNeverInfOrNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
if ((FullKnownClassLHS->KnownFPClasses & ~ClassTest) == fcNone)
return getTrue(RetTy);
}
}
// Handle fcmp with constant RHS.
if (C) {
// TODO: Need version fcmpToClassTest which returns implied class when the
// compare isn't a complete class test. e.g. > 1.0 implies fcPositive, but
// isn't implementable as a class call.
if (C->isNegative() && !C->isNegZero()) {
FPClassTest Interested = fcPositive | fcNan;
// FIXME: This assert won't always hold if we depend on the context
// instruction above
assert(!C->isNaN() && "Unexpected NaN constant!");
// TODO: We can catch more cases by using a range check rather than
// relying on CannotBeOrderedLessThanZero.
switch (Pred) {
case FCmpInst::FCMP_UGE:
case FCmpInst::FCMP_UGT:
case FCmpInst::FCMP_UNE:
case FCmpInst::FCMP_UNE: {
KnownFPClass KnownClass = computeLHSClass(Interested);
// (X >= 0) implies (X > C) when (C < 0)
if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0,
Q.AC, Q.CxtI, Q.DT))
if (KnownClass.cannotBeOrderedLessThanZero())
return getTrue(RetTy);
break;
}
case FCmpInst::FCMP_OEQ:
case FCmpInst::FCMP_OLE:
case FCmpInst::FCMP_OLT:
case FCmpInst::FCMP_OLT: {
KnownFPClass KnownClass = computeLHSClass(Interested);
// (X >= 0) implies !(X < C) when (C < 0)
if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI,
Q.DT))
if (KnownClass.cannotBeOrderedLessThanZero())
return getFalse(RetTy);
break;
}
default:
break;
}
}
// Check comparison of [minnum/maxnum with constant] with other constant.
const APFloat *C2;
if ((match(LHS, m_Intrinsic<Intrinsic::minnum>(m_Value(), m_APFloat(C2))) &&
@ -4214,13 +4207,15 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
}
}
// TODO: Could fold this with above if there were a matcher which returned all
// classes in a non-splat vector.
if (match(RHS, m_AnyZeroFP())) {
FPClassTest Interested = FMF.noNaNs() ? fcPositive : fcPositive | fcNan;
switch (Pred) {
case FCmpInst::FCMP_OGE:
case FCmpInst::FCMP_ULT: {
FPClassTest Interested = FMF.noNaNs() ? fcNegative : fcNegative | fcNan;
KnownFPClass Known = computeKnownFPClass(LHS, Q.DL, Interested, 0,
Q.TLI, Q.AC, Q.CxtI, Q.DT);
KnownFPClass Known = computeLHSClass(Interested);
// Positive or zero X >= 0.0 --> true
// Positive or zero X < 0.0 --> false
@ -4230,12 +4225,15 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
break;
}
case FCmpInst::FCMP_UGE:
case FCmpInst::FCMP_OLT:
case FCmpInst::FCMP_OLT: {
KnownFPClass Known = computeLHSClass(Interested);
// Positive or zero or nan X >= 0.0 --> true
// Positive or zero or nan X < 0.0 --> false
if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
if (Known.cannotBeOrderedLessThanZero())
return Pred == FCmpInst::FCMP_UGE ? getTrue(RetTy) : getFalse(RetTy);
break;
}
default:
break;
}
@ -6816,6 +6814,9 @@ static Value *simplifyInstructionWithOperands(Instruction *I,
const SimplifyQuery &SQ,
unsigned MaxRecurse) {
assert(I->getFunction() && "instruction should be inserted in a function");
assert((!SQ.CxtI || SQ.CxtI->getFunction() == I->getFunction()) &&
"context instruction should be in the same function");
const SimplifyQuery Q = SQ.CxtI ? SQ : SQ.getWithInstruction(I);
switch (I->getOpcode()) {

View File

@ -3997,9 +3997,15 @@ std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred,
Value *LHS, Value *RHS,
bool LookThroughSrc) {
const APFloat *ConstRHS;
if (!match(RHS, m_APFloat(ConstRHS)))
if (!match(RHS, m_APFloatAllowUndef(ConstRHS)))
return {nullptr, fcNone};
return fcmpToClassTest(Pred, F, LHS, ConstRHS, LookThroughSrc);
}
std::pair<Value *, FPClassTest>
llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS,
const APFloat *ConstRHS, bool LookThroughSrc) {
// fcmp ord x, zero|normal|subnormal|inf -> ~fcNan
if (Pred == FCmpInst::FCMP_ORD && !ConstRHS->isNaN())
return {LHS, ~fcNan};

View File

@ -600,8 +600,7 @@ define half @assume_fcmp_fabs_with_other_fabs_assume_fallback(half %arg) {
; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]]
; CHECK-NEXT: [[UNRELATED_FABS:%.*]] = fcmp oeq half [[FABS]], 0xH0000
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR16]]
; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR16]]
; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]]
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan inf norm) [[ARG]])
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan inf nzero sub norm) [[FABS]])
; CHECK-NEXT: ret half [[ARG]]

View File

@ -718,9 +718,7 @@ define i1 @is_signbit_clear_nonzero(double %x) {
define i1 @is_signbit_set_simplify_zero(double %x) {
; CHECK-LABEL: @is_signbit_set_simplify_zero(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0.000000e+00, double [[X:%.*]])
; CHECK-NEXT: [[R:%.*]] = fcmp ogt double [[S]], 0.000000e+00
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 false
;
%s = call double @llvm.copysign.f64(double 0.0, double %x)
%r = fcmp ogt double %s, 0.0
@ -731,9 +729,7 @@ define i1 @is_signbit_set_simplify_zero(double %x) {
define i1 @is_signbit_set_simplify_nan(double %x) {
; CHECK-LABEL: @is_signbit_set_simplify_nan(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0xFFFFFFFFFFFFFFFF, double [[X:%.*]])
; CHECK-NEXT: [[R:%.*]] = fcmp ogt double [[S]], 0.000000e+00
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 false
;
%s = call double @llvm.copysign.f64(double 0xffffffffffffffff, double %x)
%r = fcmp ogt double %s, 0.0

View File

@ -2444,8 +2444,7 @@ define <2 x i1> @test_class_fneg_fabs_posinf_negnormal_possubnormal_negzero_nan_
define i1 @test_class_is_zero_nozero_src(float nofpclass(zero) %arg) {
; CHECK-LABEL: @test_class_is_zero_nozero_src(
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CLASS]]
; CHECK-NEXT: ret i1 false
;
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 96)
ret i1 %class
@ -2578,8 +2577,7 @@ define i1 @test_class_is_neginf_or_nopinf_src(float nofpclass(pinf) %arg) {
define i1 @test_class_is_neginf_noninf_src(float nofpclass(ninf) %arg) {
; CHECK-LABEL: @test_class_is_neginf_noninf_src(
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0xFFF0000000000000
; CHECK-NEXT: ret i1 [[CLASS]]
; CHECK-NEXT: ret i1 false
;
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 4)
ret i1 %class
@ -2604,8 +2602,7 @@ define i1 @test_class_is_posinf_noninf_src(float nofpclass(ninf) %arg) {
define i1 @test_class_is_posinf_nopinf_src(float nofpclass(pinf) %arg) {
; CHECK-LABEL: @test_class_is_posinf_nopinf_src(
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[CLASS]]
; CHECK-NEXT: ret i1 false
;
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 512)
ret i1 %class
@ -2733,8 +2730,7 @@ define i1 @test_class_is_nan_assume_uno(float %x) {
; CHECK-LABEL: @test_class_is_nan_assume_uno(
; CHECK-NEXT: [[ORD:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: call void @llvm.assume(i1 [[ORD]])
; CHECK-NEXT: [[CLASS:%.*]] = fcmp uno float [[X]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CLASS]]
; CHECK-NEXT: ret i1 true
;
%ord = fcmp uno float %x, 0.0
call void @llvm.assume(i1 %ord)

View File

@ -656,8 +656,7 @@ define i1 @assume_nan_ord(float %x) {
; CHECK-LABEL: @assume_nan_ord(
; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: call void @llvm.assume(i1 [[UNO]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp ord float [[X]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK-NEXT: ret i1 false
;
%uno = fcmp uno float %x, 0.0
call void @llvm.assume(i1 %uno)
@ -681,8 +680,7 @@ define i1 @assume_nan_uno(float %x) {
; CHECK-LABEL: @assume_nan_uno(
; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: call void @llvm.assume(i1 [[UNO]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[X]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK-NEXT: ret i1 true
;
%uno = fcmp uno float %x, 0.0
call void @llvm.assume(i1 %uno)
@ -1525,10 +1523,7 @@ define i1 @fcmp_olt_0_assumed_oge_zero(float %x) {
define i1 @ogt_zero_fabs_select_negone_or_pinf(i1 %cond) {
; CHECK-LABEL: @ogt_zero_fabs_select_negone_or_pinf(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND:%.*]], float -1.000000e+00, float 0x7FF0000000000000
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: [[ONE:%.*]] = fcmp ogt float [[FABS]], 0.000000e+00
; CHECK-NEXT: ret i1 [[ONE]]
; CHECK-NEXT: ret i1 true
;
entry:
%select = select i1 %cond, float -1.0, float 0x7FF0000000000000
@ -1540,10 +1535,7 @@ entry:
define i1 @ogt_zero_fabs_select_one_or_ninf(i1 %cond) {
; CHECK-LABEL: @ogt_zero_fabs_select_one_or_ninf(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND:%.*]], float 1.000000e+00, float 0xFFF0000000000000
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: [[ONE:%.*]] = fcmp ogt float [[FABS]], 0.000000e+00
; CHECK-NEXT: ret i1 [[ONE]]
; CHECK-NEXT: ret i1 true
;
entry:
%select = select i1 %cond, float 1.0, float 0xFFF0000000000000

View File

@ -753,11 +753,7 @@ define i1 @isKnownNeverInfinity_cos(double %x) {
define i1 @isKnownNeverInfinity_log(double %x) {
; CHECK-LABEL: define i1 @isKnownNeverInfinity_log
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[X_CLAMP_ZERO:%.*]] = call double @llvm.maxnum.f64(double [[X]], double 0.000000e+00)
; CHECK-NEXT: [[A:%.*]] = fadd ninf double [[X_CLAMP_ZERO]], 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = call double @llvm.log.f64(double [[A]])
; CHECK-NEXT: [[R:%.*]] = fcmp une double [[E]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%x.clamp.zero = call double @llvm.maxnum.f64(double %x, double 0.0)
%a = fadd ninf double %x.clamp.zero, 1.0
@ -769,10 +765,7 @@ define i1 @isKnownNeverInfinity_log(double %x) {
define i1 @isNotKnownNeverInfinity_log_maybe_negative(double %x) {
; CHECK-LABEL: define i1 @isNotKnownNeverInfinity_log_maybe_negative
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[X_NOT_INF:%.*]] = fadd ninf double [[X]], 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = call double @llvm.log.f64(double [[X_NOT_INF]])
; CHECK-NEXT: [[R:%.*]] = fcmp une double [[E]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%x.not.inf = fadd ninf double %x, 1.0
@ -812,11 +805,7 @@ define i1 @isKnownNeverNegInfinity_log_maybe_0(double %x) {
define i1 @isKnownNeverInfinity_log10(double %x) {
; CHECK-LABEL: define i1 @isKnownNeverInfinity_log10
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[X_CLAMP_ZERO:%.*]] = call double @llvm.maxnum.f64(double [[X]], double 0.000000e+00)
; CHECK-NEXT: [[A:%.*]] = fadd ninf double [[X_CLAMP_ZERO]], 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = call double @llvm.log10.f64(double [[A]])
; CHECK-NEXT: [[R:%.*]] = fcmp une double [[E]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%x.clamp.zero = call double @llvm.maxnum.f64(double %x, double 0.0)
%a = fadd ninf double %x.clamp.zero, 1.0
@ -828,10 +817,7 @@ define i1 @isKnownNeverInfinity_log10(double %x) {
define i1 @isNotKnownNeverInfinity_log10_maybe_negative(double %x) {
; CHECK-LABEL: define i1 @isNotKnownNeverInfinity_log10_maybe_negative
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[X_NOT_INF:%.*]] = fadd ninf double [[X]], 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = call double @llvm.log10.f64(double [[X_NOT_INF]])
; CHECK-NEXT: [[R:%.*]] = fcmp une double [[E]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%x.not.inf = fadd ninf double %x, 1.0
@ -871,11 +857,7 @@ define i1 @isKnownNeverNegInfinity_log10_maybe_0(double %x) {
define i1 @isKnownNeverInfinity_log2(double %x) {
; CHECK-LABEL: define i1 @isKnownNeverInfinity_log2
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[X_CLAMP_ZERO:%.*]] = call double @llvm.maxnum.f64(double [[X]], double 0.000000e+00)
; CHECK-NEXT: [[A:%.*]] = fadd ninf double [[X_CLAMP_ZERO]], 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = call double @llvm.log2.f64(double [[A]])
; CHECK-NEXT: [[R:%.*]] = fcmp une double [[E]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%x.clamp.zero = call double @llvm.maxnum.f64(double %x, double 0.0)
%a = fadd ninf double %x.clamp.zero, 1.0
@ -887,10 +869,7 @@ define i1 @isKnownNeverInfinity_log2(double %x) {
define i1 @isNotKnownNeverInfinity_log2_maybe_negative(double %x) {
; CHECK-LABEL: define i1 @isNotKnownNeverInfinity_log2_maybe_negative
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[X_NOT_INF:%.*]] = fadd ninf double [[X]], 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = call double @llvm.log2.f64(double [[X_NOT_INF]])
; CHECK-NEXT: [[R:%.*]] = fcmp une double [[E]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%x.not.inf = fadd ninf double %x, 1.0
@ -1057,10 +1036,7 @@ define i1 @not_ninf_fabs_select_nzero_or_pinf(i1 %cond) {
; CHECK-LABEL: define i1 @not_ninf_fabs_select_nzero_or_pinf
; CHECK-SAME: (i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float -0.000000e+00, float 0x7FF0000000000000
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: [[ONE:%.*]] = fcmp one float [[FABS]], 0xFFF0000000000000
; CHECK-NEXT: ret i1 [[ONE]]
; CHECK-NEXT: ret i1 true
;
entry:
%select = select i1 %cond, float -0.000000e+00, float 0x7FF0000000000000