mibintc created this revision. mibintc added reviewers: kpn, sepavloff, andrew.w.kaylor, rjmccall. Herald added subscribers: dexonsmith, dang. mibintc requested review of this revision. Herald added a project: clang.
The Intel compiler supports the option -fp-model={source|double|extended} which causes the compiler to use a wider type for intermediate floating point calculations. Also supported is a way to embed this effect in the source program with #pragma float_control(source|double|extended). This patch proposes to extend pragma float_control syntax, and also to support a new floating point option via -ffp-eval-method={source|double|extended} Note that the C floating point working group has proposed nearly identical pragma semantics in http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1974.pdf like this #pragma STDC FENV_FLT_EVAL_METHOD width I would like to add support for this also, but it's not in this patch. I'm going to add an inline question about how to redefine __FLT_EVAL_METHOD__ macro The ICL option with description of semantics is at this url, https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D93769 Files: clang/docs/LanguageExtensions.rst clang/docs/UsersManual.rst clang/include/clang/Basic/FPOptions.def clang/include/clang/Basic/LangOptions.def clang/include/clang/Basic/LangOptions.h clang/include/clang/Basic/PragmaKinds.h clang/include/clang/Driver/Options.td clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/lib/Parse/ParsePragma.cpp clang/lib/Sema/SemaAttr.cpp clang/lib/Sema/SemaExpr.cpp clang/test/CodeGen/fp-floatcontrol-pragma.cpp
Index: clang/test/CodeGen/fp-floatcontrol-pragma.cpp =================================================================== --- clang/test/CodeGen/fp-floatcontrol-pragma.cpp +++ clang/test/CodeGen/fp-floatcontrol-pragma.cpp @@ -2,6 +2,9 @@ // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s +// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source | FileCheck %s -check-prefix=CHECK-SOURCE +// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s -check-prefix=CHECK-DOUBLE +// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended | FileCheck %s -check-prefix=CHECK-EXTENDED // Verify float_control(precise, off) enables fast math flags on fp operations. float fp_precise_1(float a, float b, float c) { @@ -229,3 +232,45 @@ result = x + t; return result; } + +float mySub(float x, float y) { +// CHECK: define float {{.*}}mySub{{.*}} +// CHECK-NS: fsub float +// CHECK-SOURCE: fsub float +// CHECK-DOUBLE: fpext float +// CHECK-DOUBLE: fpext float +// CHECK-DOUBLE: fsub double +// CHECK-DOUBLE: fptrunc double {{.*}} to float +// CHECK-EXTENDED: fpext float +// CHECK-EXTENDED: fpext float +// CHECK-EXTENDED: fsub double +// CHECK-EXTENDED: fptrunc double {{.*}} to float + return x - y; +} + +float mySubSource( float x, float y ) { +// CHECK: define float {{.*}}mySubSource{{.*}} +#pragma float_control(source) + return x - y; +// CHECK: fsub float +} + +float mySubExtended( float x, float y ) { +// CHECK: define float {{.*}}mySubExtended{{.*}} +#pragma float_control(extended) + return x - y; +// CHECK: fpext float +// CHECK: fpext float +// CHECK: fsub x86_fp80 +// CHECK: fptrunc x86_fp80 {{.*}} to float +} + +float mySubDouble( float x, float y ) { +// CHECK: define float {{.*}}mySubDouble{{.*}} +#pragma float_control(double) + return x - y; +// CHECK: fpext float +// CHECK: fpext float +// CHECK: fsub double +// CHECK: fptrunc double {{.*}} to float +} Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -773,6 +773,32 @@ QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); + auto EvalMethod = CurFPFeatures.getFPEvalMethod(); + if (EvalMethod != LangOptions::FEM_Source && + Ty->isFloatingType()) { + switch (EvalMethod) { + default: + llvm_unreachable("Unrecognized float evaluation method"); + break; + case LangOptions::FEM_Double: + if (Context.getFloatingTypeOrder(Context.DoubleTy, Ty) >0) + // Widen the expression to double. + return Ty->isComplexType() ? + ImpCastExprToType(E, Context.getComplexType(Context.DoubleTy), + CK_FloatingComplexCast) + : ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast); + break; + case LangOptions::FEM_Extended: + if (Context.getFloatingTypeOrder(Context.LongDoubleTy, Ty) > 0) + // Widen the expression to long double. + return Ty->isComplexType() ? + ImpCastExprToType(E, Context.getComplexType(Context.LongDoubleTy), + CK_FloatingComplexCast) + : ImpCastExprToType(E, Context.LongDoubleTy, CK_FloatingCast); + break; + } + } + // Half FP have to be promoted to float unless it is natively supported if (Ty->isHalfType() && !getLangOpts().NativeHalfType) return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast); Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -425,6 +425,18 @@ switch (Value) { default: llvm_unreachable("invalid pragma float_control kind"); + case PFC_Source: + //Builder.defineMacro("__FLT_EVAL_METHOD__", Twine("0")); + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Source); + break; + case PFC_Double: + //Builder.defineMacro("__FLT_EVAL_METHOD__", Twine("1")); + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Double); + break; + case PFC_Extended: + //Builder.defineMacro("__FLT_EVAL_METHOD__", Twine("2")); + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Extended); + break; case PFC_Precise: NewFPFeatures.setFPPreciseEnabled(true); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -2573,21 +2573,28 @@ // Read the identifier. PP.Lex(Tok); - if (Tok.isNot(tok::identifier)) { - PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); - return; - } - - // Verify that this is one of the float control options. - IdentifierInfo *II = Tok.getIdentifierInfo(); - PragmaFloatControlKind Kind = - llvm::StringSwitch<PragmaFloatControlKind>(II->getName()) + PragmaFloatControlKind Kind; + if (Tok.is(tok::kw_double)) { + Kind = PFC_Double; + } else { + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); + return; + } + + // Verify that this is one of the float control options. + IdentifierInfo *II = Tok.getIdentifierInfo(); + Kind = + llvm::StringSwitch<PragmaFloatControlKind>(II->getName()) .Case("precise", PFC_Precise) .Case("except", PFC_Except) .Case("push", PFC_Push) .Case("pop", PFC_Pop) + .Case("source", PFC_Source) + .Case("extended", PFC_Extended) .Default(PFC_Unknown); - PP.Lex(Tok); // the identifier + } + PP.Lex(Tok); // the first pragma token if (Kind == PFC_Unknown) { PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); return; @@ -2616,10 +2623,21 @@ // Kind is set correctly ; else if (PushOnOff == "off") { - if (Kind == PFC_Precise) + switch (Kind) { + default: + break; + case PFC_Precise: Kind = PFC_NoPrecise; - if (Kind == PFC_Except) + break; + case PFC_Except: Kind = PFC_NoExcept; + break; + case PFC_Double: + case PFC_Extended: + // Reset eval mode to 'source' + Kind = PFC_Source; + break; + } } else if (PushOnOff == "push") { Action = Sema::PSK_Push_Set; } else { Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -2756,6 +2756,20 @@ } Opts.setFPExceptionMode(FPEB); + LangOptions::FPEvalMethodKind FEM = LangOptions::FEM_Source; + if (Arg *A = Args.getLastArg(OPT_ffp_eval_method_EQ)) { + StringRef Val = A->getValue(); + if (Val.equals("double")) + FEM = LangOptions::FEM_Double; + else if (Val.equals("extended")) + FEM = LangOptions::FEM_Extended; + else if (Val.equals("source")) + FEM = LangOptions::FEM_Source; + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + } + Opts.setFPEvalMethod(FEM); + // Parse -fsanitize= arguments. parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ), Diags, Opts.Sanitize); Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2525,6 +2525,8 @@ StringRef FPModel = ""; // -ffp-exception-behavior options: strict, maytrap, ignore StringRef FPExceptionBehavior = ""; + // -ffp-eval-method options: double, extended, source + StringRef FPEvalMethod = ""; const llvm::DenormalMode DefaultDenormalFPMath = TC.getDefaultDenormalModeForType(Args, JA); const llvm::DenormalMode DefaultDenormalFP32Math = @@ -2716,6 +2718,18 @@ break; } + // Validate and pass through -ffp-float-precision option. + case options::OPT_ffp_eval_method_EQ: { + StringRef Val = A->getValue(); + if (Val.equals("double") || Val.equals("extended") || + Val.equals("source")) + FPEvalMethod = Val; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + case options::OPT_ffinite_math_only: HonorINFs = false; HonorNaNs = false; @@ -2862,6 +2876,10 @@ CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior)); + if (!FPEvalMethod.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" + + FPEvalMethod)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1343,6 +1343,8 @@ HelpText<"Controls the semantics of floating-point calculations.">; def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Specifies the exception behavior of floating-point operations.">; +def ffp_eval_method_EQ : Joined<["-"], "ffp-eval-method=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Specifies the evaluation method to use for floating point arithmetic.">; defm fast_math : OptInFFlag<"fast-math", "Allow aggressive, lossy floating-point optimizations", "", "", [], "LangOpts->FastMath", [cl_fast_relaxed_math]>; def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">, Flags<[CC1Option]>, Index: clang/include/clang/Basic/PragmaKinds.h =================================================================== --- clang/include/clang/Basic/PragmaKinds.h +++ clang/include/clang/Basic/PragmaKinds.h @@ -32,7 +32,10 @@ PFC_Except, // #pragma float_control(except [,on]) PFC_NoExcept, // #pragma float_control(except, off) PFC_Push, // #pragma float_control(push) - PFC_Pop // #pragma float_control(pop) + PFC_Pop, // #pragma float_control(pop) + PFC_Source, // #pragma float_control(source, {on|off} [,push]) + PFC_Double, // #pragma float_control(double, {on|off} [,push]) + PFC_Extended, // #pragma float_control(extended, {on|off} [,push]) }; } Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -222,6 +222,16 @@ /// Possible exception handling behavior. using ExceptionHandlingKind = llvm::ExceptionHandling; + /// Possible float expression evaluation method choies. + enum FPEvalMethodKind { + /// Use the declared type for fp arithmetic. This is default. + FEM_Source, + /// Use the type double for fp arithmetic. + FEM_Double, + /// Use extended type for fp arithmetic. + FEM_Extended + }; + enum class LaxVectorConversionKind { /// Permit no implicit vector bitcasts. None, @@ -473,6 +483,7 @@ setAllowFEnvAccess(true); else setAllowFEnvAccess(LangOptions::FPM_Off); + setFPEvalMethod(LO.getFPEvalMethod()); } bool allowFPContractWithinStatement() const { Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -283,6 +283,7 @@ COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating point") BENIGN_ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type") BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type") +BENIGN_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_Source, "FP type used for floating point arithmetic") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") Index: clang/include/clang/Basic/FPOptions.def =================================================================== --- clang/include/clang/Basic/FPOptions.def +++ clang/include/clang/Basic/FPOptions.def @@ -23,4 +23,5 @@ OPTION(NoSignedZero, bool, 1, NoHonorInfs) OPTION(AllowReciprocal, bool, 1, NoSignedZero) OPTION(AllowApproxFunc, bool, 1, AllowReciprocal) +OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc) #undef OPTION Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ clang/docs/UsersManual.rst @@ -1453,6 +1453,17 @@ * ``maytrap`` The compiler avoids transformations that may raise exceptions that would not have been raised by the original code. Constant folding performed by the compiler is exempt from this option. * ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code. +.. option:: -ffp-eval-method=<value> + + Specify the floating-point evaluation method. + + Valid values are: ``source``, ``double``, and ``extended``. + The default value is ``source``. Details: + + * ``source`` The compiler uses the floating point type declared in the source program as the evaluation method. + * ``double`` The compiler uses ``double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``double``. + * ``extended`` The compiler uses ``long double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``long double``. + .. _fp-constant-eval: Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -3260,8 +3260,29 @@ governed by the pragma behaves as though the command-line option ``-ffp-exception-behavior=ignore`` is enabled. +When ``pragma float_control(source, on)`` is enabled, the section of code governed +by the pragma behaves as though the command-line option +``-ffp-eval-method=source`` is enabled. Note: ``source`` is the default +floating point evaluation method. + +When ``pragma float_control(double, on)`` is enabled, the section of code governed +by the pragma behaves as though the command-line option +``-ffp-eval-method=double`` is enabled. + +When ``pragma float_control(extended, on)`` is enabled, the section of code governed +by the pragma behaves as though the command-line option +``-ffp-eval-method=extended`` is enabled. + +When ``pragma float_control(source, off)`` or +``pragma float_control(double, off)`` or +``pragma float_control(extended, off)`` is enabled, +the section of code governed +by the pragma behaves as though the command-line option +``-ffp-eval-method=source`` is enabled, returning floating point evaluation +method to the default setting. + The full syntax this pragma supports is -``float_control(except|precise, on|off [, push])`` and +``float_control(except|precise|source|double|extended, on|off [, push])`` and ``float_control(push|pop)``. The ``push`` and ``pop`` forms, including using ``push`` as the optional third argument, can only occur at file scope.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits