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