https://github.com/c8ef created https://github.com/llvm/llvm-project/pull/113020
None >From 93c625ad60fc834e72df667addc6eec83247fc8c Mon Sep 17 00:00:00 2001 From: c8ef <c...@outlook.com> Date: Sat, 19 Oct 2024 03:45:17 +0000 Subject: [PATCH] constexpr fma --- clang/docs/ReleaseNotes.rst | 1 + clang/include/clang/Basic/Builtins.td | 1 + clang/lib/AST/ByteCode/InterpBuiltin.cpp | 37 +++++++++++++++++++ clang/lib/AST/ExprConstant.cpp | 16 ++++++++ clang/test/AST/ByteCode/builtin-functions.cpp | 9 +++++ clang/test/Sema/constant-builtins-2.c | 7 ++++ 6 files changed, 71 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b7a6ace8bb895d..605d55a9e51f37 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -273,6 +273,7 @@ Non-comprehensive list of changes in this release - Plugins can now define custom attributes that apply to statements as well as declarations. - ``__builtin_abs`` function can now be used in constant expressions. +- ``__builtin_fma`` function can now be used in constant expressions. New Compiler Flags ------------------ diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 90475a361bb8f8..55f470a9f715b9 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -3723,6 +3723,7 @@ def Fma : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, T, T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Fmax : FPMathTemplate, LibBuiltin<"math.h"> { diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index d4a8e6c2035ee5..145f4627dd73da 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -142,6 +142,19 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result, #undef RET_CASE } +/// Get rounding mode to use in evaluation of the specified expression. +/// +/// If rounding mode is unknown at compile time, still try to evaluate the +/// expression. If the result is exact, it does not depend on rounding mode. +/// So return "tonearest" mode instead of "dynamic". +static llvm::RoundingMode getActiveRoundingMode(InterpState &S, const Expr *E) { + llvm::RoundingMode RM = + E->getFPFeaturesInEffect(S.getLangOpts()).getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + RM = llvm::RoundingMode::NearestTiesToEven; + return RM; +} + static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { @@ -549,6 +562,22 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_fma(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + const Floating &X = getParam<Floating>(Frame, 0); + const Floating &Y = getParam<Floating>(Frame, 1); + const Floating &Z = getParam<Floating>(Frame, 2); + Floating Result; + + llvm::RoundingMode RM = getActiveRoundingMode(S, Call); + Floating::mul(X, Y, RM, &Result); + Floating::add(Result, Z, RM, &Result); + + S.Stk.push<Floating>(Result); + return true; +} + // The C standard says "fabs raises no floating-point exceptions, // even if x is a signaling NaN. The returned value is independent of // the current rounding direction mode." Therefore constant folding can @@ -1814,6 +1843,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__builtin_fma: + case Builtin::BI__builtin_fmaf: + case Builtin::BI__builtin_fmal: + case Builtin::BI__builtin_fmaf128: + if (!interp__builtin_fma(S, OpPC, Frame, F, Call)) + return false; + break; + case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 8e36cad2d2c6e7..685ce8a63f6c9e 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -15314,6 +15314,22 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { Result.changeSign(); return true; + case Builtin::BI__builtin_fma: + case Builtin::BI__builtin_fmaf: + case Builtin::BI__builtin_fmal: + case Builtin::BI__builtin_fmaf128: { + APFloat Y(0.), Z(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), Y, Info) || + !EvaluateFloat(E->getArg(2), Z, Info)) + return false; + + llvm::RoundingMode RM = getActiveRoundingMode(Info, E); + Result.multiply(Y, RM); + Result.add(Z, RM); + return true; + } + case Builtin::BI__arithmetic_fence: return EvaluateFloat(E->getArg(0), Result, Info); diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index b5d334178f8213..0dba62e252b3d7 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -265,6 +265,15 @@ namespace fpclassify { char classify_subnorm [__builtin_fpclassify(-1, -1, -1, +1, -1, 1.0e-38f)]; } +namespace fma { + static_assert(__builtin_fma(1.0, 1.0, 1.0) == 2.0); + static_assert(__builtin_fma(1.0, -1.0, 1.0) == 0.0); + static_assert(__builtin_fmaf(1.0f, 1.0f, 1.0f) == 2.0f); + static_assert(__builtin_fmaf(1.0f, -1.0f, 1.0f) == 0.0f); + static_assert(__builtin_fmal(1.0L, 1.0L, 1.0L) == 2.0L); + static_assert(__builtin_fmal(1.0L, -1.0L, 1.0L) == 0.0L); +} // namespace fma + namespace abs { static_assert(__builtin_abs(14) == 14, ""); static_assert(__builtin_labs(14L) == 14L, ""); diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index e465a3c5f0ad86..2a2dbc2caee1d1 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -54,6 +54,13 @@ long double g18 = __builtin_copysignl(1.0L, -1.0L); __float128 g18_2 = __builtin_copysignf128(1.0q, -1.0q); #endif +double g19 = __builtin_fma(1.0, 1.0, 1.0); +float g20 = __builtin_fmaf(1.0f, 1.0f, 1.0f); +long double g21 = __builtin_fmal(1.0L, 1.0L, 1.0L); +#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__) +__float128 g21_2 = __builtin_fma(1.0q, 1.0q, 1.0q); +#endif + char classify_nan [__builtin_fpclassify(+1, -1, -1, -1, -1, __builtin_nan(""))]; char classify_snan [__builtin_fpclassify(+1, -1, -1, -1, -1, __builtin_nans(""))]; char classify_inf [__builtin_fpclassify(-1, +1, -1, -1, -1, __builtin_inf())]; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits