@@ -4060,19 +4060,6 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
4060
4060
if (Pred == FCmpInst::FCMP_TRUE)
4061
4061
return getTrue (RetTy);
4062
4062
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
-
4076
4063
// fcmp pred x, poison and fcmp pred poison, x
4077
4064
// fold to poison
4078
4065
if (isa<PoisonValue>(LHS) || isa<PoisonValue>(RHS))
@@ -4094,80 +4081,86 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
4094
4081
return getFalse (RetTy);
4095
4082
}
4096
4083
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
+ }
4127
4094
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)
4139
4120
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)
4143
4122
return getTrue (RetTy);
4144
4123
}
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.
4145
4131
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
4146
4136
assert (!C->isNaN () && " Unexpected NaN constant!" );
4147
4137
// TODO: We can catch more cases by using a range check rather than
4148
4138
// relying on CannotBeOrderedLessThanZero.
4149
4139
switch (Pred) {
4150
4140
case FCmpInst::FCMP_UGE:
4151
4141
case FCmpInst::FCMP_UGT:
4152
- case FCmpInst::FCMP_UNE:
4142
+ case FCmpInst::FCMP_UNE: {
4143
+ KnownFPClass KnownClass = computeLHSClass (Interested);
4144
+
4153
4145
// (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 ())
4156
4147
return getTrue (RetTy);
4157
4148
break ;
4149
+ }
4158
4150
case FCmpInst::FCMP_OEQ:
4159
4151
case FCmpInst::FCMP_OLE:
4160
- case FCmpInst::FCMP_OLT:
4152
+ case FCmpInst::FCMP_OLT: {
4153
+ KnownFPClass KnownClass = computeLHSClass (Interested);
4154
+
4161
4155
// (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 ())
4164
4157
return getFalse (RetTy);
4165
4158
break ;
4159
+ }
4166
4160
default :
4167
4161
break ;
4168
4162
}
4169
4163
}
4170
-
4171
4164
// Check comparison of [minnum/maxnum with constant] with other constant.
4172
4165
const APFloat *C2;
4173
4166
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,
4214
4207
}
4215
4208
}
4216
4209
4210
+ // TODO: Could fold this with above if there were a matcher which returned all
4211
+ // classes in a non-splat vector.
4217
4212
if (match (RHS, m_AnyZeroFP ())) {
4218
4213
switch (Pred) {
4219
4214
case FCmpInst::FCMP_OGE:
4220
4215
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);
4224
4221
4225
4222
// Positive or zero X >= 0.0 --> true
4226
4223
// Positive or zero X < 0.0 --> false
@@ -4230,12 +4227,16 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
4230
4227
break ;
4231
4228
}
4232
4229
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
+
4234
4234
// Positive or zero or nan X >= 0.0 --> true
4235
4235
// 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 ())
4237
4237
return Pred == FCmpInst::FCMP_UGE ? getTrue (RetTy) : getFalse (RetTy);
4238
4238
break ;
4239
+ }
4239
4240
default :
4240
4241
break ;
4241
4242
}
@@ -6816,6 +6817,9 @@ static Value *simplifyInstructionWithOperands(Instruction *I,
6816
6817
const SimplifyQuery &SQ,
6817
6818
unsigned MaxRecurse) {
6818
6819
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
+
6819
6823
const SimplifyQuery Q = SQ.CxtI ? SQ : SQ.getWithInstruction (I);
6820
6824
6821
6825
switch (I->getOpcode ()) {
0 commit comments