@@ -4245,6 +4245,140 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS,
4245
4245
return {Src, Mask};
4246
4246
}
4247
4247
4248
+ std::tuple<Value *, FPClassTest, FPClassTest>
4249
+ llvm::fcmpImpliesClass (CmpInst::Predicate Pred, const Function &F, Value *LHS,
4250
+ const APFloat *ConstRHS, bool LookThroughSrc) {
4251
+ auto [Val, ClassMask] =
4252
+ fcmpToClassTest (Pred, F, LHS, ConstRHS, LookThroughSrc);
4253
+ if (Val)
4254
+ return {Val, ClassMask, ~ClassMask};
4255
+
4256
+ FPClassTest RHSClass = ConstRHS->classify ();
4257
+ assert ((RHSClass == fcPosNormal || RHSClass == fcNegNormal ||
4258
+ RHSClass == fcPosSubnormal || RHSClass == fcNegSubnormal) &&
4259
+ " should have been recognized as an exact class test" );
4260
+
4261
+ const bool IsNegativeRHS = (RHSClass & fcNegative) == RHSClass;
4262
+ const bool IsPositiveRHS = (RHSClass & fcPositive) == RHSClass;
4263
+
4264
+ assert (IsNegativeRHS == ConstRHS->isNegative ());
4265
+ assert (IsPositiveRHS == !ConstRHS->isNegative ());
4266
+
4267
+ Value *Src = LHS;
4268
+ const bool IsFabs = LookThroughSrc && match (LHS, m_FAbs (m_Value (Src)));
4269
+
4270
+ if (IsFabs)
4271
+ RHSClass = llvm::inverse_fabs (RHSClass);
4272
+
4273
+ if (Pred == FCmpInst::FCMP_OEQ)
4274
+ return {Src, RHSClass, fcAllFlags};
4275
+
4276
+ if (Pred == FCmpInst::FCMP_UEQ) {
4277
+ FPClassTest Class = RHSClass | fcNan;
4278
+ return {Src, Class, ~fcNan};
4279
+ }
4280
+
4281
+ if (Pred == FCmpInst::FCMP_ONE)
4282
+ return {Src, ~fcNan, RHSClass};
4283
+
4284
+ if (Pred == FCmpInst::FCMP_UNE)
4285
+ return {Src, fcAllFlags, RHSClass};
4286
+
4287
+ if (IsNegativeRHS) {
4288
+ // TODO: Handle fneg(fabs)
4289
+ if (IsFabs) {
4290
+ // fabs(x) o> -k -> fcmp ord x, x
4291
+ // fabs(x) u> -k -> true
4292
+ // fabs(x) o< -k -> false
4293
+ // fabs(x) u< -k -> fcmp uno x, x
4294
+ switch (Pred) {
4295
+ case FCmpInst::FCMP_OGT:
4296
+ case FCmpInst::FCMP_OGE:
4297
+ return {Src, ~fcNan, fcNan};
4298
+ case FCmpInst::FCMP_UGT:
4299
+ case FCmpInst::FCMP_UGE:
4300
+ return {Src, fcAllFlags, fcNone};
4301
+ case FCmpInst::FCMP_OLT:
4302
+ case FCmpInst::FCMP_OLE:
4303
+ return {Src, fcNone, fcAllFlags};
4304
+ case FCmpInst::FCMP_ULT:
4305
+ case FCmpInst::FCMP_ULE:
4306
+ return {Src, fcNan, ~fcNan};
4307
+ default :
4308
+ break ;
4309
+ }
4310
+
4311
+ return {nullptr , fcAllFlags, fcAllFlags};
4312
+ }
4313
+
4314
+ FPClassTest ClassesLE = fcNegInf | fcNegNormal;
4315
+ FPClassTest ClassesGE = fcPositive | fcNegZero | fcNegSubnormal;
4316
+
4317
+ if (ConstRHS->isDenormal ())
4318
+ ClassesLE |= fcNegSubnormal;
4319
+ else
4320
+ ClassesGE |= fcNegNormal;
4321
+
4322
+ switch (Pred) {
4323
+ case FCmpInst::FCMP_OGT:
4324
+ case FCmpInst::FCMP_OGE:
4325
+ return {Src, ClassesGE, ~ClassesGE | RHSClass};
4326
+ case FCmpInst::FCMP_UGT:
4327
+ case FCmpInst::FCMP_UGE:
4328
+ return {Src, ClassesGE | fcNan, ~(ClassesGE | fcNan) | RHSClass};
4329
+ case FCmpInst::FCMP_OLT:
4330
+ case FCmpInst::FCMP_OLE:
4331
+ return {Src, ClassesLE, ~ClassesLE | RHSClass};
4332
+ case FCmpInst::FCMP_ULT:
4333
+ case FCmpInst::FCMP_ULE:
4334
+ return {Src, ClassesLE | fcNan, ~(ClassesLE | fcNan) | RHSClass};
4335
+ default :
4336
+ break ;
4337
+ }
4338
+ } else if (IsPositiveRHS) {
4339
+ FPClassTest ClassesGE = fcPosNormal | fcPosInf;
4340
+ FPClassTest ClassesLE = fcNegative | fcPosZero | fcPosNormal;
4341
+ if (ConstRHS->isDenormal ())
4342
+ ClassesGE |= fcPosNormal;
4343
+ else
4344
+ ClassesLE |= fcPosSubnormal;
4345
+
4346
+ FPClassTest FalseClasses = RHSClass;
4347
+ if (IsFabs) {
4348
+ ClassesGE = llvm::inverse_fabs (ClassesGE);
4349
+ ClassesLE = llvm::inverse_fabs (ClassesLE);
4350
+ }
4351
+
4352
+ switch (Pred) {
4353
+ case FCmpInst::FCMP_OGT:
4354
+ case FCmpInst::FCMP_OGE:
4355
+ return {Src, ClassesGE, ~ClassesGE | FalseClasses};
4356
+ case FCmpInst::FCMP_UGT:
4357
+ case FCmpInst::FCMP_UGE:
4358
+ return {Src, ClassesGE | fcNan, ~(ClassesGE | fcNan) | FalseClasses};
4359
+ case FCmpInst::FCMP_OLT:
4360
+ case FCmpInst::FCMP_OLE:
4361
+ return {Src, ClassesLE, ~ClassesLE | FalseClasses};
4362
+ case FCmpInst::FCMP_ULT:
4363
+ case FCmpInst::FCMP_ULE:
4364
+ return {Src, ClassesLE | fcNan, ~(ClassesLE | fcNan) | FalseClasses};
4365
+ default :
4366
+ break ;
4367
+ }
4368
+ }
4369
+
4370
+ return {nullptr , fcAllFlags, fcAllFlags};
4371
+ }
4372
+
4373
+ std::tuple<Value *, FPClassTest, FPClassTest>
4374
+ llvm::fcmpImpliesClass (CmpInst::Predicate Pred, const Function &F, Value *LHS,
4375
+ Value *RHS, bool LookThroughSrc) {
4376
+ const APFloat *ConstRHS;
4377
+ if (!match (RHS, m_APFloatAllowUndef (ConstRHS)))
4378
+ return {nullptr , fcAllFlags, fcNone};
4379
+ return fcmpImpliesClass (Pred, F, LHS, ConstRHS, LookThroughSrc);
4380
+ }
4381
+
4248
4382
static FPClassTest computeKnownFPClassFromAssumes (const Value *V,
4249
4383
const SimplifyQuery &Q) {
4250
4384
FPClassTest KnownFromAssume = fcAllFlags;
@@ -4269,18 +4403,21 @@ static FPClassTest computeKnownFPClassFromAssumes(const Value *V,
4269
4403
Value *LHS, *RHS;
4270
4404
uint64_t ClassVal = 0 ;
4271
4405
if (match (I->getArgOperand (0 ), m_FCmp (Pred, m_Value (LHS), m_Value (RHS)))) {
4272
- auto [TestedValue, TestedMask] =
4273
- fcmpToClassTest (Pred, *F, LHS, RHS, true );
4274
- // First see if we can fold in fabs/fneg into the test.
4275
- if (TestedValue == V)
4276
- KnownFromAssume &= TestedMask;
4277
- else {
4278
- // Try again without the lookthrough if we found a different source
4279
- // value.
4280
- auto [TestedValue, TestedMask] =
4281
- fcmpToClassTest (Pred, *F, LHS, RHS, false );
4282
- if (TestedValue == V)
4283
- KnownFromAssume &= TestedMask;
4406
+ const APFloat *CRHS;
4407
+ if (match (RHS, m_APFloat (CRHS))) {
4408
+ // First see if we can fold in fabs/fneg into the test.
4409
+ auto [CmpVal, MaskIfTrue, MaskIfFalse] =
4410
+ fcmpImpliesClass (Pred, *F, LHS, CRHS, true );
4411
+ if (CmpVal == V)
4412
+ KnownFromAssume &= MaskIfTrue;
4413
+ else {
4414
+ // Try again without the lookthrough if we found a different source
4415
+ // value.
4416
+ auto [CmpVal, MaskIfTrue, MaskIfFalse] =
4417
+ fcmpImpliesClass (Pred, *F, LHS, CRHS, false );
4418
+ if (CmpVal == V)
4419
+ KnownFromAssume &= MaskIfTrue;
4420
+ }
4284
4421
}
4285
4422
} else if (match (I->getArgOperand (0 ),
4286
4423
m_Intrinsic<Intrinsic::is_fpclass>(
@@ -4428,7 +4565,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
4428
4565
FPClassTest FilterRHS = fcAllFlags;
4429
4566
4430
4567
Value *TestedValue = nullptr ;
4431
- FPClassTest TestedMask = fcNone;
4568
+ FPClassTest MaskIfTrue = fcAllFlags;
4569
+ FPClassTest MaskIfFalse = fcAllFlags;
4432
4570
uint64_t ClassVal = 0 ;
4433
4571
const Function *F = cast<Instruction>(Op)->getFunction ();
4434
4572
CmpInst::Predicate Pred;
@@ -4440,20 +4578,22 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
4440
4578
// TODO: In some degenerate cases we can infer something if we try again
4441
4579
// without looking through sign operations.
4442
4580
bool LookThroughFAbsFNeg = CmpLHS != LHS && CmpLHS != RHS;
4443
- std::tie (TestedValue, TestedMask ) =
4444
- fcmpToClassTest (Pred, *F, CmpLHS, CmpRHS, LookThroughFAbsFNeg);
4581
+ std::tie (TestedValue, MaskIfTrue, MaskIfFalse ) =
4582
+ fcmpImpliesClass (Pred, *F, CmpLHS, CmpRHS, LookThroughFAbsFNeg);
4445
4583
} else if (match (Cond,
4446
4584
m_Intrinsic<Intrinsic::is_fpclass>(
4447
4585
m_Value (TestedValue), m_ConstantInt (ClassVal)))) {
4448
- TestedMask = static_cast <FPClassTest>(ClassVal);
4586
+ FPClassTest TestedMask = static_cast <FPClassTest>(ClassVal);
4587
+ MaskIfTrue = TestedMask;
4588
+ MaskIfFalse = ~TestedMask;
4449
4589
}
4450
4590
4451
4591
if (TestedValue == LHS) {
4452
4592
// match !isnan(x) ? x : y
4453
- FilterLHS = TestedMask ;
4454
- } else if (TestedValue == RHS) {
4593
+ FilterLHS = MaskIfTrue ;
4594
+ } else if (TestedValue == RHS) { // && IsExactClass
4455
4595
// match !isnan(x) ? y : x
4456
- FilterRHS = ~TestedMask ;
4596
+ FilterRHS = MaskIfFalse ;
4457
4597
}
4458
4598
4459
4599
KnownFPClass Known2;
0 commit comments