sepavloff created this revision. sepavloff requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Builtin floating-point number classification functions: - __builtin_isnan, - __builtin_isinf, - __builtin_finite, and - __builtin_isnormal now are implemented using `llvm.is_fpclass`. New builtin functions were added: - __builtin_issubnormal, - __builtin_iszero, and - __builtin_issignaling. They represent corresponding standard C library finctions and are also implemented using `llvm.is_fpclass`. The hook `testFPKind` from `TargetInfo` is removed. New builting function `__builtin_isfpclass` is added. It is called as: __builtin_isfpclass(<test>, <floating point value>) and returns integer value, which is non-zero if the floating point argument belongs to one of the classes specified by the first argument, and zero otherwise. The first argument is an integer value, where each value class is represented by one bit. There are ten data classes, as defined by the IEEE-754 standard. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D112932 Files: clang/include/clang/Basic/Builtins.def clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/TargetInfo.cpp clang/lib/CodeGen/TargetInfo.h
Index: clang/lib/CodeGen/TargetInfo.h =================================================================== --- clang/lib/CodeGen/TargetInfo.h +++ 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. /// Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -7319,48 +7319,6 @@ SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI) : TargetCodeGenInfo( std::make_unique<SystemZABIInfo>(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; - } }; } Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ 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<StringRef, 5> 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<ConstantMatrixType>(); @@ -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<CGBuilderTy> 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); Index: clang/include/clang/Basic/Builtins.def =================================================================== --- clang/include/clang/Basic/Builtins.def +++ 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")
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits