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