diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -4659,13 +4659,17 @@ * ``__builtin_ffs`` * ``__builtin_ffsl`` * ``__builtin_ffsll`` +* ``__builtin_fmax`` +* ``__builtin_fmin`` * ``__builtin_fpclassify`` +* ``__builtin_ilogb`` * ``__builtin_inf`` * ``__builtin_isinf`` * ``__builtin_isinf_sign`` * ``__builtin_isfinite`` * ``__builtin_isnan`` * ``__builtin_isnormal`` +* ``__builtin_logb`` * ``__builtin_nan`` * ``__builtin_nans`` * ``__builtin_parity`` @@ -4682,6 +4686,7 @@ * ``__builtin_rotateright16`` * ``__builtin_rotateright32`` * ``__builtin_rotateright64`` +* ``__builtin_scalbn`` The following x86-specific intrinsics can be used in constant expressions: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12410,6 +12410,19 @@ return false; return Success(DidOverflow, E); } + + case Builtin::BI__builtin_ilogb: + case Builtin::BI__builtin_ilogbf: + case Builtin::BI__builtin_ilogbl: + case Builtin::BI__builtin_ilogbf128: { + APFloat F(0.0); + if (!EvaluateFloat(E->getArg(0), F, Info)) + return false; + APSInt Logb(llvm::APInt(32, ilogb(F), /*isSigned=*/true), + /*isUnsigned=*/false); + Result = APValue(std::move(Logb)); + return true; + } } } @@ -14021,6 +14034,58 @@ Result.copySign(RHS); return true; } + + case Builtin::BI__builtin_fmax: + case Builtin::BI__builtin_fmaxf: + case Builtin::BI__builtin_fmaxl: + case Builtin::BI__builtin_fmaxf16: + case Builtin::BI__builtin_fmaxf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + if (RHS > Result) + Result = RHS; + return true; + } + + case Builtin::BI__builtin_fmin: + case Builtin::BI__builtin_fminf: + case Builtin::BI__builtin_fminl: + case Builtin::BI__builtin_fminf16: + case Builtin::BI__builtin_fminf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + if (RHS < Result) + Result = RHS; + return true; + } + + case Builtin::BI__builtin_logb: + case Builtin::BI__builtin_logbf: + case Builtin::BI__builtin_logbl: + case Builtin::BI__builtin_logbf128: { + APFloat F(0.0); + if (!EvaluateFloat(E->getArg(0), F, Info)) + return false; + Result = logb(F); + return true; + } + + case Builtin::BI__builtin_scalbn: + case Builtin::BI__builtin_scalbnf: + case Builtin::BI__builtin_scalbnl: + case Builtin::BI__builtin_scalbnf128: { + APFloat X(0.0); + APSInt Exp; + if (!EvaluateFloat(E->getArg(0), X, Info) || + !EvaluateInteger(E->getArg(1), Exp, Info)) + return false; + Result = scalbn(X, Exp.getExtValue(), APFloat::rmNearestTiesToEven); + return true; + } } } diff --git a/clang/test/Sema/constant-builtins-math.cpp b/clang/test/Sema/constant-builtins-math.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/constant-builtins-math.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +static_assert(__builtin_fmax(12.34, 56.78) == 56.78); +static_assert(__builtin_fmaxf(12.34f, 56.78f) == 56.78f); +static_assert(__builtin_fmaxl(12.34, 56.78) == 56.78); +static_assert(__builtin_fmaxf16(12.0, 56.0) == 56.0); +static_assert(__builtin_fmaxf128(12.34, 56.78) == 56.78); + +static_assert(__builtin_fmin(12.34, 56.78) == 12.34); +static_assert(__builtin_fminf(12.34f, 56.78f) == 12.34f); +static_assert(__builtin_fminl(12.34, 56.78) == 12.34); +static_assert(__builtin_fminf16(12.0, 56.0) == 12.0); +static_assert(__builtin_fminf128(12.34, 56.78) == 12.34); + +// TODO: investigate why this is `INT_MIN + 1` instead of `INT_MIN` +static_assert(__builtin_ilogb(0.0) == -2147483647); +static_assert(__builtin_ilogb(__builtin_inf()) == 2147483647); +static_assert(__builtin_ilogb(__builtin_nan("")) == -2147483648); +static_assert(__builtin_ilogb(1.0) == 0); +static_assert(__builtin_ilogb(32.0) == 5); +static_assert(__builtin_ilogb(1024.0) == 10); +static_assert(__builtin_ilogb(-1024.0) == 10); +static_assert(__builtin_ilogb(0.1) == -4); +static_assert(__builtin_ilogb(0.0000000000001) == -44); + +static_assert(__builtin_logb(0.0) == -__builtin_inf()); +static_assert(__builtin_logb(__builtin_inf()) == __builtin_inf()); +static_assert(__builtin_isnan(__builtin_logb(__builtin_nan("")))); +static_assert(__builtin_logb(1.0) == 0.0); +static_assert(__builtin_logb(32.0) == 5.0); +static_assert(__builtin_logb(1024.0) == 10.0); +static_assert(__builtin_logb(-1024.0) == 10.0); +static_assert(__builtin_logb(0.1) == -4.0); +static_assert(__builtin_logb(0.0000000000001) == -44.0); + +static_assert(__builtin_scalbn(12.5, 0) == 12.5); +static_assert(__builtin_scalbn(12.5, 1) == 25); +static_assert(__builtin_scalbn(12.5, 3) == 100.0); +static_assert(__builtin_scalbn(0.0, 100) == 0); +static_assert(__builtin_scalbn(__builtin_inf(), 100) == __builtin_inf()); +static_assert(__builtin_isnan(__builtin_scalbn(__builtin_nan(""), 100))); diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -592,6 +592,7 @@ hash_code hash_value(const IEEEFloat &Arg); int ilogb(const IEEEFloat &Arg); +IEEEFloat logb(const IEEEFloat &Arg); IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode); IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM); @@ -1248,6 +1249,9 @@ friend hash_code hash_value(const APFloat &Arg); friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); } + friend APFloat logb(const APFloat &Arg) { + return APFloat(logb(Arg.getIEEE()), Arg.getSemantics()); + } friend APFloat scalbn(APFloat X, int Exp, roundingMode RM); friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM); friend IEEEFloat; diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -4198,6 +4198,19 @@ return Normalized.exponent - SignificandBits; } +IEEEFloat logb(const IEEEFloat &Arg) { + IEEEFloat Result(Arg.getSemantics()); + if (Arg.isNaN()) + Result.makeNaN(); + else if (Arg.isZero()) + Result.makeInf(/*Negative=*/true); + else if (Arg.isInfinity()) + Result.makeInf(/*Negative=*/false); + else + Result = IEEEFloat(static_cast(ilogb(Arg))); + return Result; +} + IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode RoundingMode) { auto MaxExp = X.getSemantics().maxExponent; auto MinExp = X.getSemantics().minExponent;