Skip to content

Commit 294ad08

Browse files
committed
Revert "Revert "InstSimplify: Use correct interested FP classes when simplifying fcmp""
This reverts commit 89f0314. Change does not build.
1 parent 3e67d7b commit 294ad08

File tree

8 files changed

+235
-129
lines changed

8 files changed

+235
-129
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/ADT/SmallSet.h"
1919
#include "llvm/IR/Constants.h"
2020
#include "llvm/IR/DataLayout.h"
21+
#include "llvm/IR/FMF.h"
2122
#include "llvm/IR/InstrTypes.h"
2223
#include "llvm/IR/Intrinsics.h"
2324
#include <cassert>
@@ -229,6 +230,10 @@ std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred,
229230
const Function &F, Value *LHS,
230231
Value *RHS,
231232
bool LookThroughSrc = true);
233+
std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred,
234+
const Function &F, Value *LHS,
235+
const APFloat *ConstRHS,
236+
bool LookThroughSrc = true);
232237

233238
struct KnownFPClass {
234239
/// Floating-point classes the value could be one of.
@@ -471,6 +476,28 @@ KnownFPClass computeKnownFPClass(
471476
const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr,
472477
bool UseInstrInfo = true);
473478

479+
/// Wrapper to account for known fast math flags at the use instruction.
480+
inline KnownFPClass computeKnownFPClass(
481+
const Value *V, FastMathFlags FMF, const DataLayout &DL,
482+
FPClassTest InterestedClasses = fcAllFlags, unsigned Depth = 0,
483+
const TargetLibraryInfo *TLI = nullptr, AssumptionCache *AC = nullptr,
484+
const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr,
485+
bool UseInstrInfo = true) {
486+
if (FMF.noNaNs())
487+
InterestedClasses &= ~fcNan;
488+
if (FMF.noInfs())
489+
InterestedClasses &= ~fcInf;
490+
491+
KnownFPClass Result = computeKnownFPClass(V, DL, InterestedClasses, Depth,
492+
TLI, AC, CxtI, DT, UseInstrInfo);
493+
494+
if (FMF.noNaNs())
495+
Result.KnownFPClasses &= ~fcNan;
496+
if (FMF.noInfs())
497+
Result.KnownFPClasses &= ~fcInf;
498+
return Result;
499+
}
500+
474501
/// Return true if we can prove that the specified FP value is never equal to
475502
/// -0.0. Users should use caution when considering PreserveSign
476503
/// denormal-fp-math.

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 73 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4060,19 +4060,6 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
40604060
if (Pred == FCmpInst::FCMP_TRUE)
40614061
return getTrue(RetTy);
40624062

4063-
// Fold (un)ordered comparison if we can determine there are no NaNs.
4064-
if (Pred == FCmpInst::FCMP_UNO || Pred == FCmpInst::FCMP_ORD)
4065-
if (FMF.noNaNs() ||
4066-
(isKnownNeverNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT) &&
4067-
isKnownNeverNaN(RHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)))
4068-
return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD);
4069-
4070-
// NaN is unordered; NaN is not ordered.
4071-
assert((FCmpInst::isOrdered(Pred) || FCmpInst::isUnordered(Pred)) &&
4072-
"Comparison must be either ordered or unordered");
4073-
if (match(RHS, m_NaN()))
4074-
return ConstantInt::get(RetTy, CmpInst::isUnordered(Pred));
4075-
40764063
// fcmp pred x, poison and fcmp pred poison, x
40774064
// fold to poison
40784065
if (isa<PoisonValue>(LHS) || isa<PoisonValue>(RHS))
@@ -4094,80 +4081,86 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
40944081
return getFalse(RetTy);
40954082
}
40964083

4097-
// Handle fcmp with constant RHS.
4098-
// TODO: Use match with a specific FP value, so these work with vectors with
4099-
// undef lanes.
4100-
const APFloat *C;
4101-
if (match(RHS, m_APFloat(C))) {
4102-
// Check whether the constant is an infinity.
4103-
if (C->isInfinity()) {
4104-
if (C->isNegative()) {
4105-
switch (Pred) {
4106-
case FCmpInst::FCMP_OLT:
4107-
// No value is ordered and less than negative infinity.
4108-
return getFalse(RetTy);
4109-
case FCmpInst::FCMP_UGE:
4110-
// All values are unordered with or at least negative infinity.
4111-
return getTrue(RetTy);
4112-
default:
4113-
break;
4114-
}
4115-
} else {
4116-
switch (Pred) {
4117-
case FCmpInst::FCMP_OGT:
4118-
// No value is ordered and greater than infinity.
4119-
return getFalse(RetTy);
4120-
case FCmpInst::FCMP_ULE:
4121-
// All values are unordered with and at most infinity.
4122-
return getTrue(RetTy);
4123-
default:
4124-
break;
4125-
}
4126-
}
4084+
// Fold (un)ordered comparison if we can determine there are no NaNs.
4085+
//
4086+
// This catches the 2 variable input case, constants are handled below as a
4087+
// class-like compare.
4088+
if (Pred == FCmpInst::FCMP_ORD || Pred == FCmpInst::FCMP_UNO) {
4089+
if (FMF.noNaNs() ||
4090+
(isKnownNeverNaN(RHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT) &&
4091+
isKnownNeverNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)))
4092+
return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD);
4093+
}
41274094

4128-
// LHS == Inf
4129-
if (Pred == FCmpInst::FCMP_OEQ &&
4130-
isKnownNeverInfinity(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
4131-
return getFalse(RetTy);
4132-
// LHS != Inf
4133-
if (Pred == FCmpInst::FCMP_UNE &&
4134-
isKnownNeverInfinity(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
4135-
return getTrue(RetTy);
4136-
// LHS == Inf || LHS == NaN
4137-
if (Pred == FCmpInst::FCMP_UEQ &&
4138-
isKnownNeverInfOrNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
4095+
const APFloat *C = nullptr;
4096+
match(RHS, m_APFloatAllowUndef(C));
4097+
std::optional<KnownFPClass> FullKnownClassLHS;
4098+
4099+
// Lazily compute the possible classes for LHS. Avoid computing it twice if
4100+
// RHS is a 0.
4101+
auto computeLHSClass = [=, &FullKnownClassLHS](FPClassTest InterestedFlags =
4102+
fcAllFlags) {
4103+
if (FullKnownClassLHS)
4104+
return *FullKnownClassLHS;
4105+
return computeKnownFPClass(LHS, FMF, Q.DL, InterestedFlags, 0, Q.TLI, Q.AC,
4106+
Q.CxtI, Q.DT, Q.IIQ.UseInstrInfo);
4107+
};
4108+
4109+
if (C && Q.CxtI) {
4110+
// Fold out compares that express a class test.
4111+
//
4112+
// FIXME: Should be able to perform folds without context
4113+
// instruction. Always pass in the context function?
4114+
4115+
const Function *ParentF = Q.CxtI->getFunction();
4116+
auto [ClassVal, ClassTest] = fcmpToClassTest(Pred, *ParentF, LHS, C);
4117+
if (ClassVal) {
4118+
FullKnownClassLHS = computeLHSClass();
4119+
if ((FullKnownClassLHS->KnownFPClasses & ClassTest) == fcNone)
41394120
return getFalse(RetTy);
4140-
// LHS != Inf && LHS != NaN
4141-
if (Pred == FCmpInst::FCMP_ONE &&
4142-
isKnownNeverInfOrNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
4121+
if ((FullKnownClassLHS->KnownFPClasses & ~ClassTest) == fcNone)
41434122
return getTrue(RetTy);
41444123
}
4124+
}
4125+
4126+
// Handle fcmp with constant RHS.
4127+
if (C) {
4128+
// TODO: Need version fcmpToClassTest which returns implied class when the
4129+
// compare isn't a complete class test. e.g. > 1.0 implies fcPositive, but
4130+
// isn't implementable as a class call.
41454131
if (C->isNegative() && !C->isNegZero()) {
4132+
FPClassTest Interested = KnownFPClass::OrderedLessThanZeroMask;
4133+
4134+
// FIXME: This assert won't always hold if we depend on the context
4135+
// instruction above
41464136
assert(!C->isNaN() && "Unexpected NaN constant!");
41474137
// TODO: We can catch more cases by using a range check rather than
41484138
// relying on CannotBeOrderedLessThanZero.
41494139
switch (Pred) {
41504140
case FCmpInst::FCMP_UGE:
41514141
case FCmpInst::FCMP_UGT:
4152-
case FCmpInst::FCMP_UNE:
4142+
case FCmpInst::FCMP_UNE: {
4143+
KnownFPClass KnownClass = computeLHSClass(Interested);
4144+
41534145
// (X >= 0) implies (X > C) when (C < 0)
4154-
if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0,
4155-
Q.AC, Q.CxtI, Q.DT))
4146+
if (KnownClass.cannotBeOrderedLessThanZero())
41564147
return getTrue(RetTy);
41574148
break;
4149+
}
41584150
case FCmpInst::FCMP_OEQ:
41594151
case FCmpInst::FCMP_OLE:
4160-
case FCmpInst::FCMP_OLT:
4152+
case FCmpInst::FCMP_OLT: {
4153+
KnownFPClass KnownClass = computeLHSClass(Interested);
4154+
41614155
// (X >= 0) implies !(X < C) when (C < 0)
4162-
if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI,
4163-
Q.DT))
4156+
if (KnownClass.cannotBeOrderedLessThanZero())
41644157
return getFalse(RetTy);
41654158
break;
4159+
}
41664160
default:
41674161
break;
41684162
}
41694163
}
4170-
41714164
// Check comparison of [minnum/maxnum with constant] with other constant.
41724165
const APFloat *C2;
41734166
if ((match(LHS, m_Intrinsic<Intrinsic::minnum>(m_Value(), m_APFloat(C2))) &&
@@ -4214,13 +4207,17 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
42144207
}
42154208
}
42164209

4210+
// TODO: Could fold this with above if there were a matcher which returned all
4211+
// classes in a non-splat vector.
42174212
if (match(RHS, m_AnyZeroFP())) {
42184213
switch (Pred) {
42194214
case FCmpInst::FCMP_OGE:
42204215
case FCmpInst::FCMP_ULT: {
4221-
FPClassTest Interested = FMF.noNaNs() ? fcNegative : fcNegative | fcNan;
4222-
KnownFPClass Known = computeKnownFPClass(LHS, Q.DL, Interested, 0,
4223-
Q.TLI, Q.AC, Q.CxtI, Q.DT);
4216+
FPClassTest Interested = KnownFPClass::OrderedLessThanZeroMask;
4217+
if (!FMF.noNaNs())
4218+
Interested |= fcNan;
4219+
4220+
KnownFPClass Known = computeLHSClass(Interested);
42244221

42254222
// Positive or zero X >= 0.0 --> true
42264223
// Positive or zero X < 0.0 --> false
@@ -4230,12 +4227,16 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
42304227
break;
42314228
}
42324229
case FCmpInst::FCMP_UGE:
4233-
case FCmpInst::FCMP_OLT:
4230+
case FCmpInst::FCMP_OLT: {
4231+
FPClassTest Interested = KnownFPClass::OrderedLessThanZeroMask;
4232+
KnownFPClass Known = computeLHSClass(Interested);
4233+
42344234
// Positive or zero or nan X >= 0.0 --> true
42354235
// Positive or zero or nan X < 0.0 --> false
4236-
if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))
4236+
if (Known.cannotBeOrderedLessThanZero())
42374237
return Pred == FCmpInst::FCMP_UGE ? getTrue(RetTy) : getFalse(RetTy);
42384238
break;
4239+
}
42394240
default:
42404241
break;
42414242
}
@@ -6816,6 +6817,9 @@ static Value *simplifyInstructionWithOperands(Instruction *I,
68166817
const SimplifyQuery &SQ,
68176818
unsigned MaxRecurse) {
68186819
assert(I->getFunction() && "instruction should be inserted in a function");
6820+
assert((!SQ.CxtI || SQ.CxtI->getFunction() == I->getFunction()) &&
6821+
"context instruction should be in the same function");
6822+
68196823
const SimplifyQuery Q = SQ.CxtI ? SQ : SQ.getWithInstruction(I);
68206824

68216825
switch (I->getOpcode()) {

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4007,9 +4007,15 @@ std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred,
40074007
Value *LHS, Value *RHS,
40084008
bool LookThroughSrc) {
40094009
const APFloat *ConstRHS;
4010-
if (!match(RHS, m_APFloat(ConstRHS)))
4010+
if (!match(RHS, m_APFloatAllowUndef(ConstRHS)))
40114011
return {nullptr, fcNone};
40124012

4013+
return fcmpToClassTest(Pred, F, LHS, ConstRHS, LookThroughSrc);
4014+
}
4015+
4016+
std::pair<Value *, FPClassTest>
4017+
llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS,
4018+
const APFloat *ConstRHS, bool LookThroughSrc) {
40134019
// fcmp ord x, zero|normal|subnormal|inf -> ~fcNan
40144020
if (Pred == FCmpInst::FCMP_ORD && !ConstRHS->isNaN())
40154021
return {LHS, ~fcNan};

llvm/test/Transforms/Attributor/nofpclass.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -600,8 +600,7 @@ define half @assume_fcmp_fabs_with_other_fabs_assume_fallback(half %arg) {
600600
; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]]
601601
; CHECK-NEXT: [[UNRELATED_FABS:%.*]] = fcmp oeq half [[FABS]], 0xH0000
602602
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR16]]
603-
; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
604-
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR16]]
603+
; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]]
605604
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan inf norm) [[ARG]])
606605
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan inf nzero sub norm) [[FABS]])
607606
; CHECK-NEXT: ret half [[ARG]]

llvm/test/Transforms/InstCombine/fcmp.ll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -718,9 +718,7 @@ define i1 @is_signbit_clear_nonzero(double %x) {
718718

719719
define i1 @is_signbit_set_simplify_zero(double %x) {
720720
; CHECK-LABEL: @is_signbit_set_simplify_zero(
721-
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0.000000e+00, double [[X:%.*]])
722-
; CHECK-NEXT: [[R:%.*]] = fcmp ogt double [[S]], 0.000000e+00
723-
; CHECK-NEXT: ret i1 [[R]]
721+
; CHECK-NEXT: ret i1 false
724722
;
725723
%s = call double @llvm.copysign.f64(double 0.0, double %x)
726724
%r = fcmp ogt double %s, 0.0
@@ -731,9 +729,7 @@ define i1 @is_signbit_set_simplify_zero(double %x) {
731729

732730
define i1 @is_signbit_set_simplify_nan(double %x) {
733731
; CHECK-LABEL: @is_signbit_set_simplify_nan(
734-
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0xFFFFFFFFFFFFFFFF, double [[X:%.*]])
735-
; CHECK-NEXT: [[R:%.*]] = fcmp ogt double [[S]], 0.000000e+00
736-
; CHECK-NEXT: ret i1 [[R]]
732+
; CHECK-NEXT: ret i1 false
737733
;
738734
%s = call double @llvm.copysign.f64(double 0xffffffffffffffff, double %x)
739735
%r = fcmp ogt double %s, 0.0

llvm/test/Transforms/InstCombine/is_fpclass.ll

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,8 +2444,7 @@ define <2 x i1> @test_class_fneg_fabs_posinf_negnormal_possubnormal_negzero_nan_
24442444

24452445
define i1 @test_class_is_zero_nozero_src(float nofpclass(zero) %arg) {
24462446
; CHECK-LABEL: @test_class_is_zero_nozero_src(
2447-
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0.000000e+00
2448-
; CHECK-NEXT: ret i1 [[CLASS]]
2447+
; CHECK-NEXT: ret i1 false
24492448
;
24502449
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 96)
24512450
ret i1 %class
@@ -2578,8 +2577,7 @@ define i1 @test_class_is_neginf_or_nopinf_src(float nofpclass(pinf) %arg) {
25782577

25792578
define i1 @test_class_is_neginf_noninf_src(float nofpclass(ninf) %arg) {
25802579
; CHECK-LABEL: @test_class_is_neginf_noninf_src(
2581-
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0xFFF0000000000000
2582-
; CHECK-NEXT: ret i1 [[CLASS]]
2580+
; CHECK-NEXT: ret i1 false
25832581
;
25842582
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 4)
25852583
ret i1 %class
@@ -2604,8 +2602,7 @@ define i1 @test_class_is_posinf_noninf_src(float nofpclass(ninf) %arg) {
26042602

26052603
define i1 @test_class_is_posinf_nopinf_src(float nofpclass(pinf) %arg) {
26062604
; CHECK-LABEL: @test_class_is_posinf_nopinf_src(
2607-
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0x7FF0000000000000
2608-
; CHECK-NEXT: ret i1 [[CLASS]]
2605+
; CHECK-NEXT: ret i1 false
26092606
;
26102607
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 512)
26112608
ret i1 %class
@@ -2733,8 +2730,7 @@ define i1 @test_class_is_nan_assume_uno(float %x) {
27332730
; CHECK-LABEL: @test_class_is_nan_assume_uno(
27342731
; CHECK-NEXT: [[ORD:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
27352732
; CHECK-NEXT: call void @llvm.assume(i1 [[ORD]])
2736-
; CHECK-NEXT: [[CLASS:%.*]] = fcmp uno float [[X]], 0.000000e+00
2737-
; CHECK-NEXT: ret i1 [[CLASS]]
2733+
; CHECK-NEXT: ret i1 true
27382734
;
27392735
%ord = fcmp uno float %x, 0.0
27402736
call void @llvm.assume(i1 %ord)

0 commit comments

Comments
 (0)