@@ -4164,6 +4164,147 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS,
4164
4164
return {Src, Mask};
4165
4165
}
4166
4166
4167
+ std::tuple<Value *, FPClassTest, FPClassTest>
4168
+ llvm::fcmpImpliesClass (CmpInst::Predicate Pred, const Function &F, Value *LHS,
4169
+ const APFloat *ConstRHS, bool LookThroughSrc) {
4170
+ auto [Val, ClassMask] =
4171
+ fcmpToClassTest (Pred, F, LHS, ConstRHS, LookThroughSrc);
4172
+ if (Val)
4173
+ return {Val, ClassMask, ~ClassMask};
4174
+
4175
+ FPClassTest RHSClass = ConstRHS->classify ();
4176
+
4177
+ // If we see a zero here, we are using dynamic denormal-fp-math, and can't
4178
+ // treat comparisons to 0 as an exact class test.
4179
+ //
4180
+ // TODO: We could do better and still recognize non-equality cases.
4181
+ if (RHSClass == fcPosZero || RHSClass == fcNegZero)
4182
+ return {nullptr , fcAllFlags, fcAllFlags};
4183
+
4184
+ assert ((RHSClass == fcPosNormal || RHSClass == fcNegNormal ||
4185
+ RHSClass == fcPosSubnormal || RHSClass == fcNegSubnormal) &&
4186
+ " should have been recognized as an exact class test" );
4187
+
4188
+ const bool IsNegativeRHS = (RHSClass & fcNegative) == RHSClass;
4189
+ const bool IsPositiveRHS = (RHSClass & fcPositive) == RHSClass;
4190
+
4191
+ assert (IsNegativeRHS == ConstRHS->isNegative ());
4192
+ assert (IsPositiveRHS == !ConstRHS->isNegative ());
4193
+
4194
+ Value *Src = LHS;
4195
+ const bool IsFabs = LookThroughSrc && match (LHS, m_FAbs (m_Value (Src)));
4196
+
4197
+ if (IsFabs)
4198
+ RHSClass = llvm::inverse_fabs (RHSClass);
4199
+
4200
+ if (Pred == FCmpInst::FCMP_OEQ)
4201
+ return {Src, RHSClass, fcAllFlags};
4202
+
4203
+ if (Pred == FCmpInst::FCMP_UEQ) {
4204
+ FPClassTest Class = RHSClass | fcNan;
4205
+ return {Src, Class, ~fcNan};
4206
+ }
4207
+
4208
+ if (Pred == FCmpInst::FCMP_ONE)
4209
+ return {Src, ~fcNan, RHSClass};
4210
+
4211
+ if (Pred == FCmpInst::FCMP_UNE)
4212
+ return {Src, fcAllFlags, RHSClass};
4213
+
4214
+ if (IsNegativeRHS) {
4215
+ // TODO: Handle fneg(fabs)
4216
+ if (IsFabs) {
4217
+ // fabs(x) o> -k -> fcmp ord x, x
4218
+ // fabs(x) u> -k -> true
4219
+ // fabs(x) o< -k -> false
4220
+ // fabs(x) u< -k -> fcmp uno x, x
4221
+ switch (Pred) {
4222
+ case FCmpInst::FCMP_OGT:
4223
+ case FCmpInst::FCMP_OGE:
4224
+ return {Src, ~fcNan, fcNan};
4225
+ case FCmpInst::FCMP_UGT:
4226
+ case FCmpInst::FCMP_UGE:
4227
+ return {Src, fcAllFlags, fcNone};
4228
+ case FCmpInst::FCMP_OLT:
4229
+ case FCmpInst::FCMP_OLE:
4230
+ return {Src, fcNone, fcAllFlags};
4231
+ case FCmpInst::FCMP_ULT:
4232
+ case FCmpInst::FCMP_ULE:
4233
+ return {Src, fcNan, ~fcNan};
4234
+ default :
4235
+ break ;
4236
+ }
4237
+
4238
+ return {nullptr , fcAllFlags, fcAllFlags};
4239
+ }
4240
+
4241
+ FPClassTest ClassesLE = fcNegInf | fcNegNormal;
4242
+ FPClassTest ClassesGE = fcPositive | fcNegZero | fcNegSubnormal;
4243
+
4244
+ if (ConstRHS->isDenormal ())
4245
+ ClassesLE |= fcNegSubnormal;
4246
+ else
4247
+ ClassesGE |= fcNegNormal;
4248
+
4249
+ switch (Pred) {
4250
+ case FCmpInst::FCMP_OGT:
4251
+ case FCmpInst::FCMP_OGE:
4252
+ return {Src, ClassesGE, ~ClassesGE | RHSClass};
4253
+ case FCmpInst::FCMP_UGT:
4254
+ case FCmpInst::FCMP_UGE:
4255
+ return {Src, ClassesGE | fcNan, ~(ClassesGE | fcNan) | RHSClass};
4256
+ case FCmpInst::FCMP_OLT:
4257
+ case FCmpInst::FCMP_OLE:
4258
+ return {Src, ClassesLE, ~ClassesLE | RHSClass};
4259
+ case FCmpInst::FCMP_ULT:
4260
+ case FCmpInst::FCMP_ULE:
4261
+ return {Src, ClassesLE | fcNan, ~(ClassesLE | fcNan) | RHSClass};
4262
+ default :
4263
+ break ;
4264
+ }
4265
+ } else if (IsPositiveRHS) {
4266
+ FPClassTest ClassesGE = fcPosNormal | fcPosInf;
4267
+ FPClassTest ClassesLE = fcNegative | fcPosZero | fcPosNormal;
4268
+ if (ConstRHS->isDenormal ())
4269
+ ClassesGE |= fcPosNormal;
4270
+ else
4271
+ ClassesLE |= fcPosSubnormal;
4272
+
4273
+ if (IsFabs) {
4274
+ ClassesGE = llvm::inverse_fabs (ClassesGE);
4275
+ ClassesLE = llvm::inverse_fabs (ClassesLE);
4276
+ }
4277
+
4278
+ switch (Pred) {
4279
+ case FCmpInst::FCMP_OGT:
4280
+ case FCmpInst::FCMP_OGE:
4281
+ return {Src, ClassesGE, ~ClassesGE | RHSClass};
4282
+ case FCmpInst::FCMP_UGT:
4283
+ case FCmpInst::FCMP_UGE:
4284
+ return {Src, ClassesGE | fcNan, ~(ClassesGE | fcNan) | RHSClass};
4285
+ case FCmpInst::FCMP_OLT:
4286
+ case FCmpInst::FCMP_OLE:
4287
+ return {Src, ClassesLE, ~ClassesLE | RHSClass};
4288
+ case FCmpInst::FCMP_ULT:
4289
+ case FCmpInst::FCMP_ULE:
4290
+ return {Src, ClassesLE | fcNan, ~(ClassesLE | fcNan) | RHSClass};
4291
+ default :
4292
+ break ;
4293
+ }
4294
+ }
4295
+
4296
+ return {nullptr , fcAllFlags, fcAllFlags};
4297
+ }
4298
+
4299
+ std::tuple<Value *, FPClassTest, FPClassTest>
4300
+ llvm::fcmpImpliesClass (CmpInst::Predicate Pred, const Function &F, Value *LHS,
4301
+ Value *RHS, bool LookThroughSrc) {
4302
+ const APFloat *ConstRHS;
4303
+ if (!match (RHS, m_APFloatAllowUndef (ConstRHS)))
4304
+ return {nullptr , fcAllFlags, fcNone};
4305
+ return fcmpImpliesClass (Pred, F, LHS, ConstRHS, LookThroughSrc);
4306
+ }
4307
+
4167
4308
static FPClassTest computeKnownFPClassFromAssumes (const Value *V,
4168
4309
const SimplifyQuery &Q) {
4169
4310
FPClassTest KnownFromAssume = fcAllFlags;
@@ -4188,18 +4329,21 @@ static FPClassTest computeKnownFPClassFromAssumes(const Value *V,
4188
4329
Value *LHS, *RHS;
4189
4330
uint64_t ClassVal = 0 ;
4190
4331
if (match (I->getArgOperand (0 ), m_FCmp (Pred, m_Value (LHS), m_Value (RHS)))) {
4191
- auto [TestedValue, TestedMask] =
4192
- fcmpToClassTest (Pred, *F, LHS, RHS, true );
4193
- // First see if we can fold in fabs/fneg into the test.
4194
- if (TestedValue == V)
4195
- KnownFromAssume &= TestedMask;
4196
- else {
4197
- // Try again without the lookthrough if we found a different source
4198
- // value.
4199
- auto [TestedValue, TestedMask] =
4200
- fcmpToClassTest (Pred, *F, LHS, RHS, false );
4201
- if (TestedValue == V)
4202
- KnownFromAssume &= TestedMask;
4332
+ const APFloat *CRHS;
4333
+ if (match (RHS, m_APFloat (CRHS))) {
4334
+ // First see if we can fold in fabs/fneg into the test.
4335
+ auto [CmpVal, MaskIfTrue, MaskIfFalse] =
4336
+ fcmpImpliesClass (Pred, *F, LHS, CRHS, true );
4337
+ if (CmpVal == V)
4338
+ KnownFromAssume &= MaskIfTrue;
4339
+ else {
4340
+ // Try again without the lookthrough if we found a different source
4341
+ // value.
4342
+ auto [CmpVal, MaskIfTrue, MaskIfFalse] =
4343
+ fcmpImpliesClass (Pred, *F, LHS, CRHS, false );
4344
+ if (CmpVal == V)
4345
+ KnownFromAssume &= MaskIfTrue;
4346
+ }
4203
4347
}
4204
4348
} else if (match (I->getArgOperand (0 ),
4205
4349
m_Intrinsic<Intrinsic::is_fpclass>(
@@ -4347,7 +4491,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
4347
4491
FPClassTest FilterRHS = fcAllFlags;
4348
4492
4349
4493
Value *TestedValue = nullptr ;
4350
- FPClassTest TestedMask = fcNone;
4494
+ FPClassTest MaskIfTrue = fcAllFlags;
4495
+ FPClassTest MaskIfFalse = fcAllFlags;
4351
4496
uint64_t ClassVal = 0 ;
4352
4497
const Function *F = cast<Instruction>(Op)->getFunction ();
4353
4498
CmpInst::Predicate Pred;
@@ -4359,20 +4504,22 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
4359
4504
// TODO: In some degenerate cases we can infer something if we try again
4360
4505
// without looking through sign operations.
4361
4506
bool LookThroughFAbsFNeg = CmpLHS != LHS && CmpLHS != RHS;
4362
- std::tie (TestedValue, TestedMask ) =
4363
- fcmpToClassTest (Pred, *F, CmpLHS, CmpRHS, LookThroughFAbsFNeg);
4507
+ std::tie (TestedValue, MaskIfTrue, MaskIfFalse ) =
4508
+ fcmpImpliesClass (Pred, *F, CmpLHS, CmpRHS, LookThroughFAbsFNeg);
4364
4509
} else if (match (Cond,
4365
4510
m_Intrinsic<Intrinsic::is_fpclass>(
4366
4511
m_Value (TestedValue), m_ConstantInt (ClassVal)))) {
4367
- TestedMask = static_cast <FPClassTest>(ClassVal);
4512
+ FPClassTest TestedMask = static_cast <FPClassTest>(ClassVal);
4513
+ MaskIfTrue = TestedMask;
4514
+ MaskIfFalse = ~TestedMask;
4368
4515
}
4369
4516
4370
4517
if (TestedValue == LHS) {
4371
4518
// match !isnan(x) ? x : y
4372
- FilterLHS = TestedMask ;
4373
- } else if (TestedValue == RHS) {
4519
+ FilterLHS = MaskIfTrue ;
4520
+ } else if (TestedValue == RHS) { // && IsExactClass
4374
4521
// match !isnan(x) ? y : x
4375
- FilterRHS = ~TestedMask ;
4522
+ FilterRHS = MaskIfFalse ;
4376
4523
}
4377
4524
4378
4525
KnownFPClass Known2;
0 commit comments