modes.
+Floating-Point Test Intrinsics
+------------------------------
+
+These functions get properties of floating-point values.
+
+
+'``llvm.is.fpclass``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+ declare i1 @llvm.is.fpclass(<fptype> <op>, i32 <test>)
+ declare <N x i1> @llvm.is.fpclass(<vector-fptype> <op>, i32 <test>)
+
+Overview:
+"""""""""
+
+The '``llvm.is.fpclass``' intrinsic returns a boolean value or vector of boolean
+values depending on whether the first argument satisfies the test specified by
+the second argument.
+
+If the first argument is a floating-point scalar, then the result type is a
+boolean (:ref:`i1 <t_integer>`).
+
+If the first argument is a floating-point vector, then the result type is a
+vector of boolean with the same number of elements as the first argument.
+
+Arguments:
+""""""""""
+
+The first argument to the '``llvm.is.fpclass``' intrinsic must be
+:ref:`floating-point <t_floating>` or :ref:`vector <t_vector>`
+of floating-point values.
+
+The second argument specifies, which tests to perform. It is an integer value,
+each bit in which specifies floating-point class:
+
++-------+----------------------+
+| Bit # | floating-point class |
++=======+======================+
+| 0 | Signaling NaN |
++-------+----------------------+
+| 1 | Quiet NaN |
++-------+----------------------+
+| 2 | Negative infinity |
++-------+----------------------+
+| 3 | Negative normal |
++-------+----------------------+
+| 4 | Negative subnormal |
++-------+----------------------+
+| 5 | Negative zero |
++-------+----------------------+
+| 6 | Positive zero |
++-------+----------------------+
+| 7 | Positive subnormal |
++-------+----------------------+
+| 8 | Positive normal |
++-------+----------------------+
+| 9 | Positive infinity |
++-------+----------------------+
+
+Semantics:
+""""""""""
+
+The function checks if ``op`` belongs to any of the floating-point classes
+specified by ``test``. If ``op`` is a vector, then the check is made element by
+element. Each check yields an :ref:`i1 <t_integer>` result, which is ``true``,
+if the element value satisfies the specified test. The argument ``test`` is a
+bit mask where each bit specifies floating-point class to test. For example, the
+value 0x108 makes test for normal value, - bits 3 and 8 in it are set, which
+means that the function returns ``true`` if ``op`` is a positive or negative
+normal value. The function never raises floating-point exceptions.
+
+
General Intrinsics
------------------
//===----------------------------------------------------------------------===//
///
/// \file
-/// Utilities for dealing with flags related to floating point mode controls.
+/// Utilities for dealing with flags related to floating point properties and
+/// mode controls.
///
//===----------------------------------------------------------------------===/
}
+/// Floating-point class tests, supported by 'is_fpclass' intrinsic. Actual
+/// test may be an OR combination of basic tests.
+enum FPClassTest {
+ fcSNan = 0x0001,
+ fcQNan = 0x0002,
+ fcNegInf = 0x0004,
+ fcNegNormal = 0x0008,
+ fcNegSubnormal = 0x0010,
+ fcNegZero = 0x0020,
+ fcPosZero = 0x0040,
+ fcPosSubnormal = 0x0080,
+ fcPosNormal = 0x0100,
+ fcPosInf = 0x0200,
+
+ fcNan = fcSNan | fcQNan,
+ fcInf = fcPosInf | fcNegInf,
+ fcNormal = fcPosNormal | fcNegNormal,
+ fcSubnormal = fcPosSubnormal | fcNegSubnormal,
+ fcZero = fcPosZero | fcNegZero,
+ fcPosFinite = fcPosNormal | fcPosSubnormal | fcPosZero,
+ fcNegFinite = fcNegNormal | fcNegSubnormal | fcNegZero,
+ fcFinite = fcPosFinite | fcNegFinite,
+ fcAllFlags = fcNan | fcInf | fcFinite
+};
+
#endif // LLVM_ADT_FLOATINGPOINTMODE_H
MachineBasicBlock::iterator
findSplitPointForStackProtector(MachineBasicBlock *BB,
const TargetInstrInfo &TII);
+/// Evaluates if the specified FP class test is an inversion of a simpler test.
+/// An example is the test "inf|normal|subnormal|zero", which is an inversion
+/// of "nan".
+/// \param Test The test as specified in 'is_fpclass' intrinsic invocation.
+/// \returns The inverted test, or zero, if inversion does not produce simpler
+/// test.
+unsigned getInvertedFPClassTest(unsigned Test);
} // namespace llvm
/// Returns platform specific canonical encoding of a floating point number.
FCANONICALIZE,
+ /// Performs a check of floating point class property, defined by IEEE-754.
+ /// The first operand is the floating point value to check. The second operand
+ /// specifies the checked property and is a TargetConstant which specifies
+ /// test in the same way as intrinsic 'is_fpclass'.
+ /// Returns boolean value.
+ IS_FPCLASS,
+
/// BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector
/// with the specified, possibly variable, elements. The types of the
/// operands must match the vector element type, except that integer types
/// \returns The expansion result
SDValue expandFP_TO_INT_SAT(SDNode *N, SelectionDAG &DAG) const;
+ /// Expand check for floating point class.
+ /// \param ResultVT The type of intrinsic call result.
+ /// \param Op The tested value.
+ /// \param Test The test to perform.
+ /// \param Flags The optimization flags.
+ /// \returns The expansion result or SDValue() if it fails.
+ SDValue expandIS_FPCLASS(EVT ResultVT, SDValue Op, unsigned Test,
+ SDNodeFlags Flags, const SDLoc &DL,
+ SelectionDAG &DAG) const;
+
/// Expand CTPOP nodes. Expands vector/scalar CTPOP nodes,
/// vector nodes can only succeed if all operations are legal/custom.
/// \param N Node to expand
def int_set_rounding : DefaultAttrsIntrinsic<[], [llvm_i32_ty]>;
}
+//===--------------- Floating Point Properties ----------------------------===//
+//
+
+def int_is_fpclass
+ : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>],
+ [llvm_anyfloat_ty, llvm_i32_ty],
+ [IntrNoMem, IntrWillReturn, ImmArg<ArgIndex<1>>]>;
+
//===--------------- Constrained Floating Point Intrinsics ----------------===//
//
return SplitPoint;
}
+
+unsigned llvm::getInvertedFPClassTest(unsigned Test) {
+ unsigned InvertedTest = ~Test & fcAllFlags;
+ switch (InvertedTest) {
+ default:
+ break;
+ case fcNan:
+ case fcSNan:
+ case fcQNan:
+ case fcInf:
+ case fcPosInf:
+ case fcNegInf:
+ case fcNormal:
+ case fcPosNormal:
+ case fcNegNormal:
+ case fcSubnormal:
+ case fcPosSubnormal:
+ case fcNegSubnormal:
+ case fcZero:
+ case fcPosZero:
+ case fcNegZero:
+ case fcFinite:
+ case fcPosFinite:
+ case fcNegFinite:
+ return InvertedTest;
+ }
+ return 0;
+}
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/CodeGen/CodeGenCommonISel.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
case ISD::VECREDUCE_UMIN:
case ISD::VECREDUCE_FMAX:
case ISD::VECREDUCE_FMIN:
+ case ISD::IS_FPCLASS:
Action = TLI.getOperationAction(
Node->getOpcode(), Node->getOperand(0).getValueType());
break;
case ISD::FABS:
Results.push_back(ExpandFABS(Node));
break;
+ case ISD::IS_FPCLASS: {
+ auto CNode = cast<ConstantSDNode>(Node->getOperand(1));
+ auto Test = static_cast<FPClassTest>(CNode->getZExtValue());
+ if (SDValue Expanded =
+ TLI.expandIS_FPCLASS(Node->getValueType(0), Node->getOperand(0),
+ Test, Node->getFlags(), SDLoc(Node), DAG))
+ Results.push_back(Expanded);
+ break;
+ }
case ISD::SMIN:
case ISD::SMAX:
case ISD::UMIN:
case ISD::FSHR:
Res = PromoteIntRes_FunnelShift(N);
break;
+
+ case ISD::IS_FPCLASS:
+ Res = PromoteIntRes_IS_FPCLASS(N);
+ break;
}
// If the result is null then the sub-method took care of registering it.
return DAG.getSExtOrTrunc(SetCC, dl, NVT);
}
+SDValue DAGTypeLegalizer::PromoteIntRes_IS_FPCLASS(SDNode *N) {
+ SDLoc DL(N);
+ SDValue Arg = N->getOperand(0);
+ SDValue Test = N->getOperand(1);
+ EVT NResVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
+ return DAG.getNode(ISD::IS_FPCLASS, DL, NResVT, Arg, Test);
+}
+
SDValue DAGTypeLegalizer::PromoteIntRes_SHL(SDNode *N) {
SDValue LHS = GetPromotedInteger(N->getOperand(0));
SDValue RHS = N->getOperand(1);
SDValue PromoteIntRes_ABS(SDNode *N);
SDValue PromoteIntRes_Rotate(SDNode *N);
SDValue PromoteIntRes_FunnelShift(SDNode *N);
+ SDValue PromoteIntRes_IS_FPCLASS(SDNode *N);
// Integer Operand Promotion.
bool PromoteIntegerOperand(SDNode *N, unsigned OpNo);
SDValue ScalarizeVecRes_UNDEF(SDNode *N);
SDValue ScalarizeVecRes_VECTOR_SHUFFLE(SDNode *N);
SDValue ScalarizeVecRes_FP_TO_XINT_SAT(SDNode *N);
+ SDValue ScalarizeVecRes_IS_FPCLASS(SDNode *N);
SDValue ScalarizeVecRes_FIX(SDNode *N);
void SplitVecRes_INSERT_SUBVECTOR(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_FPOWI(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_FCOPYSIGN(SDNode *N, SDValue &Lo, SDValue &Hi);
+ void SplitVecRes_IS_FPCLASS(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_LOAD(LoadSDNode *LD, SDValue &Lo, SDValue &Hi);
void SplitVecRes_VP_LOAD(VPLoadSDNode *LD, SDValue &Lo, SDValue &Hi);
SDValue WidenVecRes_Convert_StrictFP(SDNode *N);
SDValue WidenVecRes_FP_TO_XINT_SAT(SDNode *N);
SDValue WidenVecRes_FCOPYSIGN(SDNode *N);
+ SDValue WidenVecRes_IS_FPCLASS(SDNode *N);
SDValue WidenVecRes_POWI(SDNode *N);
SDValue WidenVecRes_Unary(SDNode *N);
SDValue WidenVecRes_InregOp(SDNode *N);
SDValue WidenVecOp_Convert(SDNode *N);
SDValue WidenVecOp_FP_TO_XINT_SAT(SDNode *N);
SDValue WidenVecOp_FCOPYSIGN(SDNode *N);
+ SDValue WidenVecOp_IS_FPCLASS(SDNode *N);
SDValue WidenVecOp_VECREDUCE(SDNode *N);
SDValue WidenVecOp_VECREDUCE_SEQ(SDNode *N);
SDValue WidenVecOp_VP_REDUCE(SDNode *N);
case ISD::SETCC: R = ScalarizeVecRes_SETCC(N); break;
case ISD::UNDEF: R = ScalarizeVecRes_UNDEF(N); break;
case ISD::VECTOR_SHUFFLE: R = ScalarizeVecRes_VECTOR_SHUFFLE(N); break;
+ case ISD::IS_FPCLASS: R = ScalarizeVecRes_IS_FPCLASS(N); break;
case ISD::ANY_EXTEND_VECTOR_INREG:
case ISD::SIGN_EXTEND_VECTOR_INREG:
case ISD::ZERO_EXTEND_VECTOR_INREG:
return DAG.getNode(ExtendCode, DL, NVT, Res);
}
+SDValue DAGTypeLegalizer::ScalarizeVecRes_IS_FPCLASS(SDNode *N) {
+ SDLoc DL(N);
+ SDValue Arg = N->getOperand(0);
+ SDValue Test = N->getOperand(1);
+ EVT ArgVT = Arg.getValueType();
+ EVT ResultVT = N->getValueType(0).getVectorElementType();
+
+ if (getTypeAction(ArgVT) == TargetLowering::TypeScalarizeVector) {
+ Arg = GetScalarizedVector(Arg);
+ } else {
+ EVT VT = ArgVT.getVectorElementType();
+ Arg = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Arg,
+ DAG.getVectorIdxConstant(0, DL));
+ }
+
+ SDValue Res =
+ DAG.getNode(ISD::IS_FPCLASS, DL, MVT::i1, {Arg, Test}, N->getFlags());
+ // Vectors may have a different boolean contents to scalars. Promote the
+ // value appropriately.
+ ISD::NodeType ExtendCode =
+ TargetLowering::getExtendForContent(TLI.getBooleanContents(ArgVT));
+ return DAG.getNode(ExtendCode, DL, ResultVT, Res);
+}
//===----------------------------------------------------------------------===//
// Operand Vector Scalarization <1 x ty> -> ty.
case ISD::INSERT_SUBVECTOR: SplitVecRes_INSERT_SUBVECTOR(N, Lo, Hi); break;
case ISD::FPOWI: SplitVecRes_FPOWI(N, Lo, Hi); break;
case ISD::FCOPYSIGN: SplitVecRes_FCOPYSIGN(N, Lo, Hi); break;
+ case ISD::IS_FPCLASS: SplitVecRes_IS_FPCLASS(N, Lo, Hi); break;
case ISD::INSERT_VECTOR_ELT: SplitVecRes_INSERT_VECTOR_ELT(N, Lo, Hi); break;
case ISD::SPLAT_VECTOR:
case ISD::SCALAR_TO_VECTOR:
Hi = DAG.getNode(ISD::FCOPYSIGN, DL, LHSHi.getValueType(), LHSHi, RHSHi);
}
+void DAGTypeLegalizer::SplitVecRes_IS_FPCLASS(SDNode *N, SDValue &Lo,
+ SDValue &Hi) {
+ SDLoc DL(N);
+ SDValue ArgLo, ArgHi;
+ SDValue Test = N->getOperand(1);
+ GetSplitVector(N->getOperand(0), ArgLo, ArgHi);
+ EVT LoVT, HiVT;
+ std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
+
+ Lo = DAG.getNode(ISD::IS_FPCLASS, DL, LoVT, ArgLo, Test, N->getFlags());
+ Hi = DAG.getNode(ISD::IS_FPCLASS, DL, HiVT, ArgHi, Test, N->getFlags());
+}
+
void DAGTypeLegalizer::SplitVecRes_InregOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue LHSLo, LHSHi;
Res = WidenVecRes_FCOPYSIGN(N);
break;
+ case ISD::IS_FPCLASS:
+ Res = WidenVecRes_IS_FPCLASS(N);
+ break;
+
case ISD::FPOWI:
Res = WidenVecRes_POWI(N);
break;
return DAG.UnrollVectorOp(N, WidenVT.getVectorNumElements());
}
+SDValue DAGTypeLegalizer::WidenVecRes_IS_FPCLASS(SDNode *N) {
+ EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
+ SDValue Arg = GetWidenedVector(N->getOperand(0));
+ return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT, {Arg, N->getOperand(1)},
+ N->getFlags());
+}
+
SDValue DAGTypeLegalizer::WidenVecRes_POWI(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue InOp = GetWidenedVector(N->getOperand(0));
case ISD::STRICT_FSETCCS: Res = WidenVecOp_STRICT_FSETCC(N); break;
case ISD::VSELECT: Res = WidenVecOp_VSELECT(N); break;
case ISD::FCOPYSIGN: Res = WidenVecOp_FCOPYSIGN(N); break;
+ case ISD::IS_FPCLASS: Res = WidenVecOp_IS_FPCLASS(N); break;
case ISD::ANY_EXTEND:
case ISD::SIGN_EXTEND:
return DAG.UnrollVectorOp(N);
}
+SDValue DAGTypeLegalizer::WidenVecOp_IS_FPCLASS(SDNode *N) {
+ SDLoc DL(N);
+ EVT ResultVT = N->getValueType(0);
+ SDValue Test = N->getOperand(1);
+ SDValue WideArg = GetWidenedVector(N->getOperand(0));
+
+ // Process this node similarly to SETCC.
+ EVT WideResultVT = getSetCCResultType(WideArg.getValueType());
+ if (ResultVT.getScalarType() == MVT::i1)
+ WideResultVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
+ WideResultVT.getVectorNumElements());
+
+ SDValue WideNode = DAG.getNode(ISD::IS_FPCLASS, DL, WideResultVT,
+ {WideArg, Test}, N->getFlags());
+
+ // Extract the needed results from the result vector.
+ EVT ResVT =
+ EVT::getVectorVT(*DAG.getContext(), WideResultVT.getVectorElementType(),
+ ResultVT.getVectorNumElements());
+ SDValue CC = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResVT, WideNode,
+ DAG.getVectorIdxConstant(0, DL));
+
+ EVT OpVT = N->getOperand(0).getValueType();
+ ISD::NodeType ExtendCode =
+ TargetLowering::getExtendForContent(TLI.getBooleanContents(OpVT));
+ return DAG.getNode(ExtendCode, DL, ResultVT, CC);
+}
+
SDValue DAGTypeLegalizer::WidenVecOp_Convert(SDNode *N) {
// Since the result is legal and the input is illegal.
EVT VT = N->getValueType(0);
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/Analysis.h"
+#include "llvm/CodeGen/CodeGenCommonISel.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/GCMetadata.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
setValue(&I, Res);
DAG.setRoot(Res.getValue(0));
return;
+ case Intrinsic::is_fpclass: {
+ const DataLayout DLayout = DAG.getDataLayout();
+ EVT DestVT = TLI.getValueType(DLayout, I.getType());
+ EVT ArgVT = TLI.getValueType(DLayout, I.getArgOperand(0)->getType());
+ unsigned Test = cast<ConstantInt>(I.getArgOperand(1))->getZExtValue();
+ MachineFunction &MF = DAG.getMachineFunction();
+ const Function &F = MF.getFunction();
+ SDValue Op = getValue(I.getArgOperand(0));
+ SDNodeFlags Flags;
+ Flags.setNoFPExcept(
+ !F.getAttributes().hasFnAttr(llvm::Attribute::StrictFP));
+ // If ISD::IS_FPCLASS should be expanded, do it right now, because the
+ // expansion can use illegal types. Making expansion early allows
+ // legalizing these types prior to selection.
+ if (!TLI.isOperationLegalOrCustom(ISD::IS_FPCLASS, ArgVT)) {
+ SDValue Result = TLI.expandIS_FPCLASS(DestVT, Op, Test, Flags, sdl, DAG);
+ setValue(&I, Result);
+ return;
+ }
+
+ SDValue Check = DAG.getTargetConstant(Test, sdl, MVT::i32);
+ SDValue V = DAG.getNode(ISD::IS_FPCLASS, sdl, DestVT, {Op, Check}, Flags);
+ setValue(&I, V);
+ return;
+ }
case Intrinsic::pcmarker: {
SDValue Tmp = getValue(I.getArgOperand(0));
DAG.setRoot(DAG.getNode(ISD::PCMARKER, sdl, MVT::Other, getRoot(), Tmp));
case ISD::FCOPYSIGN: return "fcopysign";
case ISD::FGETSIGN: return "fgetsign";
case ISD::FCANONICALIZE: return "fcanonicalize";
+ case ISD::IS_FPCLASS: return "is_fpclass";
case ISD::FPOW: return "fpow";
case ISD::STRICT_FPOW: return "strict_fpow";
case ISD::SMIN: return "smin";
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/CodeGenCommonISel.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
return SDValue();
}
+SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
+ unsigned Test, SDNodeFlags Flags,
+ const SDLoc &DL,
+ SelectionDAG &DAG) const {
+ EVT OperandVT = Op.getValueType();
+ assert(OperandVT.isFloatingPoint());
+
+ // Degenerated cases.
+ if (Test == 0 || (Test & fcAllFlags) == fcAllFlags)
+ return DAG.getBoolConstant(true, DL, ResultVT, OperandVT);
+
+ // Some checks may be represented as inversion of simpler check, for example
+ // "inf|normal|subnormal|zero" => !"nan".
+ bool IsInverted = false;
+ if (unsigned InvertedCheck = getInvertedFPClassTest(Test)) {
+ IsInverted = true;
+ Test = InvertedCheck;
+ }
+
+ // Floating-point type properties.
+ EVT ScalarFloatVT = OperandVT.getScalarType();
+ const Type *FloatTy = ScalarFloatVT.getTypeForEVT(*DAG.getContext());
+ const llvm::fltSemantics &Semantics = FloatTy->getFltSemantics();
+ bool IsF80 = (ScalarFloatVT == MVT::f80);
+
+ // Some checks can be implemented using float comparisons, if floating point
+ // exceptions are ignored.
+ if (Flags.hasNoFPExcept() &&
+ isOperationLegalOrCustom(ISD::SETCC, OperandVT.getScalarType())) {
+ if (Test == fcZero)
+ return DAG.getSetCC(DL, ResultVT, Op,
+ DAG.getConstantFP(0.0, DL, OperandVT),
+ IsInverted ? ISD::SETUNE : ISD::SETOEQ);
+ if (Test == fcNan)
+ return DAG.getSetCC(DL, ResultVT, Op, Op,
+ IsInverted ? ISD::SETO : ISD::SETUO);
+ }
+
+ // In the general case use integer operations.
+ unsigned BitSize = OperandVT.getScalarSizeInBits();
+ EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), BitSize);
+ if (OperandVT.isVector())
+ IntVT = EVT::getVectorVT(*DAG.getContext(), IntVT,
+ OperandVT.getVectorElementCount());
+ SDValue OpAsInt = DAG.getBitcast(IntVT, Op);
+
+ // Various masks.
+ APInt SignBit = APInt::getSignMask(BitSize);
+ APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
+ APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
+ const unsigned ExplicitIntBitInF80 = 63;
+ APInt ExpMask = Inf;
+ if (IsF80)
+ ExpMask.clearBit(ExplicitIntBitInF80);
+ APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
+ APInt QNaNBitMask =
+ APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
+ APInt InvertionMask = APInt::getAllOnesValue(ResultVT.getScalarSizeInBits());
+
+ SDValue ValueMaskV = DAG.getConstant(ValueMask, DL, IntVT);
+ SDValue SignBitV = DAG.getConstant(SignBit, DL, IntVT);
+ SDValue ExpMaskV = DAG.getConstant(ExpMask, DL, IntVT);
+ SDValue ZeroV = DAG.getConstant(0, DL, IntVT);
+ SDValue InfV = DAG.getConstant(Inf, DL, IntVT);
+ SDValue ResultInvertionMask = DAG.getConstant(InvertionMask, DL, ResultVT);
+
+ SDValue Res;
+ const auto appendResult = [&](SDValue PartialRes) {
+ if (PartialRes) {
+ if (Res)
+ Res = DAG.getNode(ISD::OR, DL, ResultVT, Res, PartialRes);
+ else
+ Res = PartialRes;
+ }
+ };
+
+ SDValue IntBitIsSetV; // Explicit integer bit in f80 mantissa is set.
+ const auto getIntBitIsSet = [&]() -> SDValue {
+ if (!IntBitIsSetV) {
+ APInt IntBitMask(BitSize, 0);
+ IntBitMask.setBit(ExplicitIntBitInF80);
+ SDValue IntBitMaskV = DAG.getConstant(IntBitMask, DL, IntVT);
+ SDValue IntBitV = DAG.getNode(ISD::AND, DL, IntVT, OpAsInt, IntBitMaskV);
+ IntBitIsSetV = DAG.getSetCC(DL, ResultVT, IntBitV, ZeroV, ISD::SETNE);
+ }
+ return IntBitIsSetV;
+ };
+
+ // Split the value into sign bit and absolute value.
+ SDValue AbsV = DAG.getNode(ISD::AND, DL, IntVT, OpAsInt, ValueMaskV);
+ SDValue SignV = DAG.getSetCC(DL, ResultVT, OpAsInt,
+ DAG.getConstant(0.0, DL, IntVT), ISD::SETLT);
+
+ // Tests that involve more than one class should be processed first.
+ SDValue PartialRes;
+
+ if (IsF80)
+ ; // Detect finite numbers of f80 by checking individual classes because
+ // they have different settings of the explicit integer bit.
+ else if ((Test & fcFinite) == fcFinite) {
+ // finite(V) ==> abs(V) < exp_mask
+ PartialRes = DAG.getSetCC(DL, ResultVT, AbsV, ExpMaskV, ISD::SETLT);
+ Test &= ~fcFinite;
+ } else if ((Test & fcFinite) == fcPosFinite) {
+ // finite(V) && V > 0 ==> V < exp_mask
+ PartialRes = DAG.getSetCC(DL, ResultVT, OpAsInt, ExpMaskV, ISD::SETULT);
+ Test &= ~fcPosFinite;
+ } else if ((Test & fcFinite) == fcNegFinite) {
+ // finite(V) && V < 0 ==> abs(V) < exp_mask && signbit == 1
+ PartialRes = DAG.getSetCC(DL, ResultVT, AbsV, ExpMaskV, ISD::SETLT);
+ PartialRes = DAG.getNode(ISD::AND, DL, ResultVT, PartialRes, SignV);
+ Test &= ~fcNegFinite;
+ }
+ appendResult(PartialRes);
+
+ // Check for individual classes.
+
+ if (unsigned PartialCheck = Test & fcZero) {
+ if (PartialCheck == fcPosZero)
+ PartialRes = DAG.getSetCC(DL, ResultVT, OpAsInt, ZeroV, ISD::SETEQ);
+ else if (PartialCheck == fcZero)
+ PartialRes = DAG.getSetCC(DL, ResultVT, AbsV, ZeroV, ISD::SETEQ);
+ else // ISD::fcNegZero
+ PartialRes = DAG.getSetCC(DL, ResultVT, OpAsInt, SignBitV, ISD::SETEQ);
+ appendResult(PartialRes);
+ }
+
+ if (unsigned PartialCheck = Test & fcInf) {
+ if (PartialCheck == fcPosInf)
+ PartialRes = DAG.getSetCC(DL, ResultVT, OpAsInt, InfV, ISD::SETEQ);
+ else if (PartialCheck == fcInf)
+ PartialRes = DAG.getSetCC(DL, ResultVT, AbsV, InfV, ISD::SETEQ);
+ else { // ISD::fcNegInf
+ APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
+ SDValue NegInfV = DAG.getConstant(NegInf, DL, IntVT);
+ PartialRes = DAG.getSetCC(DL, ResultVT, OpAsInt, NegInfV, ISD::SETEQ);
+ }
+ appendResult(PartialRes);
+ }
+
+ if (unsigned PartialCheck = Test & fcNan) {
+ APInt InfWithQnanBit = Inf | QNaNBitMask;
+ SDValue InfWithQnanBitV = DAG.getConstant(InfWithQnanBit, DL, IntVT);
+ if (PartialCheck == fcNan) {
+ // isnan(V) ==> abs(V) > int(inf)
+ PartialRes = DAG.getSetCC(DL, ResultVT, AbsV, InfV, ISD::SETGT);
+ if (IsF80) {
+ // Recognize unsupported values as NaNs for compatibility with glibc.
+ // In them (exp(V)==0) == int_bit.
+ SDValue ExpBits = DAG.getNode(ISD::AND, DL, IntVT, AbsV, ExpMaskV);
+ SDValue ExpIsZero =
+ DAG.getSetCC(DL, ResultVT, ExpBits, ZeroV, ISD::SETEQ);
+ SDValue IsPseudo =
+ DAG.getSetCC(DL, ResultVT, getIntBitIsSet(), ExpIsZero, ISD::SETEQ);
+ PartialRes = DAG.getNode(ISD::OR, DL, ResultVT, PartialRes, IsPseudo);
+ }
+ } else if (PartialCheck == fcQNan) {
+ // isquiet(V) ==> abs(V) >= (unsigned(Inf) | quiet_bit)
+ PartialRes =
+ DAG.getSetCC(DL, ResultVT, AbsV, InfWithQnanBitV, ISD::SETGE);
+ } else { // ISD::fcSNan
+ // issignaling(V) ==> abs(V) > unsigned(Inf) &&
+ // abs(V) < (unsigned(Inf) | quiet_bit)
+ SDValue IsNan = DAG.getSetCC(DL, ResultVT, AbsV, InfV, ISD::SETGT);
+ SDValue IsNotQnan =
+ DAG.getSetCC(DL, ResultVT, AbsV, InfWithQnanBitV, ISD::SETLT);
+ PartialRes = DAG.getNode(ISD::AND, DL, ResultVT, IsNan, IsNotQnan);
+ }
+ appendResult(PartialRes);
+ }
+
+ if (unsigned PartialCheck = Test & fcSubnormal) {
+ // issubnormal(V) ==> unsigned(abs(V) - 1) < (all mantissa bits set)
+ // issubnormal(V) && V>0 ==> unsigned(V - 1) < (all mantissa bits set)
+ SDValue V = (PartialCheck == fcPosSubnormal) ? OpAsInt : AbsV;
+ SDValue MantissaV = DAG.getConstant(AllOneMantissa, DL, IntVT);
+ SDValue VMinusOneV =
+ DAG.getNode(ISD::SUB, DL, IntVT, V, DAG.getConstant(1, DL, IntVT));
+ PartialRes = DAG.getSetCC(DL, ResultVT, VMinusOneV, MantissaV, ISD::SETULT);
+ if (PartialCheck == fcNegSubnormal)
+ PartialRes = DAG.getNode(ISD::AND, DL, ResultVT, PartialRes, SignV);
+ appendResult(PartialRes);
+ }
+
+ if (unsigned PartialCheck = Test & fcNormal) {
+ // isnormal(V) ==> (0 < exp < max_exp) ==> (unsigned(exp-1) < (max_exp-1))
+ APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
+ SDValue ExpLSBV = DAG.getConstant(ExpLSB, DL, IntVT);
+ SDValue ExpMinus1 = DAG.getNode(ISD::SUB, DL, IntVT, AbsV, ExpLSBV);
+ APInt ExpLimit = ExpMask - ExpLSB;
+ SDValue ExpLimitV = DAG.getConstant(ExpLimit, DL, IntVT);
+ PartialRes = DAG.getSetCC(DL, ResultVT, ExpMinus1, ExpLimitV, ISD::SETULT);
+ if (PartialCheck == fcNegNormal)
+ PartialRes = DAG.getNode(ISD::AND, DL, ResultVT, PartialRes, SignV);
+ else if (PartialCheck == fcPosNormal) {
+ SDValue PosSignV =
+ DAG.getNode(ISD::XOR, DL, ResultVT, SignV, ResultInvertionMask);
+ PartialRes = DAG.getNode(ISD::AND, DL, ResultVT, PartialRes, PosSignV);
+ }
+ if (IsF80)
+ PartialRes =
+ DAG.getNode(ISD::AND, DL, ResultVT, PartialRes, getIntBitIsSet());
+ appendResult(PartialRes);
+ }
+
+ if (!Res)
+ return DAG.getConstant(IsInverted, DL, ResultVT);
+ if (IsInverted)
+ Res = DAG.getNode(ISD::XOR, DL, ResultVT, Res, ResultInvertionMask);
+ return Res;
+}
+
// Only expand vector types if we have the appropriate vector bit operations.
static bool canExpandVectorCTPOP(const TargetLowering &TLI, EVT VT) {
assert(VT.isVector() && "Expected vector type");
ISD::UMULFIX, ISD::UMULFIXSAT,
ISD::SDIVFIX, ISD::SDIVFIXSAT,
ISD::UDIVFIX, ISD::UDIVFIXSAT,
- ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT},
+ ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT,
+ ISD::IS_FPCLASS},
VT, Expand);
// Overflow operations default to expand
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=i686-linux | FileCheck %s -check-prefix=CHECK-32
+; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s -check-prefix=CHECK-64
+
+define i1 @is_nan_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_nan_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: fldt {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_nan_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: fldt {{[0-9]+}}(%rsp)
+; CHECK-64-NEXT: fucompi %st(0), %st
+; CHECK-64-NEXT: setp %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 3) ; "nan"
+ ret i1 %0
+}
+
+define i1 @is_nan_f80_strict(x86_fp80 %x) strictfp {
+; CHECK-32-LABEL: is_nan_f80_strict:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: .cfi_offset %esi, -8
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: andl $32767, %ecx # imm = 0x7FFF
+; CHECK-32-NEXT: xorl %edx, %edx
+; CHECK-32-NEXT: cmpl {{[0-9]+}}(%esp), %edx
+; CHECK-32-NEXT: movl $-2147483648, %esi # imm = 0x80000000
+; CHECK-32-NEXT: sbbl %eax, %esi
+; CHECK-32-NEXT: movl $32767, %esi # imm = 0x7FFF
+; CHECK-32-NEXT: sbbl %ecx, %esi
+; CHECK-32-NEXT: sbbl %edx, %edx
+; CHECK-32-NEXT: setl %dl
+; CHECK-32-NEXT: testl %ecx, %ecx
+; CHECK-32-NEXT: sete %cl
+; CHECK-32-NEXT: shrl $31, %eax
+; CHECK-32-NEXT: xorb %cl, %al
+; CHECK-32-NEXT: xorb $1, %al
+; CHECK-32-NEXT: orb %dl, %al
+; CHECK-32-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_nan_f80_strict:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: movabsq $-9223372036854775808, %rdx # imm = 0x8000000000000000
+; CHECK-64-NEXT: cmpq %rcx, %rdx
+; CHECK-64-NEXT: movl $32767, %edx # imm = 0x7FFF
+; CHECK-64-NEXT: sbbq %rax, %rdx
+; CHECK-64-NEXT: setl %dl
+; CHECK-64-NEXT: shrq $63, %rcx
+; CHECK-64-NEXT: testq %rax, %rax
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: xorb %cl, %al
+; CHECK-64-NEXT: xorb $1, %al
+; CHECK-64-NEXT: orb %dl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 3) ; "nan"
+ ret i1 %0
+}
+
+define i1 @is_snan_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_snan_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %ebx
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 12
+; CHECK-32-NEXT: .cfi_offset %esi, -12
+; CHECK-32-NEXT: .cfi_offset %ebx, -8
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %edx
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-32-NEXT: xorl %ecx, %ecx
+; CHECK-32-NEXT: cmpl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: movl $-2147483648, %esi # imm = 0x80000000
+; CHECK-32-NEXT: sbbl %edx, %esi
+; CHECK-32-NEXT: movl $32767, %esi # imm = 0x7FFF
+; CHECK-32-NEXT: sbbl %eax, %esi
+; CHECK-32-NEXT: movl $0, %esi
+; CHECK-32-NEXT: sbbl %esi, %esi
+; CHECK-32-NEXT: setl %bl
+; CHECK-32-NEXT: cmpl $-1073741824, %edx # imm = 0xC0000000
+; CHECK-32-NEXT: sbbl $32767, %eax # imm = 0x7FFF
+; CHECK-32-NEXT: sbbl %ecx, %ecx
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: andb %bl, %al
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: popl %ebx
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_snan_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: movabsq $-4611686018427387904, %rdx # imm = 0xC000000000000000
+; CHECK-64-NEXT: cmpq %rdx, %rcx
+; CHECK-64-NEXT: movq %rax, %rdx
+; CHECK-64-NEXT: sbbq $32767, %rdx # imm = 0x7FFF
+; CHECK-64-NEXT: setl %dl
+; CHECK-64-NEXT: movabsq $-9223372036854775808, %rsi # imm = 0x8000000000000000
+; CHECK-64-NEXT: cmpq %rcx, %rsi
+; CHECK-64-NEXT: movl $32767, %ecx # imm = 0x7FFF
+; CHECK-64-NEXT: sbbq %rax, %rcx
+; CHECK-64-NEXT: setl %al
+; CHECK-64-NEXT: andb %dl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 1) ; "snan"
+ ret i1 %0
+}
+
+define i1 @is_qnan_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_qnan_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-32-NEXT: xorl %ecx, %ecx
+; CHECK-32-NEXT: movl $-1073741825, %edx # imm = 0xBFFFFFFF
+; CHECK-32-NEXT: cmpl {{[0-9]+}}(%esp), %edx
+; CHECK-32-NEXT: movl $32767, %edx # imm = 0x7FFF
+; CHECK-32-NEXT: sbbl %eax, %edx
+; CHECK-32-NEXT: sbbl %ecx, %ecx
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_qnan_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: movabsq $-4611686018427387905, %rcx # imm = 0xBFFFFFFFFFFFFFFF
+; CHECK-64-NEXT: cmpq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: movl $32767, %ecx # imm = 0x7FFF
+; CHECK-64-NEXT: sbbq %rax, %rcx
+; CHECK-64-NEXT: setl %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 2) ; "qnan"
+ ret i1 %0
+}
+
+define i1 @is_zero_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_zero_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: fldt {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fldz
+; CHECK-32-NEXT: fucompp
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setnp %cl
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_zero_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: fldt {{[0-9]+}}(%rsp)
+; CHECK-64-NEXT: fldz
+; CHECK-64-NEXT: fucompi %st(1), %st
+; CHECK-64-NEXT: fstp %st(0)
+; CHECK-64-NEXT: setnp %cl
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 96) ; 0x60 = "zero"
+ ret i1 %0
+}
+
+define i1 @is_zero_f80_strict(x86_fp80 %x) strictfp {
+; CHECK-32-LABEL: is_zero_f80_strict:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_zero_f80_strict:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: orq {{[0-9]+}}(%rsp), %rax
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 96) ; 0x60 = "zero"
+ ret i1 %0
+}
+
+define i1 @is_poszero_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_poszero_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_poszero_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: orq {{[0-9]+}}(%rsp), %rax
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 64) ; 0x40 = "+zero"
+ ret i1 %0
+}
+
+define i1 @is_negzero_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_negzero_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: xorl $32768, %eax # imm = 0x8000
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_negzero_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: xorq $32768, %rax # imm = 0x8000
+; CHECK-64-NEXT: orq {{[0-9]+}}(%rsp), %rax
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 32) ; 0x20 = "-zero"
+ ret i1 %0
+}
+
+define i1 @is_inf_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_inf_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: notl %eax
+; CHECK-32-NEXT: movl $-2147483648, %ecx # imm = 0x80000000
+; CHECK-32-NEXT: xorl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl %ecx, %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_inf_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: notl %eax
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
+; CHECK-64-NEXT: xorq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: orq %rax, %rcx
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 516) ; 0x204 = "inf"
+ ret i1 %0
+}
+
+define i1 @is_posinf_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_posinf_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: movl $-2147483648, %ecx # imm = 0x80000000
+; CHECK-32-NEXT: xorl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: xorl $32767, %eax # imm = 0x7FFF
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl %ecx, %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_posinf_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
+; CHECK-64-NEXT: xorq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: xorq $32767, %rax # imm = 0x7FFF
+; CHECK-64-NEXT: orq %rcx, %rax
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 512) ; 0x200 = "+inf"
+ ret i1 %0
+}
+
+define i1 @is_neginf_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_neginf_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: xorl $65535, %eax # imm = 0xFFFF
+; CHECK-32-NEXT: movl $-2147483648, %ecx # imm = 0x80000000
+; CHECK-32-NEXT: xorl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl %ecx, %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_neginf_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: notl %eax
+; CHECK-64-NEXT: movzwl %ax, %eax
+; CHECK-64-NEXT: movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
+; CHECK-64-NEXT: xorq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: orq %rax, %rcx
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 4) ; "-inf"
+ ret i1 %0
+}
+
+define i1 @is_normal_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_normal_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: andl $32767, %ecx # imm = 0x7FFF
+; CHECK-32-NEXT: decl %ecx
+; CHECK-32-NEXT: movzwl %cx, %ecx
+; CHECK-32-NEXT: xorl %edx, %edx
+; CHECK-32-NEXT: cmpl $32766, %ecx # imm = 0x7FFE
+; CHECK-32-NEXT: sbbl %edx, %edx
+; CHECK-32-NEXT: setb %cl
+; CHECK-32-NEXT: shrl $31, %eax
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_normal_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: shrq $63, %rcx
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: decl %eax
+; CHECK-64-NEXT: movzwl %ax, %eax
+; CHECK-64-NEXT: cmpl $32766, %eax # imm = 0x7FFE
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 264) ; 0x108 = "normal"
+ ret i1 %0
+}
+
+define i1 @is_posnormal_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_posnormal_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: .cfi_offset %esi, -8
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %edx
+; CHECK-32-NEXT: movswl %dx, %ecx
+; CHECK-32-NEXT: sarl $15, %ecx
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: andl $32767, %edx # imm = 0x7FFF
+; CHECK-32-NEXT: decl %edx
+; CHECK-32-NEXT: movzwl %dx, %edx
+; CHECK-32-NEXT: xorl %esi, %esi
+; CHECK-32-NEXT: cmpl $32766, %edx # imm = 0x7FFE
+; CHECK-32-NEXT: sbbl %esi, %esi
+; CHECK-32-NEXT: setb %dl
+; CHECK-32-NEXT: testl %ecx, %ecx
+; CHECK-32-NEXT: setns %cl
+; CHECK-32-NEXT: shrl $31, %eax
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: andb %dl, %al
+; CHECK-32-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_posnormal_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rax
+; CHECK-64-NEXT: movswq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: testq %rcx, %rcx
+; CHECK-64-NEXT: setns %dl
+; CHECK-64-NEXT: andl $32767, %ecx # imm = 0x7FFF
+; CHECK-64-NEXT: decl %ecx
+; CHECK-64-NEXT: movzwl %cx, %ecx
+; CHECK-64-NEXT: cmpl $32766, %ecx # imm = 0x7FFE
+; CHECK-64-NEXT: setb %cl
+; CHECK-64-NEXT: shrq $63, %rax
+; CHECK-64-NEXT: andb %dl, %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: # kill: def $al killed $al killed $rax
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 256) ; 0x100 = "+normal"
+ ret i1 %0
+}
+
+define i1 @is_negnormal_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_negnormal_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: .cfi_offset %esi, -8
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %edx
+; CHECK-32-NEXT: movswl %dx, %ecx
+; CHECK-32-NEXT: sarl $15, %ecx
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: andl $32767, %edx # imm = 0x7FFF
+; CHECK-32-NEXT: decl %edx
+; CHECK-32-NEXT: movzwl %dx, %edx
+; CHECK-32-NEXT: xorl %esi, %esi
+; CHECK-32-NEXT: cmpl $32766, %edx # imm = 0x7FFE
+; CHECK-32-NEXT: sbbl %esi, %esi
+; CHECK-32-NEXT: setb %dl
+; CHECK-32-NEXT: testl %ecx, %ecx
+; CHECK-32-NEXT: sets %cl
+; CHECK-32-NEXT: shrl $31, %eax
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: andb %dl, %al
+; CHECK-32-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_negnormal_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rax
+; CHECK-64-NEXT: movswq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: testq %rcx, %rcx
+; CHECK-64-NEXT: sets %dl
+; CHECK-64-NEXT: andl $32767, %ecx # imm = 0x7FFF
+; CHECK-64-NEXT: decl %ecx
+; CHECK-64-NEXT: movzwl %cx, %ecx
+; CHECK-64-NEXT: cmpl $32766, %ecx # imm = 0x7FFE
+; CHECK-64-NEXT: setb %cl
+; CHECK-64-NEXT: shrq $63, %rax
+; CHECK-64-NEXT: andb %dl, %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: # kill: def $al killed $al killed $rax
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 8) ; "-normal"
+ ret i1 %0
+}
+
+define i1 @is_subnormal_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_subnormal_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: .cfi_offset %esi, -8
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %esi
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-32-NEXT: xorl %edx, %edx
+; CHECK-32-NEXT: addl $-1, %esi
+; CHECK-32-NEXT: adcl $-1, %ecx
+; CHECK-32-NEXT: adcl $-1, %eax
+; CHECK-32-NEXT: adcl $-1, %edx
+; CHECK-32-NEXT: cmpl $-1, %esi
+; CHECK-32-NEXT: sbbl $2147483647, %ecx # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: sbbl $0, %eax
+; CHECK-32-NEXT: sbbl $0, %edx
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_subnormal_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: addq $-1, %rcx
+; CHECK-64-NEXT: adcq $-1, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rdx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: cmpq %rdx, %rcx
+; CHECK-64-NEXT: sbbq $0, %rax
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 144) ; 0x90 = "subnormal"
+ ret i1 %0
+}
+
+define i1 @is_possubnormal_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_possubnormal_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: .cfi_offset %esi, -8
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %edx
+; CHECK-32-NEXT: addl $-1, %ecx
+; CHECK-32-NEXT: adcl $-1, %edx
+; CHECK-32-NEXT: adcl $-1, %eax
+; CHECK-32-NEXT: movzwl %ax, %eax
+; CHECK-32-NEXT: xorl %esi, %esi
+; CHECK-32-NEXT: cmpl $-1, %ecx
+; CHECK-32-NEXT: sbbl $2147483647, %edx # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: sbbl $0, %eax
+; CHECK-32-NEXT: sbbl %esi, %esi
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_possubnormal_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rcx
+; CHECK-64-NEXT: addq $-1, %rcx
+; CHECK-64-NEXT: adcq $-1, %rax
+; CHECK-64-NEXT: movzwl %ax, %eax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rdx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: cmpq %rdx, %rcx
+; CHECK-64-NEXT: sbbq $0, %rax
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 128) ; 0x80 = "+subnormal"
+ ret i1 %0
+}
+
+define i1 @is_negsubnormal_f80(x86_fp80 %x) {
+; CHECK-32-LABEL: is_negsubnormal_f80:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %edi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 12
+; CHECK-32-NEXT: .cfi_offset %esi, -12
+; CHECK-32-NEXT: .cfi_offset %edi, -8
+; CHECK-32-NEXT: movzwl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: movswl %cx, %eax
+; CHECK-32-NEXT: sarl $15, %eax
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %esi
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %edi
+; CHECK-32-NEXT: andl $32767, %ecx # imm = 0x7FFF
+; CHECK-32-NEXT: xorl %edx, %edx
+; CHECK-32-NEXT: addl $-1, %esi
+; CHECK-32-NEXT: adcl $-1, %edi
+; CHECK-32-NEXT: adcl $-1, %ecx
+; CHECK-32-NEXT: adcl $-1, %edx
+; CHECK-32-NEXT: cmpl $-1, %esi
+; CHECK-32-NEXT: sbbl $2147483647, %edi # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: sbbl $0, %ecx
+; CHECK-32-NEXT: sbbl $0, %edx
+; CHECK-32-NEXT: setb %cl
+; CHECK-32-NEXT: testl %eax, %eax
+; CHECK-32-NEXT: sets %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: popl %edi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_negsubnormal_f80:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movzwl {{[0-9]+}}(%rsp), %eax
+; CHECK-64-NEXT: movswq %ax, %rcx
+; CHECK-64-NEXT: movq {{[0-9]+}}(%rsp), %rdx
+; CHECK-64-NEXT: andl $32767, %eax # imm = 0x7FFF
+; CHECK-64-NEXT: addq $-1, %rdx
+; CHECK-64-NEXT: adcq $-1, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rsi # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: cmpq %rsi, %rdx
+; CHECK-64-NEXT: sbbq $0, %rax
+; CHECK-64-NEXT: setb %dl
+; CHECK-64-NEXT: testq %rcx, %rcx
+; CHECK-64-NEXT: sets %al
+; CHECK-64-NEXT: andb %dl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f80(x86_fp80 %x, i32 16) ; 0x10 = "-subnormal"
+ ret i1 %0
+}
+
+declare i1 @llvm.is.fpclass.f80(x86_fp80, i32)
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=i686-linux | FileCheck %s -check-prefix=CHECK-32
+; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s -check-prefix=CHECK-64
+
+define i1 @isnan_f(float %x) {
+; CHECK-32-LABEL: isnan_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: ucomiss %xmm0, %xmm0
+; CHECK-64-NEXT: setp %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 3) ; "nan"
+ ret i1 %0
+}
+
+define i1 @isnot_nan_f(float %x) {
+; CHECK-32-LABEL: isnot_nan_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setnp %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnot_nan_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: ucomiss %xmm0, %xmm0
+; CHECK-64-NEXT: setnp %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 1020) ; 0x3fc = "zero|subnormal|normal|inf"
+ ret i1 %0
+}
+
+define i1 @issignaling_f(float %x) {
+; CHECK-32-LABEL: issignaling_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2143289344, %eax # imm = 0x7FC00000
+; CHECK-32-NEXT: setl %cl
+; CHECK-32-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001
+; CHECK-32-NEXT: setge %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: issignaling_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2143289344, %eax # imm = 0x7FC00000
+; CHECK-64-NEXT: setl %cl
+; CHECK-64-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001
+; CHECK-64-NEXT: setge %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 1) ; "snan"
+ ret i1 %0
+}
+
+define i1 @isquiet_f(float %x) {
+; CHECK-32-LABEL: isquiet_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2143289344, %eax # imm = 0x7FC00000
+; CHECK-32-NEXT: setge %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isquiet_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2143289344, %eax # imm = 0x7FC00000
+; CHECK-64-NEXT: setge %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 2) ; "qnan"
+ ret i1 %0
+}
+
+define i1 @isinf_f(float %x) {
+; CHECK-32-LABEL: isinf_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isinf_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 516) ; 0x204 = "inf"
+ ret i1 %0
+}
+
+define i1 @is_plus_inf_f(float %x) {
+; CHECK-32-LABEL: is_plus_inf_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: cmpl $2139095040, {{[0-9]+}}(%esp) # imm = 0x7F800000
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_plus_inf_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 512) ; 0x200 = "+inf"
+ ret i1 %0
+}
+
+define i1 @is_minus_inf_f(float %x) {
+; CHECK-32-LABEL: is_minus_inf_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: cmpl $-8388608, {{[0-9]+}}(%esp) # imm = 0xFF800000
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_minus_inf_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: cmpl $-8388608, %eax # imm = 0xFF800000
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 4) ; "-inf"
+ ret i1 %0
+}
+
+define i1 @isfinite_f(float %x) {
+; CHECK-32-LABEL: isfinite_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isfinite_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-64-NEXT: setl %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite"
+ ret i1 %0
+}
+
+define i1 @is_plus_finite_f(float %x) {
+; CHECK-32-LABEL: is_plus_finite_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: cmpl $2139095040, {{[0-9]+}}(%esp) # imm = 0x7F800000
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_plus_finite_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 448) ; 0x1c0 = "+finite"
+ ret i1 %0
+}
+
+define i1 @is_minus_finite_f(float %x) {
+; CHECK-32-LABEL: is_minus_finite_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: testl %eax, %eax
+; CHECK-32-NEXT: sets %cl
+; CHECK-32-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_minus_finite_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: testl %eax, %eax
+; CHECK-64-NEXT: sets %cl
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-64-NEXT: setl %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 56) ; 0x38 = "-finite"
+ ret i1 %0
+}
+
+define i1 @isnormal_f(float %x) {
+; CHECK-32-LABEL: isnormal_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: addl $-8388608, %eax # imm = 0xFF800000
+; CHECK-32-NEXT: cmpl $2130706432, %eax # imm = 0x7F000000
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnormal_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: addl $-8388608, %eax # imm = 0xFF800000
+; CHECK-64-NEXT: cmpl $2130706432, %eax # imm = 0x7F000000
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 264) ; 0x108 = "normal"
+ ret i1 %0
+}
+
+define i1 @is_plus_normal_f(float %x) {
+; CHECK-32-LABEL: is_plus_normal_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: testl %eax, %eax
+; CHECK-32-NEXT: setns %cl
+; CHECK-32-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: addl $-8388608, %eax # imm = 0xFF800000
+; CHECK-32-NEXT: cmpl $2130706432, %eax # imm = 0x7F000000
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_plus_normal_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: testl %eax, %eax
+; CHECK-64-NEXT: setns %cl
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: addl $-8388608, %eax # imm = 0xFF800000
+; CHECK-64-NEXT: cmpl $2130706432, %eax # imm = 0x7F000000
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 256) ; 0x100 = "+normal"
+ ret i1 %0
+}
+
+define i1 @issubnormal_f(float %x) {
+; CHECK-32-LABEL: issubnormal_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: decl %eax
+; CHECK-32-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: issubnormal_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: decl %eax
+; CHECK-64-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 144) ; 0x90 = "subnormal"
+ ret i1 %0
+}
+
+define i1 @is_plus_subnormal_f(float %x) {
+; CHECK-32-LABEL: is_plus_subnormal_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: decl %eax
+; CHECK-32-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_plus_subnormal_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: decl %eax
+; CHECK-64-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 128) ; 0x80 = "+subnormal"
+ ret i1 %0
+}
+
+define i1 @is_minus_subnormal_f(float %x) {
+; CHECK-32-LABEL: is_minus_subnormal_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: testl %eax, %eax
+; CHECK-32-NEXT: sets %cl
+; CHECK-32-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: decl %eax
+; CHECK-32-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_minus_subnormal_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: testl %eax, %eax
+; CHECK-64-NEXT: sets %cl
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: decl %eax
+; CHECK-64-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: andb %cl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 16) ; 0x10 = "-subnormal"
+ ret i1 %0
+}
+
+define i1 @iszero_f(float %x) {
+; CHECK-32-LABEL: iszero_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fldz
+; CHECK-32-NEXT: fucompp
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setnp %cl
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: iszero_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: xorps %xmm1, %xmm1
+; CHECK-64-NEXT: cmpeqss %xmm0, %xmm1
+; CHECK-64-NEXT: movd %xmm1, %eax
+; CHECK-64-NEXT: andl $1, %eax
+; CHECK-64-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 96) ; 0x60 = "zero"
+ ret i1 %0
+}
+
+define i1 @is_plus_zero_f(float %x) {
+; CHECK-32-LABEL: is_plus_zero_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: cmpl $0, {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_plus_zero_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: testl %eax, %eax
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 64) ; 0x40 = "+zero"
+ ret i1 %0
+}
+
+define i1 @is_minus_zero_f(float %x) {
+; CHECK-32-LABEL: is_minus_zero_f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: cmpl $-2147483648, {{[0-9]+}}(%esp) # imm = 0x80000000
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: is_minus_zero_f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: cmpl $-2147483648, %eax # imm = 0x80000000
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 32) ; 0x20 = "-zero"
+ ret i1 %0
+}
+
+
+
+define i1 @isnan_f_strictfp(float %x) strictfp {
+; CHECK-32-LABEL: isnan_f_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001
+; CHECK-32-NEXT: setge %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_f_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001
+; CHECK-64-NEXT: setge %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 3) ; "nan"
+ ret i1 %0
+}
+
+define i1 @isfinite_f_strictfp(float %x) strictfp {
+; CHECK-32-LABEL: isfinite_f_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isfinite_f_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000
+; CHECK-64-NEXT: setl %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite"
+ ret i1 %0
+}
+
+define i1 @iszero_f_strictfp(float %x) strictfp {
+; CHECK-32-LABEL: iszero_f_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: testl $2147483647, {{[0-9]+}}(%esp) # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: iszero_f_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: testl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 96) ; 0x60 = "zero"
+ ret i1 %0
+}
+
+
+define i1 @isnan_d(double %x) {
+; CHECK-32-LABEL: isnan_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: fldl {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: ucomisd %xmm0, %xmm0
+; CHECK-64-NEXT: setp %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; "nan"
+ ret i1 %0
+}
+
+define i1 @isinf_d(double %x) {
+; CHECK-32-LABEL: isinf_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: xorl $2146435072, %eax # imm = 0x7FF00000
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isinf_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: andq %rax, %rcx
+; CHECK-64-NEXT: movabsq $9218868437227405312, %rax # imm = 0x7FF0000000000000
+; CHECK-64-NEXT: cmpq %rax, %rcx
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 516) ; 0x204 = "inf"
+ ret i1 %0
+}
+
+define i1 @isfinite_d(double %x) {
+; CHECK-32-LABEL: isfinite_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2146435072, %eax # imm = 0x7FF00000
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isfinite_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: andq %rax, %rcx
+; CHECK-64-NEXT: movabsq $9218868437227405312, %rax # imm = 0x7FF0000000000000
+; CHECK-64-NEXT: cmpq %rax, %rcx
+; CHECK-64-NEXT: setl %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 504) ; 0x1f8 = "finite"
+ ret i1 %0
+}
+
+define i1 @isnormal_d(double %x) {
+; CHECK-32-LABEL: isnormal_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: addl $-1048576, %eax # imm = 0xFFF00000
+; CHECK-32-NEXT: shrl $21, %eax
+; CHECK-32-NEXT: cmpl $1023, %eax # imm = 0x3FF
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnormal_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: andq %rax, %rcx
+; CHECK-64-NEXT: movabsq $-4503599627370496, %rax # imm = 0xFFF0000000000000
+; CHECK-64-NEXT: addq %rcx, %rax
+; CHECK-64-NEXT: shrq $53, %rax
+; CHECK-64-NEXT: cmpl $1023, %eax # imm = 0x3FF
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 264) ; 0x108 = "normal"
+ ret i1 %0
+}
+
+define i1 @issubnormal_d(double %x) {
+; CHECK-32-LABEL: issubnormal_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: movl $2147483647, %ecx # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: addl $-1, %eax
+; CHECK-32-NEXT: adcl $-1, %ecx
+; CHECK-32-NEXT: cmpl $-1, %eax
+; CHECK-32-NEXT: sbbl $1048575, %ecx # imm = 0xFFFFF
+; CHECK-32-NEXT: setb %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: issubnormal_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: andq %rax, %rcx
+; CHECK-64-NEXT: decq %rcx
+; CHECK-64-NEXT: movabsq $4503599627370495, %rax # imm = 0xFFFFFFFFFFFFF
+; CHECK-64-NEXT: cmpq %rax, %rcx
+; CHECK-64-NEXT: setb %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 144) ; 0x90 = "subnormal"
+ ret i1 %0
+}
+
+define i1 @iszero_d(double %x) {
+; CHECK-32-LABEL: iszero_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: fldl {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fldz
+; CHECK-32-NEXT: fucompp
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setnp %cl
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: iszero_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: xorpd %xmm1, %xmm1
+; CHECK-64-NEXT: cmpeqsd %xmm0, %xmm1
+; CHECK-64-NEXT: movq %xmm1, %rax
+; CHECK-64-NEXT: andl $1, %eax
+; CHECK-64-NEXT: # kill: def $al killed $al killed $rax
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 96) ; 0x60 = "zero"
+ ret i1 %0
+}
+
+define i1 @issignaling_d(double %x) {
+; CHECK-32-LABEL: issignaling_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: xorl %ecx, %ecx
+; CHECK-32-NEXT: cmpl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: movl $2146435072, %ecx # imm = 0x7FF00000
+; CHECK-32-NEXT: sbbl %eax, %ecx
+; CHECK-32-NEXT: setl %cl
+; CHECK-32-NEXT: cmpl $2146959360, %eax # imm = 0x7FF80000
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: andb %cl, %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: issignaling_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: andq %rax, %rcx
+; CHECK-64-NEXT: movabsq $9221120237041090560, %rax # imm = 0x7FF8000000000000
+; CHECK-64-NEXT: cmpq %rax, %rcx
+; CHECK-64-NEXT: setl %dl
+; CHECK-64-NEXT: movabsq $9218868437227405312, %rax # imm = 0x7FF0000000000000
+; CHECK-64-NEXT: cmpq %rax, %rcx
+; CHECK-64-NEXT: setg %al
+; CHECK-64-NEXT: andb %dl, %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 1) ; "snan"
+ ret i1 %0
+}
+
+define i1 @isquiet_d(double %x) {
+; CHECK-32-LABEL: isquiet_d:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2146959360, %eax # imm = 0x7FF80000
+; CHECK-32-NEXT: setge %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isquiet_d:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: andq %rax, %rcx
+; CHECK-64-NEXT: movabsq $9221120237041090559, %rax # imm = 0x7FF7FFFFFFFFFFFF
+; CHECK-64-NEXT: cmpq %rax, %rcx
+; CHECK-64-NEXT: setg %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 2) ; "qnan"
+ ret i1 %0
+}
+
+define i1 @isnan_d_strictfp(double %x) strictfp {
+; CHECK-32-LABEL: isnan_d_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: xorl %ecx, %ecx
+; CHECK-32-NEXT: cmpl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: movl $2146435072, %ecx # imm = 0x7FF00000
+; CHECK-32-NEXT: sbbl %eax, %ecx
+; CHECK-32-NEXT: setl %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_d_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; CHECK-64-NEXT: andq %rax, %rcx
+; CHECK-64-NEXT: movabsq $9218868437227405312, %rax # imm = 0x7FF0000000000000
+; CHECK-64-NEXT: cmpq %rax, %rcx
+; CHECK-64-NEXT: setg %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; "nan"
+ ret i1 %0
+}
+
+define i1 @iszero_d_strictfp(double %x) strictfp {
+; CHECK-32-LABEL: iszero_d_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: orl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: sete %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: iszero_d_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movq %xmm0, %rax
+; CHECK-64-NEXT: shlq $1, %rax
+; CHECK-64-NEXT: testq %rax, %rax
+; CHECK-64-NEXT: sete %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 96) ; 0x60 = "zero"
+ ret i1 %0
+}
+
+
+
+define <1 x i1> @isnan_v1f(<1 x float> %x) {
+; CHECK-32-LABEL: isnan_v1f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_v1f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: ucomiss %xmm0, %xmm0
+; CHECK-64-NEXT: setp %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call <1 x i1> @llvm.is.fpclass.v1f32(<1 x float> %x, i32 3) ; "nan"
+ ret <1 x i1> %0
+}
+
+define <1 x i1> @isnan_v1f_strictfp(<1 x float> %x) strictfp {
+; CHECK-32-LABEL: isnan_v1f_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001
+; CHECK-32-NEXT: setge %al
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_v1f_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: movd %xmm0, %eax
+; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF
+; CHECK-64-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001
+; CHECK-64-NEXT: setge %al
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call <1 x i1> @llvm.is.fpclass.v1f32(<1 x float> %x, i32 3) ; "nan"
+ ret <1 x i1> %0
+}
+
+define <2 x i1> @isnan_v2f(<2 x float> %x) {
+; CHECK-32-LABEL: isnan_v2f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %cl
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %dl
+; CHECK-32-NEXT: movl %ecx, %eax
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_v2f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: cmpunordps %xmm0, %xmm0
+; CHECK-64-NEXT: shufps {{.*#+}} xmm0 = xmm0[0,1,1,3]
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 3) ; "nan"
+ ret <2 x i1> %0
+}
+
+
+define <2 x i1> @isnot_nan_v2f(<2 x float> %x) {
+; CHECK-32-LABEL: isnot_nan_v2f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setnp %cl
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setnp %dl
+; CHECK-32-NEXT: movl %ecx, %eax
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnot_nan_v2f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: cmpordps %xmm0, %xmm0
+; CHECK-64-NEXT: shufps {{.*#+}} xmm0 = xmm0[0,1,1,3]
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 1020) ; 0x3fc = "zero|subnormal|normal|inf"
+ ret <2 x i1> %0
+}
+
+define <2 x i1> @isnan_v2f_strictfp(<2 x float> %x) strictfp {
+; CHECK-32-LABEL: isnan_v2f_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl $2147483647, %ecx # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: andl %ecx, %eax
+; CHECK-32-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001
+; CHECK-32-NEXT: setge %al
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: cmpl $2139095041, %ecx # imm = 0x7F800001
+; CHECK-32-NEXT: setge %dl
+; CHECK-32-NEXT: retl
+;
+; CHECK-64-LABEL: isnan_v2f_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: shufps {{.*#+}} xmm0 = xmm0[0,1,1,3]
+; CHECK-64-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-64-NEXT: pcmpgtd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 3) ; "nan"
+ ret <2 x i1> %0
+}
+
+define <4 x i1> @isnan_v4f(<4 x float> %x) {
+; CHECK-32-LABEL: isnan_v4f:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %dh
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %dl
+; CHECK-32-NEXT: addb %dl, %dl
+; CHECK-32-NEXT: orb %dh, %dl
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %dh
+; CHECK-32-NEXT: fucomp %st(0)
+; CHECK-32-NEXT: fnstsw %ax
+; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax
+; CHECK-32-NEXT: sahf
+; CHECK-32-NEXT: setp %al
+; CHECK-32-NEXT: addb %al, %al
+; CHECK-32-NEXT: orb %dh, %al
+; CHECK-32-NEXT: shlb $2, %al
+; CHECK-32-NEXT: orb %dl, %al
+; CHECK-32-NEXT: movb %al, (%ecx)
+; CHECK-32-NEXT: movl %ecx, %eax
+; CHECK-32-NEXT: retl $4
+;
+; CHECK-64-LABEL: isnan_v4f:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: cmpunordps %xmm0, %xmm0
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 3) ; "nan"
+ ret <4 x i1> %0
+}
+
+define <4 x i1> @isnan_v4f_strictfp(<4 x float> %x) strictfp {
+; CHECK-32-LABEL: isnan_v4f_strictfp:
+; CHECK-32: # %bb.0: # %entry
+; CHECK-32-NEXT: pushl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 8
+; CHECK-32-NEXT: .cfi_offset %esi, -8
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %eax
+; CHECK-32-NEXT: movl $2147483647, %ecx # imm = 0x7FFFFFFF
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %edx
+; CHECK-32-NEXT: andl %ecx, %edx
+; CHECK-32-NEXT: cmpl $2139095041, %edx # imm = 0x7F800001
+; CHECK-32-NEXT: setge %dh
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %esi
+; CHECK-32-NEXT: andl %ecx, %esi
+; CHECK-32-NEXT: cmpl $2139095041, %esi # imm = 0x7F800001
+; CHECK-32-NEXT: setge %dl
+; CHECK-32-NEXT: addb %dl, %dl
+; CHECK-32-NEXT: orb %dh, %dl
+; CHECK-32-NEXT: movl {{[0-9]+}}(%esp), %esi
+; CHECK-32-NEXT: andl %ecx, %esi
+; CHECK-32-NEXT: cmpl $2139095041, %esi # imm = 0x7F800001
+; CHECK-32-NEXT: setge %dh
+; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %ecx
+; CHECK-32-NEXT: cmpl $2139095041, %ecx # imm = 0x7F800001
+; CHECK-32-NEXT: setge %cl
+; CHECK-32-NEXT: addb %cl, %cl
+; CHECK-32-NEXT: orb %dh, %cl
+; CHECK-32-NEXT: shlb $2, %cl
+; CHECK-32-NEXT: orb %dl, %cl
+; CHECK-32-NEXT: movb %cl, (%eax)
+; CHECK-32-NEXT: popl %esi
+; CHECK-32-NEXT: .cfi_def_cfa_offset 4
+; CHECK-32-NEXT: retl $4
+;
+; CHECK-64-LABEL: isnan_v4f_strictfp:
+; CHECK-64: # %bb.0: # %entry
+; CHECK-64-NEXT: pand {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-64-NEXT: pcmpgtd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-64-NEXT: retq
+entry:
+ %0 = tail call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 3) ; "nan"
+ ret <4 x i1> %0
+}
+
+
+declare i1 @llvm.is.fpclass.f32(float, i32)
+declare i1 @llvm.is.fpclass.f64(double, i32)
+declare <1 x i1> @llvm.is.fpclass.v1f32(<1 x float>, i32)
+declare <2 x i1> @llvm.is.fpclass.v2f32(<2 x float>, i32)
+declare <4 x i1> @llvm.is.fpclass.v4f32(<4 x float>, i32)