diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2d918967e7f0b0..2453804cd7735b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -621,6 +621,8 @@ Floating Point Support in Clang - Add ``__builtin_exp10``, ``__builtin_exp10f``, ``__builtin_exp10f16``, ``__builtin_exp10l`` and ``__builtin_exp10f128`` builtins. +- Add ``__builtin_iszero``, ``__builtin_issignaling`` and + ``__builtin_issubnormal``. AST Matchers ------------ diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 6ea8484606cfd5..ebcb5b45e5bdc2 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -494,6 +494,9 @@ BUILTIN(__builtin_isinf, "i.", "FnctE") BUILTIN(__builtin_isinf_sign, "i.", "FnctE") BUILTIN(__builtin_isnan, "i.", "FnctE") BUILTIN(__builtin_isnormal, "i.", "FnctE") +BUILTIN(__builtin_issubnormal,"i.", "FnctE") +BUILTIN(__builtin_iszero, "i.", "FnctE") +BUILTIN(__builtin_issignaling,"i.", "FnctE") BUILTIN(__builtin_isfpclass, "i.", "nctE") // FP signbit builtins diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index e5539dedec02a4..b4da8f336b0beb 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12303,6 +12303,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, Success(Val.isNormal() ? 1 : 0, E); } + case Builtin::BI__builtin_issubnormal: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isDenormal() ? 1 : 0, E); + } + + case Builtin::BI__builtin_iszero: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isZero() ? 1 : 0, E); + } + + case Builtin::BI__builtin_issignaling: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isSignaling() ? 1 : 0, E); + } + case Builtin::BI__builtin_isfpclass: { APSInt MaskVal; if (!EvaluateInteger(E->getArg(1), MaskVal, Info)) diff --git a/clang/lib/AST/Interp/Floating.h b/clang/lib/AST/Interp/Floating.h index a22b3fa79f3992..e4ac76d8509fb8 100644 --- a/clang/lib/AST/Interp/Floating.h +++ b/clang/lib/AST/Interp/Floating.h @@ -93,6 +93,7 @@ class Floating final { bool isMin() const { return F.isSmallest(); } bool isMinusOne() const { return F.isExactlyValue(-1.0); } bool isNan() const { return F.isNaN(); } + bool isSignaling() const { return F.isSignaling(); } bool isInf() const { return F.isInfinity(); } bool isFinite() const { return F.isFinite(); } bool isNormal() const { return F.isNormal(); } diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 7552c1b88cff60..87880a4aca48a8 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -303,6 +303,15 @@ static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *F) { + const Floating &Arg = S.Stk.peek(); + + pushInt(S, Arg.isSignaling()); + return true; +} + static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F, bool CheckSign) { @@ -334,6 +343,24 @@ static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *F) { + const Floating &Arg = S.Stk.peek(); + + pushInt(S, Arg.isDenormal()); + return true; +} + +static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *F) { + const Floating &Arg = S.Stk.peek(); + + pushInt(S, Arg.isZero()); + return true; +} + /// First parameter to __builtin_isfpclass is the floating value, the /// second one is an integral value. static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC, @@ -488,6 +515,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, if (interp__builtin_isnan(S, OpPC, Frame, F)) return retInt(S, OpPC, Dummy); break; + case Builtin::BI__builtin_issignaling: + if (interp__builtin_issignaling(S, OpPC, Frame, F)) + return retInt(S, OpPC, Dummy); + break; case Builtin::BI__builtin_isinf: if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false)) @@ -507,6 +538,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, if (interp__builtin_isnormal(S, OpPC, Frame, F)) return retInt(S, OpPC, Dummy); break; + case Builtin::BI__builtin_issubnormal: + if (interp__builtin_issubnormal(S, OpPC, Frame, F)) + return retInt(S, OpPC, Dummy); + break; + case Builtin::BI__builtin_iszero: + if (interp__builtin_iszero(S, OpPC, Frame, F)) + return retInt(S, OpPC, Dummy); + break; case Builtin::BI__builtin_isfpclass: if (interp__builtin_isfpclass(S, OpPC, Frame, F, Call)) return retInt(S, OpPC, Dummy); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 8cb7943df9a782..5d3946a84b6c34 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3287,6 +3287,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, ConvertType(E->getType()))); } + case Builtin::BI__builtin_issignaling: { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); + Value *V = EmitScalarExpr(E->getArg(0)); + return RValue::get( + Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcSNan), + ConvertType(E->getType()))); + } + case Builtin::BI__builtin_isinf: { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); Value *V = EmitScalarExpr(E->getArg(0)); @@ -3321,6 +3329,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, ConvertType(E->getType()))); } + case Builtin::BI__builtin_issubnormal: { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); + Value *V = EmitScalarExpr(E->getArg(0)); + return RValue::get( + Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcSubnormal), + ConvertType(E->getType()))); + } + + case Builtin::BI__builtin_iszero: { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); + Value *V = EmitScalarExpr(E->getArg(0)); + return RValue::get( + Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcZero), + ConvertType(E->getType()))); + } + case Builtin::BI__builtin_isfpclass: { Expr::EvalResult Result; if (!E->getArg(1)->EvaluateAsInt(Result, CGM.getContext())) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2594a8f97f7d94..914ed7f3f5c491 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2227,7 +2227,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_isinf: case Builtin::BI__builtin_isinf_sign: case Builtin::BI__builtin_isnan: + case Builtin::BI__builtin_issignaling: case Builtin::BI__builtin_isnormal: + case Builtin::BI__builtin_issubnormal: + case Builtin::BI__builtin_iszero: case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: case Builtin::BI__builtin_signbitl: diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp index 65361d67d68d57..a78a0fbdf11b1d 100644 --- a/clang/test/AST/Interp/builtin-functions.cpp +++ b/clang/test/AST/Interp/builtin-functions.cpp @@ -130,6 +130,8 @@ namespace nan { // expected-error {{must be initialized by a constant expression}} \ // expected-note {{read of dereferenced one-past-the-end pointer}} \ // expected-note {{in call to}} + static_assert(!__builtin_issignaling(__builtin_nan("")), ""); + static_assert(__builtin_issignaling(__builtin_nans("")), ""); } namespace fmin { @@ -153,6 +155,17 @@ namespace inf { static_assert(__builtin_isnormal(1.0), ""); static_assert(!__builtin_isnormal(__builtin_inf()), ""); + +#ifndef __AVR__ + static_assert(__builtin_issubnormal(0x1p-1070), ""); +#endif + static_assert(!__builtin_issubnormal(__builtin_inf()), ""); + + static_assert(__builtin_iszero(0.0), ""); + static_assert(!__builtin_iszero(__builtin_inf()), ""); + + static_assert(__builtin_issignaling(__builtin_nans("")), ""); + static_assert(!__builtin_issignaling(__builtin_inf()), ""); } namespace isfpclass { diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 1b1b2cd6413a34..ce1182b724dcc2 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -64,6 +64,9 @@ int main(void) { P(isinf_sign, (1.)); P(isnan, (1.)); P(isfinite, (1.)); + P(iszero, (1.)); + P(issubnormal, (1.)); + P(issignaling, (1.)); P(isfpclass, (1., 1)); // Bitwise & Numeric Functions @@ -270,6 +273,18 @@ void test_float_builtins(__fp16 *H, float F, double D, long double LD) { // CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264) // CHECK: zext i1 [[TMP]] to i32 + res = __builtin_issubnormal(F); + // CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144) + // CHECK: zext i1 [[TMP]] to i32 + + res = __builtin_iszero(F); + // CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96) + // CHECK: zext i1 [[TMP]] to i32 + + res = __builtin_issignaling(F); + // CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1) + // CHECK: zext i1 [[TMP]] to i32 + res = __builtin_flt_rounds(); // CHECK: call i32 @llvm.get.rounding( } diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index 93948201c451b4..2bdd7b06daabfe 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -124,6 +124,45 @@ char isnormal_inf_neg[!__builtin_isnormal(-__builtin_inf()) ? 1 : -1]; char isnormal_nan [!__builtin_isnormal(__builtin_nan("")) ? 1 : -1]; char isnormal_snan [!__builtin_isnormal(__builtin_nans("")) ? 1 : -1]; +char iszero_inf_pos[!__builtin_iszero(__builtin_inf()) ? 1 : -1]; +char iszero_pos [!__builtin_iszero(1.0) ? 1 : -1]; +char iszero_normf [!__builtin_iszero(1e-37f) ? 1 : -1]; +char iszero_denormf[!__builtin_iszero(1e-38f) ? 1 : -1]; +char iszero_norm [!__builtin_iszero(1e-307) ? 1 : -1]; +char iszero_denorm [!__builtin_iszero(1e-308) ? 1 : -1]; +char iszero_zero [__builtin_iszero(0.0) ? 1 : -1]; +char iszero_negzero[__builtin_iszero(-0.0) ? 1 : -1]; +char iszero_neg [!__builtin_iszero(-1.0) ? 1 : -1]; +char iszero_inf_neg[!__builtin_iszero(-__builtin_inf()) ? 1 : -1]; +char iszero_nan [!__builtin_iszero(__builtin_nan("")) ? 1 : -1]; +char iszero_snan [!__builtin_iszero(__builtin_nans("")) ? 1 : -1]; + +char issubnormal_inf_pos[!__builtin_issubnormal(__builtin_inf()) ? 1 : -1]; +char issubnormal_pos [!__builtin_issubnormal(1.0) ? 1 : -1]; +char issubnormal_normf [!__builtin_issubnormal(1e-37f) ? 1 : -1]; +char issubnormal_denormf[__builtin_issubnormal(1e-38f) ? 1 : -1]; +char issubnormal_norm [!__builtin_issubnormal(1e-307) ? 1 : -1]; +char issubnormal_denorm [__builtin_issubnormal(1e-308) ? 1 : -1]; +char issubnormal_zero [!__builtin_issubnormal(0.0) ? 1 : -1]; +char issubnormal_negzero[!__builtin_issubnormal(-0.0) ? 1 : -1]; +char issubnormal_neg [!__builtin_issubnormal(-1.0) ? 1 : -1]; +char issubnormal_inf_neg[!__builtin_issubnormal(-__builtin_inf()) ? 1 : -1]; +char issubnormal_nan [!__builtin_issubnormal(__builtin_nan("")) ? 1 : -1]; +char issubnormal_snan [!__builtin_issubnormal(__builtin_nans("")) ? 1 : -1]; + +char issignaling_inf_pos[!__builtin_issignaling(__builtin_inf()) ? 1 : -1]; +char issignaling_pos [!__builtin_issignaling(1.0) ? 1 : -1]; +char issignaling_normf [!__builtin_issignaling(1e-37f) ? 1 : -1]; +char issignaling_denormf[!__builtin_issignaling(1e-38f) ? 1 : -1]; +char issignaling_norm [!__builtin_issignaling(1e-307) ? 1 : -1]; +char issignaling_denorm [!__builtin_issignaling(1e-308) ? 1 : -1]; +char issignaling_zero [!__builtin_issignaling(0.0) ? 1 : -1]; +char issignaling_negzero[!__builtin_issignaling(-0.0) ? 1 : -1]; +char issignaling_neg [!__builtin_issignaling(-1.0) ? 1 : -1]; +char issignaling_inf_neg[!__builtin_issignaling(-__builtin_inf()) ? 1 : -1]; +char issignaling_nan [!__builtin_issignaling(__builtin_nan("")) ? 1 : -1]; +char issignaling_snan [__builtin_issignaling(__builtin_nans("")) ? 1 : -1]; + char isfpclass_inf_pos_0[__builtin_isfpclass(__builtin_inf(), 0x0200) ? 1 : -1]; // fcPosInf char isfpclass_inf_pos_1[!__builtin_isfpclass(__builtin_inff(), 0x0004) ? 1 : -1]; // fcNegInf char isfpclass_inf_pos_2[__builtin_isfpclass(__builtin_infl(), 0x0207) ? 1 : -1]; // fcSNan|fcQNan|fcNegInf|fcPosInf