return Builder.CreateFCmp(FCmpInst::getOrderedPredicate(PredR), RHS0, RHS1);
}
+/// Returns a pair of values, which if passed to llvm.is.fpclass, returns the
+/// same result as an fcmp with the given operands.
+static std::pair<Value *, unsigned> fcmpToClassTest(FCmpInst::Predicate Pred,
+ Value *LHS, Value *RHS) {
+ const APFloat *ConstRHS;
+ if (!match(RHS, m_APFloat(ConstRHS)))
+ return {nullptr, 0};
+
+ if (ConstRHS->isZero()) {
+ switch (Pred) {
+ // TODO: Compares eq/ne with 0 depends on the denormal handling mode.
+ case FCmpInst::FCMP_ORD:
+ // Canonical form of ord/uno is with a zero. We could also handle
+ // non-canonical other non-NaN constants or LHS == RHS.
+ return {LHS, ~fcNan & fcAllFlags};
+ case FCmpInst::FCMP_UNO:
+ return {LHS, fcNan};
+ default:
+ break;
+ }
+
+ return {nullptr, 0};
+ }
+
+ Value *Src = LHS;
+ const bool IsFabs = match(LHS, m_FAbs(m_Value(Src)));
+
+ // Compute the test mask that would return true for the ordered comparisons.
+ unsigned Mask;
+
+ if (ConstRHS->isInfinity()) {
+ switch (Pred) {
+ case FCmpInst::FCMP_OEQ:
+ case FCmpInst::FCMP_UNE: {
+ // Match __builtin_isinf patterns
+ //
+ // fcmp oeq x, +inf -> is_fpclass x, fcPosInf
+ // fcmp oeq fabs(x), +inf -> is_fpclass x, fcInf
+ // fcmp oeq x, -inf -> is_fpclass x, fcNegInf
+ // fcmp oeq fabs(x), -inf -> is_fpclass x, 0 -> false
+ //
+ // fcmp une x, +inf -> is_fpclass x, ~fcPosInf
+ // fcmp une fabs(x), +inf -> is_fpclass x, ~fcInf
+ // fcmp une x, -inf -> is_fpclass x, ~fcNegInf
+ // fcmp une fabs(x), -inf -> is_fpclass x, fcAllFlags -> true
+
+ if (ConstRHS->isNegative()) {
+ Mask = fcNegInf;
+ if (IsFabs)
+ Mask = 0;
+ } else {
+ Mask = fcPosInf;
+ if (IsFabs)
+ Mask |= fcNegInf;
+ }
+
+ break;
+ }
+ case FCmpInst::FCMP_ONE:
+ case FCmpInst::FCMP_UEQ: {
+ // Match __builtin_isinf patterns
+ // fcmp one x, -inf -> is_fpclass x, fcNegInf
+ // fcmp one fabs(x), -inf -> is_fpclass x, ~fcNegInf & ~fcNan
+ // fcmp one x, +inf -> is_fpclass x, ~fcNegInf & ~fcNan
+ // fcmp one fabs(x), +inf -> is_fpclass x, ~fcInf & fcNan
+ //
+ // fcmp ueq x, +inf -> is_fpclass x, fcPosInf|fcNan
+ // fcmp ueq (fabs x), +inf -> is_fpclass x, fcInf|fcNan
+ // fcmp ueq x, -inf -> is_fpclass x, fcNegInf|fcNan
+ // fcmp ueq fabs(x), -inf -> is_fpclass x, fcNan
+ if (ConstRHS->isNegative()) {
+ Mask = ~fcNegInf & ~fcNan;
+ if (IsFabs)
+ Mask = ~fcNan;
+ } else {
+ Mask = ~fcPosInf & ~fcNan;
+ if (IsFabs)
+ Mask &= ~fcNegInf;
+ }
+
+ Mask &= fcAllFlags;
+ break;
+ }
+ case FCmpInst::FCMP_OLT:
+ case FCmpInst::FCMP_UGE: {
+ if (ConstRHS->isNegative()) // TODO
+ return {nullptr, 0};
+
+ // fcmp olt fabs(x), +inf -> fcFinite
+ // fcmp uge fabs(x), +inf -> ~fcFinite
+ // fcmp olt x, +inf -> fcFinite|fcNegInf
+ // fcmp uge x, +inf -> ~(fcFinite|fcNegInf)
+ Mask = fcFinite;
+ if (!IsFabs)
+ Mask |= fcNegInf;
+ break;
+ }
+ case FCmpInst::FCMP_OGE:
+ case FCmpInst::FCMP_ULT: {
+ if (ConstRHS->isNegative()) // TODO
+ return {nullptr, 0};
+
+ // fcmp oge fabs(x), +inf -> fcInf
+ // fcmp oge x, +inf -> fcPosInf
+ // fcmp ult fabs(x), +inf -> ~fcInf
+ // fcmp ult x, +inf -> ~fcPosInf
+ Mask = fcPosInf;
+ if (IsFabs)
+ Mask |= fcNegInf;
+ break;
+ }
+ default:
+ return {nullptr, 0};
+ }
+ } else if (ConstRHS->isSmallestNormalized() && !ConstRHS->isNegative()) {
+ // Match pattern that's used in __builtin_isnormal.
+ switch (Pred) {
+ case FCmpInst::FCMP_OLT:
+ case FCmpInst::FCMP_UGE: {
+ // fcmp olt x, smallest_normal -> fcNegInf|fcNegNormal|fcSubnormal|fcZero
+ // fcmp olt fabs(x), smallest_normal -> fcSubnormal|fcZero
+ // fcmp uge x, smallest_normal -> fcNan|fcPosNormal|fcPosInf
+ // fcmp uge fabs(x), smallest_normal -> ~(fcSubnormal|fcZero)
+ Mask = fcZero | fcSubnormal;
+ if (!IsFabs)
+ Mask |= fcNegNormal | fcNegInf;
+
+ break;
+ }
+ case FCmpInst::FCMP_OGE:
+ case FCmpInst::FCMP_ULT: {
+ // fcmp oge x, smallest_normal -> fcPosNormal | fcPosInf
+ // fcmp oge fabs(x), smallest_normal -> fcInf | fcNormal
+ // fcmp ult x, smallest_normal -> ~(fcPosNormal | fcPosInf)
+ // fcmp ult fabs(x), smallest_normal -> ~(fcInf | fcNormal)
+ Mask = fcPosInf | fcPosNormal;
+ if (IsFabs)
+ Mask |= fcNegInf | fcNegNormal;
+ break;
+ }
+ default:
+ return {nullptr, 0};
+ }
+ } else
+ return {nullptr, 0};
+
+ // Invert the comparison for the unordered cases.
+ if (FCmpInst::isUnordered(Pred))
+ Mask = ~Mask & fcAllFlags;
+
+ assert((Mask & ~fcAllFlags) == 0);
+
+ return {Src, Mask};
+}
+
Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS,
bool IsAnd, bool IsLogicalSelect) {
Value *LHS0 = LHS->getOperand(0), *LHS1 = LHS->getOperand(1);
return nullptr;
}
+/// Match an fcmp against a special value that performs a test possible by
+/// llvm.is.fpclass.
+static bool matchIsFPClassLikeFCmp(Value *Op, Value *&ClassVal,
+ uint64_t &ClassMask) {
+ auto *FCmp = dyn_cast<FCmpInst>(Op);
+ if (!FCmp || !FCmp->hasOneUse())
+ return false;
+
+ std::tie(ClassVal, ClassMask) = fcmpToClassTest(
+ FCmp->getPredicate(), FCmp->getOperand(0), FCmp->getOperand(1));
+ return ClassVal != nullptr;
+}
+
/// or (is_fpclass x, mask0), (is_fpclass x, mask1)
/// -> is_fpclass x, (mask0 | mask1)
/// and (is_fpclass x, mask0), (is_fpclass x, mask1)
/// -> is_fpclass x, (mask0 ^ mask1)
Instruction *InstCombinerImpl::foldLogicOfIsFPClass(BinaryOperator &BO,
Value *Op0, Value *Op1) {
- Value *ClassVal;
+ Value *ClassVal0 = nullptr;
+ Value *ClassVal1 = nullptr;
uint64_t ClassMask0, ClassMask1;
- if (match(Op0, m_OneUse(m_Intrinsic<Intrinsic::is_fpclass>(
- m_Value(ClassVal), m_ConstantInt(ClassMask0)))) &&
+ // Restrict to folding one fcmp into one is.fpclass for now, don't introduce a
+ // new class.
+ //
+ // TODO: Support forming is.fpclass out of 2 separate fcmps when codegen is
+ // better.
+
+ bool IsLHSClass =
+ match(Op0, m_OneUse(m_Intrinsic<Intrinsic::is_fpclass>(
+ m_Value(ClassVal0), m_ConstantInt(ClassMask0))));
+ bool IsRHSClass =
match(Op1, m_OneUse(m_Intrinsic<Intrinsic::is_fpclass>(
- m_Specific(ClassVal), m_ConstantInt(ClassMask1))))) {
+ m_Value(ClassVal1), m_ConstantInt(ClassMask1))));
+ if (((IsLHSClass && IsRHSClass) ||
+ ((!IsLHSClass && matchIsFPClassLikeFCmp(Op0, ClassVal0, ClassMask0)) ||
+ (!IsRHSClass && matchIsFPClassLikeFCmp(Op1, ClassVal1, ClassMask1)))) &&
+ ClassVal0 == ClassVal1) {
unsigned NewClassMask;
switch (BO.getOpcode()) {
case Instruction::And:
llvm_unreachable("not a binary logic operator");
}
- // TODO: Also check for special fcmps
- auto *II = cast<IntrinsicInst>(Op0);
+ auto *II = IsLHSClass ? cast<IntrinsicInst>(Op0) : cast<IntrinsicInst>(Op1);
II->setArgOperand(
1, ConstantInt::get(II->getArgOperand(1)->getType(), NewClassMask));
return replaceInstUsesWith(BO, II);
define i1 @fcmp_oeq_inf_or_class_normal(half %x) {
; CHECK-LABEL: @fcmp_oeq_inf_or_class_normal(
-; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
-; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[OEQ_INF]], [[CLASS]]
-; CHECK-NEXT: ret i1 [[OR]]
+; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776)
+; CHECK-NEXT: ret i1 [[CLASS]]
;
%oeq.inf = fcmp oeq half %x, 0xH7C00
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
define i1 @class_normal_or_fcmp_oeq_inf(half %x) {
; CHECK-LABEL: @class_normal_or_fcmp_oeq_inf(
-; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
-; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[CLASS]], [[OEQ_INF]]
-; CHECK-NEXT: ret i1 [[OR]]
+; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776)
+; CHECK-NEXT: ret i1 [[CLASS]]
;
%oeq.inf = fcmp oeq half %x, 0xH7C00
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
define <2 x i1> @fcmp_oeq_inf_or_class_normal_vector(<2 x half> %x) {
; CHECK-LABEL: @fcmp_oeq_inf_or_class_normal_vector(
-; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq <2 x half> [[X:%.*]], <half 0xH7C00, half 0xH7C00>
-; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X]], i32 264)
-; CHECK-NEXT: [[OR:%.*]] = or <2 x i1> [[OEQ_INF]], [[CLASS]]
-; CHECK-NEXT: ret <2 x i1> [[OR]]
+; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 776)
+; CHECK-NEXT: ret <2 x i1> [[CLASS]]
;
%oeq.inf = fcmp oeq <2 x half> %x, <half 0xH7C00, half 0xH7C00>
%class = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> %x, i32 264)
define i1 @fcmp_isfinite_and_class_subnormal(half %x) {
; CHECK-LABEL: @fcmp_isfinite_and_class_subnormal(
-; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT: [[IS_FINITE:%.*]] = fcmp olt half [[FABS]], 0xH7C00
-; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 144)
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[IS_FINITE]], [[SUBNORMAL_CLASS]]
-; CHECK-NEXT: ret i1 [[AND]]
+; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 144)
+; CHECK-NEXT: ret i1 [[SUBNORMAL_CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.finite = fcmp olt half %fabs, 0xH7C00
define i1 @fcmp_isfinite_or_class_subnormal(half %x) {
; CHECK-LABEL: @fcmp_isfinite_or_class_subnormal(
-; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT: [[IS_FINITE:%.*]] = fcmp olt half [[FABS]], 0xH7C00
-; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 144)
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_FINITE]], [[SUBNORMAL_CLASS]]
-; CHECK-NEXT: ret i1 [[OR]]
+; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 504)
+; CHECK-NEXT: ret i1 [[SUBNORMAL_CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.finite = fcmp olt half %fabs, 0xH7C00
; -> isfinite
define i1 @fcmp_issubnormal_or_class_finite(half %x) {
; CHECK-LABEL: @fcmp_issubnormal_or_class_finite(
-; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 504)
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_SUBNORMAL]], [[IS_FINITE_CLASS]]
-; CHECK-NEXT: ret i1 [[OR]]
+; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 504)
+; CHECK-NEXT: ret i1 [[IS_FINITE_CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.subnormal = fcmp olt half %fabs, 0xH0400
; -> isfinite
define i1 @class_finite_or_fcmp_issubnormal(half %x) {
; CHECK-LABEL: @class_finite_or_fcmp_issubnormal(
-; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 504)
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_FINITE_CLASS]], [[IS_SUBNORMAL]]
-; CHECK-NEXT: ret i1 [[OR]]
+; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 504)
+; CHECK-NEXT: ret i1 [[IS_FINITE_CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.subnormal = fcmp olt half %fabs, 0xH0400
; -> issubnormal
define i1 @fcmp_issubnormal_and_class_finite(half %x) {
; CHECK-LABEL: @fcmp_issubnormal_and_class_finite(
-; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 504)
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[IS_SUBNORMAL]], [[IS_FINITE_CLASS]]
-; CHECK-NEXT: ret i1 [[AND]]
+; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 240)
+; CHECK-NEXT: ret i1 [[IS_FINITE_CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.subnormal = fcmp olt half %fabs, 0xH0400
define i1 @class_inf_or_fcmp_issubnormal(half %x) {
; CHECK-LABEL: @class_inf_or_fcmp_issubnormal(
-; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT: [[IS_INF_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 516)
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_INF_CLASS]], [[IS_SUBNORMAL]]
-; CHECK-NEXT: ret i1 [[OR]]
+; CHECK-NEXT: [[IS_INF_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 756)
+; CHECK-NEXT: ret i1 [[IS_INF_CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.subnormal = fcmp olt half %fabs, 0xH0400
; -> isfinite
define <2 x i1> @class_finite_or_fcmp_issubnormal_vector(<2 x half> %x) {
; CHECK-LABEL: @class_finite_or_fcmp_issubnormal_vector(
-; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]])
-; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt <2 x half> [[FABS]], <half 0xH0400, half 0xH0400>
-; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X]], i32 504)
-; CHECK-NEXT: [[OR:%.*]] = or <2 x i1> [[IS_FINITE_CLASS]], [[IS_SUBNORMAL]]
-; CHECK-NEXT: ret <2 x i1> [[OR]]
+; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 504)
+; CHECK-NEXT: ret <2 x i1> [[IS_FINITE_CLASS]]
;
%fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
%is.subnormal = fcmp olt <2 x half> %fabs, <half 0xH0400, half 0xH0400>
define i1 @fcmp_oeq_inf_xor_class_normal(half %x) {
; CHECK-LABEL: @fcmp_oeq_inf_xor_class_normal(
-; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
-; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
-; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[OEQ_INF]], [[CLASS]]
-; CHECK-NEXT: ret i1 [[XOR]]
+; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776)
+; CHECK-NEXT: ret i1 [[CLASS]]
;
%oeq.inf = fcmp oeq half %x, 0xH7C00
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
define i1 @class_normal_xor_fcmp_oeq_inf(half %x) {
; CHECK-LABEL: @class_normal_xor_fcmp_oeq_inf(
-; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
-; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
-; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CLASS]], [[OEQ_INF]]
-; CHECK-NEXT: ret i1 [[XOR]]
+; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776)
+; CHECK-NEXT: ret i1 [[CLASS]]
;
%oeq.inf = fcmp oeq half %x, 0xH7C00
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
define i1 @test_fold_or_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_or_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 1)
-; CHECK-NEXT: [[CLASS1:%.*]] = fcmp uno float [[A]], 0.000000e+00
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[CLASS0]], [[CLASS1]]
-; CHECK-NEXT: ret i1 [[OR]]
+; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[CLASS0]]
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1)
%class1 = fcmp uno float %a, 0.000000e+00
define i1 @test_fold_or3_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_or3_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4)
-; CHECK-NEXT: [[OR_1:%.*]] = or i1 [[CLASS0]], [[CLASS2]]
-; CHECK-NEXT: ret i1 [[OR_1]]
+; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 7)
+; CHECK-NEXT: ret i1 [[CLASS2]]
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1)
%class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2)
define i1 @test_fold_or_all_tests_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_or_all_tests_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4)
-; CHECK-NEXT: [[CLASS3:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 8)
-; CHECK-NEXT: [[CLASS4:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 16)
-; CHECK-NEXT: [[CLASS5:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 32)
-; CHECK-NEXT: [[CLASS6:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 64)
-; CHECK-NEXT: [[CLASS7:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 128)
-; CHECK-NEXT: [[CLASS8:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 256)
-; CHECK-NEXT: [[CLASS9:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 512)
-; CHECK-NEXT: [[OR_1:%.*]] = or i1 [[CLASS0]], [[CLASS2]]
-; CHECK-NEXT: [[OR_2:%.*]] = or i1 [[OR_1]], [[CLASS3]]
-; CHECK-NEXT: [[OR_3:%.*]] = or i1 [[OR_2]], [[CLASS4]]
-; CHECK-NEXT: [[OR_4:%.*]] = or i1 [[OR_3]], [[CLASS5]]
-; CHECK-NEXT: [[OR_5:%.*]] = or i1 [[OR_4]], [[CLASS6]]
-; CHECK-NEXT: [[OR_6:%.*]] = or i1 [[OR_5]], [[CLASS7]]
-; CHECK-NEXT: [[OR_7:%.*]] = or i1 [[OR_6]], [[CLASS8]]
-; CHECK-NEXT: [[OR_8:%.*]] = or i1 [[OR_7]], [[CLASS9]]
-; CHECK-NEXT: ret i1 [[OR_8]]
+; CHECK-NEXT: ret i1 true
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1)
%class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2)
define i1 @test_fold_and_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_and_class_f32_0(
; CHECK-NEXT: [[CLASS0:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 1)
-; CHECK-NEXT: [[CLASS1:%.*]] = fcmp uno float [[A]], 0.000000e+00
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CLASS0]], [[CLASS1]]
-; CHECK-NEXT: ret i1 [[AND]]
+; CHECK-NEXT: ret i1 [[CLASS0]]
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1)
%class1 = fcmp uno float %a, 0.000000e+00
define i1 @test_fold_and3_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_and3_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CLASS1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 2)
-; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 7)
-; CHECK-NEXT: [[AND_0:%.*]] = and i1 [[CLASS0]], [[CLASS1]]
-; CHECK-NEXT: [[AND_1:%.*]] = and i1 [[AND_0]], [[CLASS2]]
-; CHECK-NEXT: ret i1 [[AND_1]]
+; CHECK-NEXT: [[CLASS1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 2)
+; CHECK-NEXT: ret i1 [[CLASS1]]
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 3)
%class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2)
define i1 @test_fold_and_not_all_tests_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_and_not_all_tests_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = fcmp ord float [[A:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 1019)
-; CHECK-NEXT: [[CLASS3:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 1015)
-; CHECK-NEXT: [[CLASS4:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 1007)
-; CHECK-NEXT: [[CLASS5:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 991)
-; CHECK-NEXT: [[CLASS6:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 959)
-; CHECK-NEXT: [[CLASS7:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 895)
-; CHECK-NEXT: [[CLASS8:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 767)
-; CHECK-NEXT: [[CLASS9:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 511)
-; CHECK-NEXT: [[AND_1:%.*]] = and i1 [[CLASS0]], [[CLASS2]]
-; CHECK-NEXT: [[AND_2:%.*]] = and i1 [[AND_1]], [[CLASS3]]
-; CHECK-NEXT: [[AND_3:%.*]] = and i1 [[AND_2]], [[CLASS4]]
-; CHECK-NEXT: [[AND_4:%.*]] = and i1 [[AND_3]], [[CLASS5]]
-; CHECK-NEXT: [[AND_5:%.*]] = and i1 [[AND_4]], [[CLASS6]]
-; CHECK-NEXT: [[AND_6:%.*]] = and i1 [[AND_5]], [[CLASS7]]
-; CHECK-NEXT: [[AND_7:%.*]] = and i1 [[AND_6]], [[CLASS8]]
-; CHECK-NEXT: [[AND_8:%.*]] = and i1 [[AND_7]], [[CLASS9]]
-; CHECK-NEXT: ret i1 [[AND_8]]
+; CHECK-NEXT: ret i1 false
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1022)
%class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 1021)
define i1 @test_fold_xor_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_xor_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 1)
-; CHECK-NEXT: [[CLASS1:%.*]] = fcmp uno float [[A]], 0.000000e+00
-; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CLASS0]], [[CLASS1]]
-; CHECK-NEXT: ret i1 [[XOR]]
+; CHECK-NEXT: [[CLASS0:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 2)
+; CHECK-NEXT: ret i1 [[CLASS0]]
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1)
%class1 = fcmp uno float %a, 0.000000e+00
define i1 @test_fold_xor3_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_xor3_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4)
-; CHECK-NEXT: [[XOR_1:%.*]] = xor i1 [[CLASS0]], [[CLASS2]]
-; CHECK-NEXT: ret i1 [[XOR_1]]
+; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 7)
+; CHECK-NEXT: ret i1 [[CLASS2]]
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1)
%class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2)
define i1 @test_fold_xor_all_tests_class_f32_0(float %a) {
; CHECK-LABEL: @test_fold_xor_all_tests_class_f32_0(
-; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4)
-; CHECK-NEXT: [[CLASS3:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 8)
-; CHECK-NEXT: [[CLASS4:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 16)
-; CHECK-NEXT: [[CLASS5:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 32)
-; CHECK-NEXT: [[CLASS6:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 64)
-; CHECK-NEXT: [[CLASS7:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 128)
-; CHECK-NEXT: [[CLASS8:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 256)
-; CHECK-NEXT: [[CLASS9:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 512)
-; CHECK-NEXT: [[XOR_1:%.*]] = xor i1 [[CLASS0]], [[CLASS2]]
-; CHECK-NEXT: [[XOR_2:%.*]] = xor i1 [[XOR_1]], [[CLASS3]]
-; CHECK-NEXT: [[XOR_3:%.*]] = xor i1 [[XOR_2]], [[CLASS4]]
-; CHECK-NEXT: [[XOR_4:%.*]] = xor i1 [[XOR_3]], [[CLASS5]]
-; CHECK-NEXT: [[XOR_5:%.*]] = xor i1 [[XOR_4]], [[CLASS6]]
-; CHECK-NEXT: [[XOR_6:%.*]] = xor i1 [[XOR_5]], [[CLASS7]]
-; CHECK-NEXT: [[XOR_7:%.*]] = xor i1 [[XOR_6]], [[CLASS8]]
-; CHECK-NEXT: [[XOR_8:%.*]] = xor i1 [[XOR_7]], [[CLASS9]]
-; CHECK-NEXT: ret i1 [[XOR_8]]
+; CHECK-NEXT: ret i1 true
;
%class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1)
%class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2)