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 @@ -470,6 +470,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 @@ -29,6 +29,7 @@ #include "clang/CodeGen/CGFunctionInfo.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/ValueTracking.h" @@ -2247,6 +2248,16 @@ } } +static Value *createCallToIsFPClass(CodeGenFunction *CGF, const CallExpr *Call, + unsigned Test) { + auto TestV = llvm::ConstantInt::get(CGF->Int32Ty, Test); + const Expr *Arg = Call->getNumArgs() == 1 ? Call->getArg(0) : Call->getArg(1); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*CGF, Call); + Value *V = CGF->EmitScalarExpr(Arg); + Function *F = CGF->CGM.getIntrinsic(Intrinsic::is_fpclass, V->getType()); + return CGF->Builder.CreateCall(F, {V, TestV}); +} + RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -3092,37 +3103,55 @@ // 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(createCallToIsFPClass(this, E, FPClassTest::fcNan), + 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(createCallToIsFPClass(this, E, FPClassTest::fcSNan), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_isinf: + return RValue::get( + Builder.CreateZExt(createCallToIsFPClass(this, E, FPClassTest::fcInf), + 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( + createCallToIsFPClass(this, E, FPClassTest::fcFinite), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_isnormal: + return RValue::get(Builder.CreateZExt( + createCallToIsFPClass(this, E, FPClassTest::fcNormal), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_issubnormal: + return RValue::get(Builder.CreateZExt( + createCallToIsFPClass(this, E, FPClassTest::fcSubnormal), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_iszero: + return RValue::get( + Builder.CreateZExt(createCallToIsFPClass(this, E, FPClassTest::fcZero), + ConvertType(E->getType()))); + + case Builtin::BI__builtin_isfpclass: { + Expr::EvalResult Result; + if (!E->getArg(0)->EvaluateAsInt(Result, CGM.getContext())) + break; + uint64_t Test = Result.Val.getInt().getLimitedValue(); + return RValue::get(Builder.CreateZExt(createCallToIsFPClass(this, E, Test), + ConvertType(E->getType()))); } case Builtin::BI__builtin_elementwise_abs: { @@ -3295,52 +3324,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); @@ -3360,26 +3343,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 @@ -126,16 +126,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 @@ -7363,48 +7363,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; - } }; }