diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -469,6 +469,10 @@ BUILTIN(__builtin_isinf_sign, "i.", "Fnct") BUILTIN(__builtin_isnan, "i.", "Fnct") BUILTIN(__builtin_isnormal, "i.", "Fnct") +BUILTIN(__builtin_issubnormal, "i.", "Fnct") +BUILTIN(__builtin_iszero, "i.", "Fnct") +BUILTIN(__builtin_issignaling, "i.", "Fnct") +BUILTIN(__builtin_isfpclass, "iCi.", "Fnct") // FP signbit builtins BUILTIN(__builtin_signbit, "i.", "Fnct") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2223,6 +2223,82 @@ } } +static Value *callIsFPClass(CodeGenFunction *CGF, const CallExpr *E, + StringRef Check) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*CGF, E); + const Expr *Arg = E->getNumArgs() == 1 ? E->getArg(0) : E->getArg(1); + Value *V = CGF->EmitScalarExpr(Arg); + Function *F = CGF->CGM.getIntrinsic(Intrinsic::is_fpclass, V->getType()); + auto MDArg = llvm::MDString::get(CGF->getLLVMContext(), Check); + return CGF->Builder.CreateCall( + F, {V, MetadataAsValue::get(CGF->getLLVMContext(), MDArg)}); +} + +enum FPClassCheck { + fcBad = 0, + 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 +}; + +static std::string convertCodeToFPCheck(unsigned Code) { + SmallVector Parts; + if ((Code & fcZero) == fcZero) + Parts.push_back("zero"); + else if (Code & fcPosZero) + Parts.push_back("+zero"); + else if (Code & fcNegZero) + Parts.push_back("-zero"); + if ((Code & fcSubnormal) == fcSubnormal) + Parts.push_back("subnormal"); + else if (Code & fcPosSubnormal) + Parts.push_back("+subnormal"); + else if (Code & fcNegSubnormal) + Parts.push_back("-subnormal"); + if ((Code & fcNormal) == fcNormal) + Parts.push_back("normal"); + else if (Code & fcPosNormal) + Parts.push_back("+normal"); + else if (Code & fcNegNormal) + Parts.push_back("-normal"); + if ((Code & fcInf) == fcInf) + Parts.push_back("inf"); + else if (Code & fcPosInf) + Parts.push_back("+inf"); + else if (Code & fcNegInf) + Parts.push_back("-inf"); + if ((Code & fcNan) == fcNan) + Parts.push_back("nan"); + else if (Code & fcQNan) + Parts.push_back("qnan"); + else if (Code & fcSNan) + Parts.push_back("snan"); + std::string Result; + for (StringRef P : Parts) { + if (!Result.empty()) + Result += "|"; + Result += P; + } + return Result; +} + RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -3068,38 +3144,40 @@ // ZExt bool to int type. return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()))); } - case Builtin::BI__builtin_isnan: { - CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); - Value *V = EmitScalarExpr(E->getArg(0)); - llvm::Type *Ty = V->getType(); - const llvm::fltSemantics &Semantics = Ty->getFltSemantics(); - if (!Builder.getIsFPConstrained() || - Builder.getDefaultConstrainedExcept() == fp::ebIgnore || - !Ty->isIEEE()) { - V = Builder.CreateFCmpUNO(V, V, "cmp"); - return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); - } - if (Value *Result = getTargetHooks().testFPKind(V, BuiltinID, Builder, CGM)) - return RValue::get(Result); + case Builtin::BI__builtin_isnan: + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, "nan"), + ConvertType(E->getType()))); - // NaN has all exp bits set and a non zero significand. Therefore: - // isnan(V) == ((exp mask - (abs(V) & exp mask)) < 0) - unsigned bitsize = Ty->getScalarSizeInBits(); - llvm::IntegerType *IntTy = Builder.getIntNTy(bitsize); - Value *IntV = Builder.CreateBitCast(V, IntTy); - APInt AndMask = APInt::getSignedMaxValue(bitsize); - Value *AbsV = - Builder.CreateAnd(IntV, llvm::ConstantInt::get(IntTy, AndMask)); - APInt ExpMask = APFloat::getInf(Semantics).bitcastToAPInt(); - Value *Sub = - Builder.CreateSub(llvm::ConstantInt::get(IntTy, ExpMask), AbsV); - // V = sign bit (Sub) <=> V = (Sub < 0) - V = Builder.CreateLShr(Sub, llvm::ConstantInt::get(IntTy, bitsize - 1)); - if (bitsize > 32) - V = Builder.CreateTrunc(V, ConvertType(E->getType())); - return RValue::get(V); - } + case Builtin::BI__builtin_issignaling: + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, "snan"), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_isinf: + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, "inf"), + ConvertType(E->getType()))); + + case Builtin::BIfinite: + case Builtin::BI__finite: + case Builtin::BIfinitef: + case Builtin::BI__finitef: + case Builtin::BIfinitel: + case Builtin::BI__finitel: + case Builtin::BI__builtin_isfinite: + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, "finite"), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_isnormal: + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, "normal"), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_issubnormal: + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, "subnormal"), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_iszero: + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, "zero"), + ConvertType(E->getType()))); case Builtin::BI__builtin_matrix_transpose: { const auto *MatrixTy = E->getArg(0)->getType()->getAs(); @@ -3110,6 +3188,17 @@ return RValue::get(Result); } + case Builtin::BI__builtin_isfpclass: { + Expr::EvalResult Result; + if (!E->getArg(0)->EvaluateAsInt(Result, CGM.getContext())) + break; + llvm::APSInt Code = Result.Val.getInt(); + std::string Test = + convertCodeToFPCheck(Code.zextOrTrunc(32).getZExtValue()); + return RValue::get(Builder.CreateZExt(callIsFPClass(this, E, Test), + ConvertType(E->getType()))); + } + case Builtin::BI__builtin_matrix_column_major_load: { MatrixBuilder MB(Builder); // Emit everything that isn't dependent on the first parameter type @@ -3148,52 +3237,6 @@ return RValue::get(Result); } - case Builtin::BIfinite: - case Builtin::BI__finite: - case Builtin::BIfinitef: - case Builtin::BI__finitef: - case Builtin::BIfinitel: - case Builtin::BI__finitel: - case Builtin::BI__builtin_isinf: - case Builtin::BI__builtin_isfinite: { - // isinf(x) --> fabs(x) == infinity - // isfinite(x) --> fabs(x) != infinity - // x != NaN via the ordered compare in either case. - CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); - Value *V = EmitScalarExpr(E->getArg(0)); - llvm::Type *Ty = V->getType(); - if (!Builder.getIsFPConstrained() || - Builder.getDefaultConstrainedExcept() == fp::ebIgnore || - !Ty->isIEEE()) { - Value *Fabs = EmitFAbs(*this, V); - Constant *Infinity = ConstantFP::getInfinity(V->getType()); - CmpInst::Predicate Pred = (BuiltinID == Builtin::BI__builtin_isinf) - ? CmpInst::FCMP_OEQ - : CmpInst::FCMP_ONE; - Value *FCmp = Builder.CreateFCmp(Pred, Fabs, Infinity, "cmpinf"); - return RValue::get(Builder.CreateZExt(FCmp, ConvertType(E->getType()))); - } - - if (Value *Result = getTargetHooks().testFPKind(V, BuiltinID, Builder, CGM)) - return RValue::get(Result); - - // Inf values have all exp bits set and a zero significand. Therefore: - // isinf(V) == ((V << 1) == ((exp mask) << 1)) - // isfinite(V) == ((V << 1) < ((exp mask) << 1)) using unsigned comparison - unsigned bitsize = Ty->getScalarSizeInBits(); - llvm::IntegerType *IntTy = Builder.getIntNTy(bitsize); - Value *IntV = Builder.CreateBitCast(V, IntTy); - Value *Shl1 = Builder.CreateShl(IntV, 1); - const llvm::fltSemantics &Semantics = Ty->getFltSemantics(); - APInt ExpMask = APFloat::getInf(Semantics).bitcastToAPInt(); - Value *ExpMaskShl1 = llvm::ConstantInt::get(IntTy, ExpMask.shl(1)); - if (BuiltinID == Builtin::BI__builtin_isinf) - V = Builder.CreateICmpEQ(Shl1, ExpMaskShl1); - else - V = Builder.CreateICmpULT(Shl1, ExpMaskShl1); - return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); - } - case Builtin::BI__builtin_isinf_sign: { // isinf_sign(x) -> fabs(x) == infinity ? (signbit(x) ? -1 : 1) : 0 CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); @@ -3213,26 +3256,6 @@ return RValue::get(Result); } - case Builtin::BI__builtin_isnormal: { - // isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min - CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); - // FIXME: for strictfp/IEEE-754 we need to not trap on SNaN here. - Value *V = EmitScalarExpr(E->getArg(0)); - Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq"); - - Value *Abs = EmitFAbs(*this, V); - Value *IsLessThanInf = - Builder.CreateFCmpULT(Abs, ConstantFP::getInfinity(V->getType()),"isinf"); - APFloat Smallest = APFloat::getSmallestNormalized( - getContext().getFloatTypeSemantics(E->getArg(0)->getType())); - Value *IsNormal = - Builder.CreateFCmpUGE(Abs, ConstantFP::get(V->getContext(), Smallest), - "isnormal"); - V = Builder.CreateAnd(Eq, IsLessThanInf, "and"); - V = Builder.CreateAnd(V, IsNormal, "and"); - return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); - } - case Builtin::BI__builtin_flt_rounds: { Function *F = CGM.getIntrinsic(Intrinsic::flt_rounds); diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -127,16 +127,6 @@ return Address; } - /// Performs a target specific test of a floating point value for things - /// like IsNaN, Infinity, ... Nullptr is returned if no implementation - /// exists. - virtual llvm::Value * - testFPKind(llvm::Value *V, unsigned BuiltinID, CGBuilderTy &Builder, - CodeGenModule &CGM) const { - assert(V->getType()->isFloatingPointTy() && "V should have an FP type."); - return nullptr; - } - /// Corrects the low-level LLVM type for a given constraint and "usual" /// type. /// diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -7319,48 +7319,6 @@ SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI) : TargetCodeGenInfo( std::make_unique(CGT, HasVector, SoftFloatABI)) {} - - llvm::Value *testFPKind(llvm::Value *V, unsigned BuiltinID, - CGBuilderTy &Builder, - CodeGenModule &CGM) const override { - assert(V->getType()->isFloatingPointTy() && "V should have an FP type."); - // Only use TDC in constrained FP mode. - if (!Builder.getIsFPConstrained()) - return nullptr; - - llvm::Type *Ty = V->getType(); - if (Ty->isFloatTy() || Ty->isDoubleTy() || Ty->isFP128Ty()) { - llvm::Module &M = CGM.getModule(); - auto &Ctx = M.getContext(); - llvm::Function *TDCFunc = - llvm::Intrinsic::getDeclaration(&M, llvm::Intrinsic::s390_tdc, Ty); - unsigned TDCBits = 0; - switch (BuiltinID) { - case Builtin::BI__builtin_isnan: - TDCBits = 0xf; - break; - case Builtin::BIfinite: - case Builtin::BI__finite: - case Builtin::BIfinitef: - case Builtin::BI__finitef: - case Builtin::BIfinitel: - case Builtin::BI__finitel: - case Builtin::BI__builtin_isfinite: - TDCBits = 0xfc0; - break; - case Builtin::BI__builtin_isinf: - TDCBits = 0x30; - break; - default: - break; - } - if (TDCBits) - return Builder.CreateCall( - TDCFunc, - {V, llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), TDCBits)}); - } - return nullptr; - } }; }