diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index f45d88092eb4a8..5249d3f3f79300 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -3907,6 +3907,38 @@ A ``#pragma clang fp`` pragma may contain any number of options: ... } +``#pragma clang fp eval_method`` allows floating-point behavior to be specified +for a section of the source code. This pragma can appear at file or namespace +scope, or at the start of a compound statement (excluding comments). +The pragma is active within the scope of the compound statement. + +When ``pragma clang fp eval_method(source)`` is enabled, the section of code +governed by the pragma behaves as though the command-line option +``-ffp-eval-method=source`` is enabled. Rounds intermediate results to +source-defined precision. + +When ``pragma clang fp eval_method(double)`` is enabled, the section of code +governed by the pragma behaves as though the command-line option +``-ffp-eval-method=double`` is enabled. Rounds intermediate results to +``double`` precision. + +When ``pragma clang fp eval_method(extended)`` is enabled, the section of code +governed by the pragma behaves as though the command-line option +``-ffp-eval-method=extended`` is enabled. Rounds intermediate results to +target-dependent ``long double`` precision. In Win32 programming, for instance, +the long double data type maps to the double, 64-bit precision data type. + +The full syntax this pragma supports is +``#pragma clang fp eval_method(source|double|extended)``. + +.. code-block:: c++ + + for(...) { + // The compiler will use long double as the floating-point evaluation + // method. + #pragma clang fp eval_method(extended) + a = b[i] * c[i] + e; + } The ``#pragma float_control`` pragma allows precise floating-point semantics and floating-point exception behavior to be specified diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 1df96296cb8ac7..70fee29ab2a845 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1566,6 +1566,22 @@ Note that floating-point operations performed as part of constant initialization * ``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= + + Specify the floating-point evaluation method for intermediate results within + a single expression of the code. + + Valid values are: ``source``, ``double``, and ``extended``. + For 64-bit targets, the default value is ``source``. For 32-bit x86 targets + however, in the case of NETBSD 6.99.26 and under, the default value is + ``double``; in the case of NETBSD greater than 6.99.26, with NoSSE, the + default value is ``extended``, with SSE 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``. + .. option:: -f[no-]protect-parens: This option pertains to floating-point types, complex types with @@ -1587,6 +1603,17 @@ Note that floating-point operations performed as part of constant initialization has no effect because the optimizer is prohibited from making unsafe transformations. +.. _FLT_EVAL_METHOD: + +A note about ``__FLT_EVAL_METHOD__`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The macro ``__FLT_EVAL_METHOD__`` will expand to either the value set from the +command line option ``ffp-eval-method`` or to the value from the target info +setting. The ``__FLT_EVAL_METHOD__`` macro cannot expand to the correct +evaluation method in the presence of a ``#pragma`` which alters the evaluation +method. An error is issued if ``__FLT_EVAL_METHOD__`` is expanded inside a scope +modified by ``#pragma clang fp eval_method``. + .. _fp-constant-eval: A note about Floating Point Constant Evaluation diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 421527827a4bdb..bbf26d637265ec 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -318,6 +318,11 @@ def err_opt_not_valid_on_target : Error< def err_invalid_feature_combination : Error< "invalid feature combination: %0">; +// Eval method +def warn_no_support_for_eval_method_source_on_m32 : Warning< + "Setting FPEvalMethod to source on a 32bit target, with no SSE is" + " not supported.">; + // Source manager def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; def err_file_modified : Error< diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index a4436208799f9a..0f424b02c812a8 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -321,6 +321,10 @@ def err_pragma_include_instead_system_reserved : Error< "header '%0' is an implementation detail; #include %select{'%2'|either '%2' " "or '%3'|one of %2}1 instead">; +def err_illegal_use_of_flt_eval_macro : Error< + "'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing " + "'#pragma clang fp eval_method'">; + def pp_poisoning_existing_macro : Warning<"poisoning existing macro">; def pp_out_of_date_dependency : Warning< "current file is older than dependency %0">; diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def index a93fa475cd5f65..224c1827144f55 100644 --- a/clang/include/clang/Basic/FPOptions.def +++ b/clang/include/clang/Basic/FPOptions.def @@ -23,4 +23,5 @@ OPTION(NoHonorInfs, bool, 1, NoHonorNaNs) OPTION(NoSignedZero, bool, 1, NoHonorInfs) OPTION(AllowReciprocal, bool, 1, NoSignedZero) OPTION(AllowApproxFunc, bool, 1, AllowReciprocal) +OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc) #undef OPTION diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 4651f4fff6aa00..89b11fdea89b22 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -301,6 +301,7 @@ BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contracti 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_UnsetOnCommandLine, "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") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 50c7f038fc6be1..2e334e375950ee 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -235,6 +235,24 @@ class LangOptions : public LangOptionsBase { FPE_Strict }; + /// Possible float expression evaluation method choices. + enum FPEvalMethodKind { + /// The evaluation method cannot be determined or is inconsistent for this + /// target. + FEM_Indeterminable = -1, + /// Use the declared type for fp arithmetic. + FEM_Source = 0, + /// Use the type double for fp arithmetic. + FEM_Double = 1, + /// Use extended type for fp arithmetic. + FEM_Extended = 2, + /// Used only for FE option processing; this is only used to indicate that + /// the user did not specify an explicit evaluation method on the command + /// line and so the target should be queried for its default evaluation + /// method instead. + FEM_UnsetOnCommandLine = 3 + }; + /// Possible exception handling behavior. enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm }; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 22918f7e12e843..8e18ded7d37651 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -726,7 +726,11 @@ class TargetInfo : public virtual TransferrableTargetInfo, } /// Return the value for the C99 FLT_EVAL_METHOD macro. - virtual unsigned getFloatEvalMethod() const { return 0; } + virtual LangOptions::FPEvalMethodKind getFPEvalMethod() const { + return LangOptions::FPEvalMethodKind::FEM_Source; + } + + virtual bool supportSourceEvalMethod() const { return true; } // getLargeArrayMinWidth/Align - Return the minimum array size that is // 'large' and its alignment. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b81973155cae6e..f1e8b967c78e55 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1495,6 +1495,11 @@ def : Flag<["-"], "fextended-identifiers">, Group; def : Flag<["-"], "fno-extended-identifiers">, Group, Flags<[Unsupported]>; def fhosted : Flag<["-"], "fhosted">, Group; def fdenormal_fp_math_EQ : Joined<["-"], "fdenormal-fp-math=">, Group, Flags<[CC1Option]>; +def ffp_eval_method_EQ : Joined<["-"], "ffp-eval-method=">, Group, Flags<[CC1Option]>, + HelpText<"Specifies the evaluation method to use for floating-point arithmetic.">, + Values<"source,double,extended">, NormalizedValuesScope<"LangOptions">, + NormalizedValues<["FEM_Source", "FEM_Double", "FEM_Extended"]>, + MarshallingInfoEnum, "FEM_UnsetOnCommandLine">; def ffp_model_EQ : Joined<["-"], "ffp-model=">, Group, Flags<[NoXarchOption]>, HelpText<"Controls the semantics of floating-point calculations.">; def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group, Flags<[CC1Option]>, diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 2802329a60220e..f2c84e43ddca38 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -179,12 +179,27 @@ class Preprocessor { IdentifierInfo *Ident__is_target_vendor; // __is_target_vendor IdentifierInfo *Ident__is_target_os; // __is_target_os IdentifierInfo *Ident__is_target_environment; // __is_target_environment + IdentifierInfo *Ident__FLT_EVAL_METHOD__; // __FLT_EVAL_METHOD // Weak, only valid (and set) while InMacroArgs is true. Token* ArgMacro; SourceLocation DATELoc, TIMELoc; + // FEM_UnsetOnCommandLine means that an explicit evaluation method was + // not specified on the command line. The target is queried to set the + // default evaluation method. + LangOptions::FPEvalMethodKind CurrentFPEvalMethod = + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; + + // The most recent pragma location where the floating point evaluation + // method was modified. This is used to determine whether the + // 'pragma clang fp eval_method' was used whithin the current scope. + SourceLocation LastFPEvalPragmaLocation; + + LangOptions::FPEvalMethodKind TUFPEvalMethod = + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; + // Next __COUNTER__ value, starts at 0. unsigned CounterValue = 0; @@ -2048,6 +2063,32 @@ class Preprocessor { unsigned getCounterValue() const { return CounterValue; } void setCounterValue(unsigned V) { CounterValue = V; } + LangOptions::FPEvalMethodKind getCurrentFPEvalMethod() const { + assert(CurrentFPEvalMethod != LangOptions::FEM_UnsetOnCommandLine && + "FPEvalMethod should be set either from command line or from the " + "target info"); + return CurrentFPEvalMethod; + } + + LangOptions::FPEvalMethodKind getTUFPEvalMethod() const { + return TUFPEvalMethod; + } + + SourceLocation getLastFPEvalPragmaLocation() const { + return LastFPEvalPragmaLocation; + } + + void setCurrentFPEvalMethod(SourceLocation PragmaLoc, + LangOptions::FPEvalMethodKind Val) { + assert(Val != LangOptions::FEM_UnsetOnCommandLine && + "FPEvalMethod should never be set to FEM_UnsetOnCommandLine"); + // This is the location of the '#pragma float_control" where the + // execution state is modifed. + LastFPEvalPragmaLocation = PragmaLoc; + CurrentFPEvalMethod = Val; + TUFPEvalMethod = Val; + } + /// Retrieves the module that we're currently building, if any. Module *getCurrentModule(); diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 981800a7e2356d..d2e588992238de 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -184,6 +184,7 @@ class Parser : public CodeCompletionHandler { std::unique_ptr PCSectionHandler; std::unique_ptr MSCommentHandler; std::unique_ptr MSDetectMismatchHandler; + std::unique_ptr FPEvalMethodHandler; std::unique_ptr FloatControlHandler; std::unique_ptr MSPointersToMembers; std::unique_ptr MSVtorDisp; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c1e846c55dee7f..60ee577fca06a2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1541,19 +1541,16 @@ class Sema final { /// statements. class FPFeaturesStateRAII { public: - FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.CurFPFeatures) { - OldOverrides = S.FpPragmaStack.CurrentValue; - } - ~FPFeaturesStateRAII() { - S.CurFPFeatures = OldFPFeaturesState; - S.FpPragmaStack.CurrentValue = OldOverrides; - } + FPFeaturesStateRAII(Sema &S); + ~FPFeaturesStateRAII(); FPOptionsOverride getOverrides() { return OldOverrides; } private: Sema& S; FPOptions OldFPFeaturesState; FPOptionsOverride OldOverrides; + LangOptions::FPEvalMethodKind OldEvalMethod; + SourceLocation OldFPPragmaLocation; }; void addImplicitTypedef(StringRef Name, QualType T); @@ -10131,6 +10128,9 @@ class Sema final { !CurFPFeatures.getAllowApproxFunc(); } + void ActOnPragmaFPEvalMethod(SourceLocation Loc, + LangOptions::FPEvalMethodKind Value); + /// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control void ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action, PragmaFloatControlKind Value); diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 3c1830d5f8e891..f61652d285a890 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -749,7 +749,9 @@ class AIXTargetInfo : public OSTargetInfo { } // AIX sets FLT_EVAL_METHOD to be 1. - unsigned getFloatEvalMethod() const override { return 1; } + LangOptions::FPEvalMethodKind getFPEvalMethod() const override { + return LangOptions::FPEvalMethodKind::FEM_Double; + } bool defaultsToAIXPowerAlignment() const override { return true; } }; diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index d1b66432e38b47..e0bb3c344c5b68 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -168,11 +168,15 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { return LongDoubleFormat == &llvm::APFloat::IEEEquad() ? "g" : "e"; } - unsigned getFloatEvalMethod() const override { + LangOptions::FPEvalMethodKind getFPEvalMethod() const override { // X87 evaluates with 80 bits "long double" precision. - return SSELevel == NoSSE ? 2 : 0; + return SSELevel == NoSSE ? LangOptions::FPEvalMethodKind::FEM_Extended + : LangOptions::FPEvalMethodKind::FEM_Source; } + // EvalMethod `source` is not supported for targets with `NoSSE` feature. + bool supportSourceEvalMethod() const override { return SSELevel > NoSSE; } + ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { @@ -471,13 +475,13 @@ class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : NetBSDTargetInfo(Triple, Opts) {} - unsigned getFloatEvalMethod() const override { + LangOptions::FPEvalMethodKind getFPEvalMethod() const override { VersionTuple OsVersion = getTriple().getOSVersion(); // New NetBSD uses the default rounding mode. if (OsVersion >= VersionTuple(6, 99, 26) || OsVersion.getMajor() == 0) - return X86_32TargetInfo::getFloatEvalMethod(); + return X86_32TargetInfo::getFPEvalMethod(); // NetBSD before 6.99.26 defaults to "double" rounding. - return 1; + return LangOptions::FPEvalMethodKind::FEM_Double; } }; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 945f6269777990..ee32e5849ff842 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2719,6 +2719,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, 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 = @@ -2914,6 +2916,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, break; } + // Validate and pass through -ffp-eval-method 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; @@ -3069,6 +3083,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, 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 diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index bf8a0b2abe22ea..ff507e2c00aaad 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1136,7 +1136,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, } // Macros to control C99 numerics and - Builder.defineMacro("__FLT_EVAL_METHOD__", Twine(TI.getFloatEvalMethod())); Builder.defineMacro("__FLT_RADIX__", "2"); Builder.defineMacro("__DECIMAL_DIG__", "__LDBL_DECIMAL_DIG__"); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index a29ff215d7ea0b..82fc57c8f2e88d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -342,6 +342,7 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__TIME__ = RegisterBuiltinMacro(*this, "__TIME__"); Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__"); Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma"); + Ident__FLT_EVAL_METHOD__ = RegisterBuiltinMacro(*this, "__FLT_EVAL_METHOD__"); // C++ Standing Document Extensions. if (getLangOpts().CPlusPlus) @@ -1574,6 +1575,17 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Surround the string with " and strip the trailing newline. OS << '"' << StringRef(Result).drop_back() << '"'; Tok.setKind(tok::string_literal); + } else if (II == Ident__FLT_EVAL_METHOD__) { + // __FLT_EVAL_METHOD__ is set to the default value. + OS << getTUFPEvalMethod(); + // __FLT_EVAL_METHOD__ expands to a simple numeric value. + Tok.setKind(tok::numeric_constant); + if (getLastFPEvalPragmaLocation().isValid()) { + // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is altered + // by the pragma. + Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); + Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); + } } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 27e8501278626a..5c6aa0e47635b7 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -3028,12 +3028,13 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, namespace { /// Used as the annotation value for tok::annot_pragma_fp. struct TokFPAnnotValue { - enum FlagKinds { Contract, Reassociate, Exceptions }; + enum FlagKinds { Contract, Reassociate, Exceptions, EvalMethod }; enum FlagValues { On, Off, Fast }; llvm::Optional ContractValue; llvm::Optional ReassociateValue; llvm::Optional ExceptionsValue; + llvm::Optional EvalMethodValue; }; } // end anonymous namespace @@ -3060,6 +3061,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, .Case("contract", TokFPAnnotValue::Contract) .Case("reassociate", TokFPAnnotValue::Reassociate) .Case("exceptions", TokFPAnnotValue::Exceptions) + .Case("eval_method", TokFPAnnotValue::EvalMethod) .Default(None); if (!FlagKind) { PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option) @@ -3074,8 +3076,11 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, return; } PP.Lex(Tok); + bool isEvalMethodDouble = + Tok.is(tok::kw_double) && FlagKind == TokFPAnnotValue::EvalMethod; - if (Tok.isNot(tok::identifier)) { + // Don't diagnose if we have an eval_metod pragma with "double" kind. + if (Tok.isNot(tok::identifier) && !isEvalMethodDouble) { PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) << PP.getSpelling(Tok) << OptionInfo->getName() << static_cast(*FlagKind); @@ -3121,6 +3126,19 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; return; } + } else if (FlagKind == TokFPAnnotValue::EvalMethod) { + AnnotValue->EvalMethodValue = + llvm::StringSwitch>( + II->getName()) + .Case("source", LangOptions::FPEvalMethodKind::FEM_Source) + .Case("double", LangOptions::FPEvalMethodKind::FEM_Double) + .Case("extended", LangOptions::FPEvalMethodKind::FEM_Extended) + .Default(llvm::None); + if (!AnnotValue->EvalMethodValue) { + PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) + << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; + return; + } } PP.Lex(Tok); @@ -3223,6 +3241,9 @@ void Parser::HandlePragmaFP() { if (AnnotValue->ExceptionsValue) Actions.ActOnPragmaFPExceptions(Tok.getLocation(), *AnnotValue->ExceptionsValue); + if (AnnotValue->EvalMethodValue) + Actions.ActOnPragmaFPEvalMethod(Tok.getLocation(), + *AnnotValue->EvalMethodValue); ConsumeAnnotationToken(); } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index ee07775b6346ff..cadedf6d98dbde 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1153,6 +1153,16 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { if (R.isUsable()) Stmts.push_back(R.get()); } + // Warn the user that using option `-ffp-eval-method=source` on a + // 32-bit target and feature `sse` disabled, or using + // `pragma clang fp eval_method=source` and feature `sse` disabled, is not + // supported. + if (!PP.getTargetInfo().supportSourceEvalMethod() && + (PP.getLastFPEvalPragmaLocation().isValid() || + PP.getCurrentFPEvalMethod() == + LangOptions::FPEvalMethodKind::FEM_Source)) + Diag(Tok.getLocation(), + diag::warn_no_support_for_eval_method_source_on_m32); SourceLocation CloseLoc = Tok.getLocation(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 7b57c8da4e9cca..db3eda622639f5 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -242,6 +242,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, SemaPPCallbackHandler = Callbacks.get(); PP.addPPCallbacks(std::move(Callbacks)); SemaPPCallbackHandler->set(*this); + if (getLangOpts().getFPEvalMethod() == LangOptions::FEM_UnsetOnCommandLine) + // Use setting from TargetInfo. + PP.setCurrentFPEvalMethod(SourceLocation(), + ctxt.getTargetInfo().getFPEvalMethod()); + else + // Set initial value of __FLT_EVAL_METHOD__ from the command line. + PP.setCurrentFPEvalMethod(SourceLocation(), + getLangOpts().getFPEvalMethod()); + CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod()); } // Anchor Sema's type info to this TU. @@ -2630,3 +2639,15 @@ const llvm::MapVector & Sema::getMismatchingDeleteExpressions() const { return DeleteExprs; } + +Sema::FPFeaturesStateRAII::FPFeaturesStateRAII(Sema &S) + : S(S), OldFPFeaturesState(S.CurFPFeatures), + OldOverrides(S.FpPragmaStack.CurrentValue), + OldEvalMethod(S.PP.getCurrentFPEvalMethod()), + OldFPPragmaLocation(S.PP.getLastFPEvalPragmaLocation()) {} + +Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() { + S.CurFPFeatures = OldFPFeaturesState; + S.FpPragmaStack.CurrentValue = OldOverrides; + S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod); +} diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 38e6e60af90dbf..d623060fd10cf1 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -470,6 +470,27 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD)); } +void Sema::ActOnPragmaFPEvalMethod(SourceLocation Loc, + LangOptions::FPEvalMethodKind Value) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + switch (Value) { + default: + llvm_unreachable("invalid pragma eval_method kind"); + case LangOptions::FEM_Source: + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Source); + break; + case LangOptions::FEM_Double: + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Double); + break; + case LangOptions::FEM_Extended: + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Extended); + break; + } + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + PP.setCurrentFPEvalMethod(Loc, Value); +} + void Sema::ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action, PragmaFloatControlKind Value) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 22b3f371afe79a..88fc89bec629a0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -773,6 +773,40 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); + LangOptions::FPEvalMethodKind EvalMethod = CurFPFeatures.getFPEvalMethod(); + if (EvalMethod != LangOptions::FEM_Source && Ty->isFloatingType() && + (getLangOpts().getFPEvalMethod() != + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine || + PP.getLastFPEvalPragmaLocation().isValid())) { + switch (EvalMethod) { + default: + llvm_unreachable("Unrecognized float evaluation method"); + break; + case LangOptions::FEM_UnsetOnCommandLine: + llvm_unreachable("Float evaluation method should be set by now"); + 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); diff --git a/clang/test/CodeGen/X86/32bit-behavior-no-eval.c b/clang/test/CodeGen/X86/32bit-behavior-no-eval.c new file mode 100644 index 00000000000000..d040e827ce31ce --- /dev/null +++ b/clang/test/CodeGen/X86/32bit-behavior-no-eval.c @@ -0,0 +1,30 @@ +// SSE +// RUN: %clang_cc1 \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \ +// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s + +// NO SSE +// RUN: %clang_cc1 \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s + +// NO SSE Fast Math +// RUN: %clang_cc1 \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -ffast-math -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FM %s + +float addit(float a, float b, float c) { + // CHECK: load float, float* + // CHECK: load float, float* + // CHECK: fadd float + // CHECK: load float, float* + // CHECK: fadd float + + // CHECK-FM: load float, float* + // CHECK-FM: load float, float* + // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn float + // CHECK-FM: load float, float* + // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn float + + return a + b + c; +} diff --git a/clang/test/CodeGen/X86/32bit-behavior.c b/clang/test/CodeGen/X86/32bit-behavior.c new file mode 100644 index 00000000000000..a7e0f008c9f353 --- /dev/null +++ b/clang/test/CodeGen/X86/32bit-behavior.c @@ -0,0 +1,109 @@ +// SSE +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=source \ +// RUN: | FileCheck -check-prefix=CHECK-SRC %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=double \ +// RUN: | FileCheck -check-prefix=CHECK-DBL %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \ +// RUN: | FileCheck -check-prefix=CHECK-DBL %s + +// SSE Fast Math +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=source \ +// RUN: -ffast-math | FileCheck -check-prefix=CHECK-FM-SRC %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=double \ +// RUN: -ffast-math | FileCheck -check-prefix=CHECK-FM %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \ +// RUN: -ffast-math | FileCheck -check-prefix=CHECK-FM %s + +// NO SSE +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=source \ +// RUN: | FileCheck -check-prefix=CHECK-SRC %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=double \ +// RUN: | FileCheck -check-prefix=CHECK-DBL %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \ +// RUN: | FileCheck -check-prefix=CHECK-DBL %s + +// NO SSE Fast Math +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=source \ +// RUN: -ffast-math | FileCheck -check-prefix=CHECK %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=double \ +// RUN: -ffast-math | FileCheck -check-prefix=CHECK-DBL-FM %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \ +// RUN: -ffast-math | FileCheck -check-prefix=CHECK-DBL-FM %s + +float addit(float a, float b, float c) { + // CHECK-SRC: load float, float* + // CHECK-SRC: load float, float* + // CHECK-SRC: fadd float + // CHECK-SRC: load float, float* + // CHECK-SRC: fadd float + + // CHECK-FM-SRC: load float, float* + // CHECK-FM-SRC: load float, float* + // CHECK-FM-SRC: fadd reassoc nnan ninf nsz arcp afn float + // CHECK-FM-SRC: load float, float* + // CHECK-FM-SRC: fadd reassoc nnan ninf nsz arcp afn float + + // CHECK-FM: load float, float* + // CHECK-FM: fpext float {{.*}} to double + // CHECK-FM: load float, float* + // CHECK-FM: fpext float {{.*}} to double + // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn double + // CHECK-FM: load float, float* + // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn double + // CHECK-FM: fptrunc double {{.*}} to float + + // CHECK-DBL: load float, float* + // CHECK-DBL: fpext float {{.*}} to double + // CHECK-DBL: load float, float* + // CHECK-DBL: fpext float {{.*}} to double + // CHECK-DBL: fadd double + // CHECK-DBL: load float, float* + // CHECK-DBL: fpext float {{.*}} to double + // CHECK-DBL: fadd double + // CHECK-DBL: fptrunc double {{.*}} to float + + // CHECK-DBL-FM: load float, float* + // CHECK-DBL-FM: fpext float {{.*}} to double + // CHECK-DBL-FM: load float, float* + // CHECK-DBL-FM: fpext float {{.*}} to double + // CHECK-DBL-FM: fadd reassoc nnan ninf nsz arcp afn double + // CHECK-DBL-FM: load float, float* + // CHECK-DBL-FM: fpext float {{.*}} to double + // CHECK-DBL-FM: fadd reassoc nnan ninf nsz arcp afn double + // CHECK-DBL-FM: fptrunc double {{.*}} to float + + // CHECK: ret float + return a + b + c; +} diff --git a/clang/test/CodeGen/X86/fp-eval-method.c b/clang/test/CodeGen/X86/fp-eval-method.c new file mode 100644 index 00000000000000..5bfc3701050f5d --- /dev/null +++ b/clang/test/CodeGen/X86/fp-eval-method.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple i386-unknown-netbsd6 -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK + +// RUN: %clang_cc1 -triple i386-unknown-netbsd7 -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK-EXT + +// RUN: %clang_cc1 -triple i386--linux -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK-EXT + +float f(float x, float y) { + // CHECK: define{{.*}} float @f + // CHECK: fadd float + return 2.0f + x + y; +} + +int getEvalMethod() { + // CHECK: ret i32 1 + // CHECK-EXT: ret i32 2 + return __FLT_EVAL_METHOD__; +} diff --git a/clang/test/CodeGen/flt_eval_macro.cpp b/clang/test/CodeGen/flt_eval_macro.cpp new file mode 100644 index 00000000000000..aa7455f0efe0bf --- /dev/null +++ b/clang/test/CodeGen/flt_eval_macro.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 \ +// RUN: -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=CHECK-SRC %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \ +// RUN: | FileCheck -check-prefix=CHECK-SRC %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double \ +// RUN: | FileCheck -check-prefixes=CHECK-DBL %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended \ +// RUN: | FileCheck -check-prefixes=CHECK-EXT-FLT %s + +// RUN: %clang_cc1 -triple powerpc-unknown-aix -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefix=CHECK-DBL-PPC + +// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 \ +// RUN: | FileCheck %s -check-prefix=CHECK-EXT-FLT + +int getFEM() { + // LABEL: define {{.*}}getFEM{{.*}} + return __FLT_EVAL_METHOD__; + // CHECK-SRC: ret {{.*}} 0 + // CHECK-DBL: ret {{.*}} 1 + // CHECK-DBL-PPC: ret {{.*}} 1 + // CHECK-EXT-FLT: ret {{.*}} 2 +} + +float func() { + // LABEL: define {{.*}}@_Z4func{{.*}} + float X = 100.0f; + float Y = -45.3f; + float Z = 393.78f; + float temp; +#if __FLT_EVAL_METHOD__ == 0 + temp = X + Y + Z; +#elif __FLT_EVAL_METHOD__ == 1 + temp = X * Y * Z; +#elif __FLT_EVAL_METHOD__ == 2 + temp = X * Y - Z; +#endif + // CHECK-SRC: load float, float* + // CHECK-SRC: load float, float* + // CHECK-SRC: fadd float + // CHECK-SRC: load float, float* + // CHECK-SRC: fadd float + + // CHECK-DBL: load float, float* + // CHECK-DBL: fpext float + // CHECK-DBL: load float, float* + // CHECK-DBL: fpext float + // CHECK-DBL: fmul double + // CHECK-DBL: load float, float* + // CHECK-DBL: fpext float + // CHECK-DBL: fmul double + // CHECK-DBL: fptrunc double + + // CHECK-EXT-FLT: load float, float* + // CHECK-EXT-FLT: fpext float + // CHECK-EXT-FLT: load float, float* + // CHECK-EXT-FLT: fpext float + // CHECK-EXT-FLT: fmul x86_fp80 + // CHECK-EXT-FLT: load float, float* + // CHECK-EXT-FLT: fpext float + // CHECK-EXT-FLT: fsub x86_fp80 + // CHECK-EXT-FLT: fptrunc x86_fp80 + + // CHECK-DBL-PPC: load float, float* + // CHECK-DBL-PPC: load float, float* + // CHECK-DBL-PPC: fmul float + // CHECK-DBL-PPC: load float, float* + // CHECK-DBL-PPC: fmul float + + return temp; +} diff --git a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp index ef29d24de1dbca..966eaf6053970a 100644 --- a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp +++ b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp @@ -1,7 +1,53 @@ -// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s -// 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 -DEXCEPT=1 \ +// RUN: -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=CHECK-NS %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s \ +// RUN: -check-prefixes=CHECK-DEFAULT,CHECK-CONST-ARGS + +// RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=CHECK-FENV %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point -DNF128 \ +// RUN: -triple %itanium_abi_triple -O3 -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=CHECK-O3 %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \ +// RUN: | FileCheck %s -check-prefixes=CHECK-SOURCE,CHECK-CONST-ARGS + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double \ +// RUN: | FileCheck %s -check-prefixes=CHECK-DOUBLE,CHECK-CONST-ARGS + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended \ +// RUN: -mlong-double-80 | FileCheck %s \ +// RUN: -check-prefixes=CHECK-EXTENDED,CHECK-CONST-ARGS + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \ +// RUN: | FileCheck %s -check-prefix=CHECK-SOURCE + +// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s \ +// RUN: -check-prefix=CHECK-DOUBLE + +// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \ +// RUN: -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 \ +// RUN: | FileCheck %s -check-prefix=CHECK-EXTENDED + +// RUN: %clang_cc1 -triple powerpc-unknown-aix -DNF128 -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefix=CHECK-AIX + +bool f() { + // CHECK: define {{.*}}f{{.*}} + return __FLT_EVAL_METHOD__ < 0 && + __FLT_EVAL_METHOD__ == -1; + // CHECK: ret {{.*}} true +} // Verify float_control(precise, off) enables fast math flags on fp operations. float fp_precise_1(float a, float b, float c) { @@ -229,3 +275,115 @@ float try_lam(float x, unsigned n) { 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 clang fp eval_method(source) + return x - y; + // CHECK: fsub float +} + +float mySubExtended(float x, float y) { +// CHECK: define {{.*}}float {{.*}}mySubExtended{{.*}} +#pragma clang fp eval_method(extended) + return x - y; + // CHECK: fpext float + // CHECK: fpext float + // CHECK: fsub x86_fp80 + // CHECK: fptrunc x86_fp80 {{.*}} to float + // CHECK-AIX: fsub double + // CHECK-AIX: fptrunc double +} + +float mySubDouble(float x, float y) { +// CHECK: define {{.*}}float {{.*}}mySubDouble{{.*}} +#pragma clang fp eval_method(double) + return x - y; + // CHECK: fpext float + // CHECK: fpext float + // CHECK: fsub double + // CHECK: fptrunc double {{.*}} to float +} + +#ifndef NF128 +__float128 mySub128(__float128 x, __float128 y) { + // CHECK: define {{.*}}mySub128{{.*}} + // Expect no fpext since fp128 is already widest + // CHECK: load fp128 + // CHECK-NEXT: load fp128 + // CHECK-NEXT: fsub fp128 + // CHECK-NEXT: ret fp128 + return x - y; +} +#endif + +void mySubfp16(__fp16 *res, __fp16 *x, __fp16 *y) { + // CHECK: define {{.*}}mySubfp16{{.*}} + *res = *x - *y; + // CHECK: load half + // CHECK-NEXT: load half + // CHECK-NEXT: fpext half{{.*}} + // CHECK-NEXT: load half + // CHECK-NEXT: load half + // CHECK-NS: fpext half{{.*}} to float + // CHECK-DEFAULT: fpext half{{.*}} to float + // CHECK-DOUBLE: fpext half{{.*}} to float + // CHECK-EXTENDED: fpext half{{.*}} to float + // CHECK-NEXT: fsub + // CHECK-NEXT: fptrunc {{.*}}to half + // CHECK-NS: fptrunc float {{.*}} to half + // CHECK-DOUBLE: fptrunc float {{.*}} to half + // CHECK-EXTENDED: fptrunc float {{.*}} to half +} + +float Div(float x, float y, float z) { + // CHECK: define{{.*}}float {{.*}}Div{{.*}} + // CHECK-CONST-ARGS: fdiv float + return x / (y / z); +} + +float DivExtended(float x, float y, float z) { +// CHECK: define{{.*}}float {{.*}}DivExtended{{.*}} +#pragma clang fp eval_method(extended) + // CHECK-CONST-ARGS: fdiv x86_fp80 + // CHECK-CONST-ARGS: fptrunc x86_fp80 + return x / (y / z); +} + +float DivDouble(float x, float y, float z) { +// CHECK: define{{.*}}float {{.*}}DivDouble{{.*}} +#pragma clang fp eval_method(double) + // CHECK-CONST-ARGS: fdiv double + // CHECK-CONST-ARGS: fptrunc double + return x / (y / z); +} + +float DivSource(float x, float y, float z) { +// CHECK: define{{.*}}float {{.*}}DivSource{{.*}} +#pragma clang fp eval_method(source) + // CHECK-CONST-ARGS: fdiv float + return x / (y / z); +} + +int main() { + float f = Div(4.2f, 1.0f, 3.0f); + float fextended = DivExtended(4.2f, 1.0f, 3.0f); + float fdouble = DivDouble(4.2f, 1.0f, 3.0f); + float fsource = DivSource(4.2f, 1.0f, 3.0f); + // CHECK: store float +} diff --git a/clang/test/Preprocessor/flt_eval_macro.cpp b/clang/test/Preprocessor/flt_eval_macro.cpp new file mode 100644 index 00000000000000..47f2592e261bd0 --- /dev/null +++ b/clang/test/Preprocessor/flt_eval_macro.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -E -dM %s -o - | FileCheck %s -strict-whitespace + +#ifdef __FLT_EVAL_METHOD__ +#if __FLT_EVAL_METHOD__ == 3 +#define __GLIBC_FLT_EVAL_METHOD 2 +#else +#define __GLIBC_FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +#endif +#elif defined __x86_64__ +#define __GLIBC_FLT_EVAL_METHOD 0 +#else +#define __GLIBC_FLT_EVAL_METHOD 2 +#endif + +#if __GLIBC_FLT_EVAL_METHOD == 0 || __GLIBC_FLT_EVAL_METHOD == 16 +#define Name "One" +#elif __GLIBC_FLT_EVAL_METHOD == 1 +#define Name "Two" +#elif __GLIBC_FLT_EVAL_METHOD == 2 +#define Name "Unset on command line" +#elif __GLIBC_FLT_EVAL_METHOD == 32 +#define Name "Four" +#elif __GLIBC_FLT_EVAL_METHOD == 33 +#define Name "Five" +#elif __GLIBC_FLT_EVAL_METHOD == 64 +#define Name "Six" +#elif __GLIBC_FLT_EVAL_METHOD == 65 +#define Name "Seven" +#elif __GLIBC_FLT_EVAL_METHOD == 128 +#define Name "Eight" +#elif __GLIBC_FLT_EVAL_METHOD == 129 +#define Name "Nine" +#else +#error "Unknown __GLIBC_FLT_EVAL_METHOD" +#endif + +int foo() { + // CHECK: #define Name "Unset on command line" + return Name; +} + +#if __FLT_EVAL_METHOD__ == 3 +#define Val "val0" +#endif + +#pragma fp eval_method(double) + +#if __FLT_EVAL_METHOD__ == 0 +#define Val "val1" +#elif __FLT_EVAL_METHOD__ == 1 +#define Val "val2" +#elif __FLT_EVAL_METHOD__ == 2 +#define Val "val3" +#endif + +int goo() { + // CHECK: #define Val "val0" + return Name; +} diff --git a/clang/test/Preprocessor/init-aarch64.c b/clang/test/Preprocessor/init-aarch64.c index f6809d8d9b48ff..66cab8b1f8d040 100644 --- a/clang/test/Preprocessor/init-aarch64.c +++ b/clang/test/Preprocessor/init-aarch64.c @@ -93,7 +93,6 @@ // AARCH64-NEXT: #define __FLT_DENORM_MIN__ 1.40129846e-45F // AARCH64-NEXT: #define __FLT_DIG__ 6 // AARCH64-NEXT: #define __FLT_EPSILON__ 1.19209290e-7F -// AARCH64-NEXT: #define __FLT_EVAL_METHOD__ 0 // AARCH64-NEXT: #define __FLT_HAS_DENORM__ 1 // AARCH64-NEXT: #define __FLT_HAS_INFINITY__ 1 // AARCH64-NEXT: #define __FLT_HAS_QUIET_NAN__ 1 @@ -388,7 +387,6 @@ // AARCH64-DARWIN: #define __FLT_DENORM_MIN__ 1.40129846e-45F // AARCH64-DARWIN: #define __FLT_DIG__ 6 // AARCH64-DARWIN: #define __FLT_EPSILON__ 1.19209290e-7F -// AARCH64-DARWIN: #define __FLT_EVAL_METHOD__ 0 // AARCH64-DARWIN: #define __FLT_HAS_DENORM__ 1 // AARCH64-DARWIN: #define __FLT_HAS_INFINITY__ 1 // AARCH64-DARWIN: #define __FLT_HAS_QUIET_NAN__ 1 @@ -604,7 +602,6 @@ // AARCH64-MSVC: #define __FLT_DENORM_MIN__ 1.40129846e-45F // AARCH64-MSVC: #define __FLT_DIG__ 6 // AARCH64-MSVC: #define __FLT_EPSILON__ 1.19209290e-7F -// AARCH64-MSVC: #define __FLT_EVAL_METHOD__ 0 // AARCH64-MSVC: #define __FLT_HAS_DENORM__ 1 // AARCH64-MSVC: #define __FLT_HAS_INFINITY__ 1 // AARCH64-MSVC: #define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init-arm.c b/clang/test/Preprocessor/init-arm.c index 32eb2c513f8b01..2d1503c18560ed 100644 --- a/clang/test/Preprocessor/init-arm.c +++ b/clang/test/Preprocessor/init-arm.c @@ -35,7 +35,6 @@ // ARM:#define __FLT_DENORM_MIN__ 1.40129846e-45F // ARM:#define __FLT_DIG__ 6 // ARM:#define __FLT_EPSILON__ 1.19209290e-7F -// ARM:#define __FLT_EVAL_METHOD__ 0 // ARM:#define __FLT_HAS_DENORM__ 1 // ARM:#define __FLT_HAS_INFINITY__ 1 // ARM:#define __FLT_HAS_QUIET_NAN__ 1 @@ -235,7 +234,6 @@ // ARM-BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F // ARM-BE:#define __FLT_DIG__ 6 // ARM-BE:#define __FLT_EPSILON__ 1.19209290e-7F -// ARM-BE:#define __FLT_EVAL_METHOD__ 0 // ARM-BE:#define __FLT_HAS_DENORM__ 1 // ARM-BE:#define __FLT_HAS_INFINITY__ 1 // ARM-BE:#define __FLT_HAS_QUIET_NAN__ 1 @@ -428,7 +426,6 @@ // ARMEABISOFTFP:#define __FLT_DENORM_MIN__ 1.40129846e-45F // ARMEABISOFTFP:#define __FLT_DIG__ 6 // ARMEABISOFTFP:#define __FLT_EPSILON__ 1.19209290e-7F -// ARMEABISOFTFP:#define __FLT_EVAL_METHOD__ 0 // ARMEABISOFTFP:#define __FLT_HAS_DENORM__ 1 // ARMEABISOFTFP:#define __FLT_HAS_INFINITY__ 1 // ARMEABISOFTFP:#define __FLT_HAS_QUIET_NAN__ 1 @@ -623,7 +620,6 @@ // ARMEABIHARDFP:#define __FLT_DENORM_MIN__ 1.40129846e-45F // ARMEABIHARDFP:#define __FLT_DIG__ 6 // ARMEABIHARDFP:#define __FLT_EPSILON__ 1.19209290e-7F -// ARMEABIHARDFP:#define __FLT_EVAL_METHOD__ 0 // ARMEABIHARDFP:#define __FLT_HAS_DENORM__ 1 // ARMEABIHARDFP:#define __FLT_HAS_INFINITY__ 1 // ARMEABIHARDFP:#define __FLT_HAS_QUIET_NAN__ 1 @@ -821,7 +817,6 @@ // ARM-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F // ARM-NETBSD:#define __FLT_DIG__ 6 // ARM-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F -// ARM-NETBSD:#define __FLT_EVAL_METHOD__ 0 // ARM-NETBSD:#define __FLT_HAS_DENORM__ 1 // ARM-NETBSD:#define __FLT_HAS_INFINITY__ 1 // ARM-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init-mips.c b/clang/test/Preprocessor/init-mips.c index d76396aa35c91f..a07cee64e6848d 100644 --- a/clang/test/Preprocessor/init-mips.c +++ b/clang/test/Preprocessor/init-mips.c @@ -37,7 +37,6 @@ // MIPS32BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F // MIPS32BE:#define __FLT_DIG__ 6 // MIPS32BE:#define __FLT_EPSILON__ 1.19209290e-7F -// MIPS32BE:#define __FLT_EVAL_METHOD__ 0 // MIPS32BE:#define __FLT_HAS_DENORM__ 1 // MIPS32BE:#define __FLT_HAS_INFINITY__ 1 // MIPS32BE:#define __FLT_HAS_QUIET_NAN__ 1 @@ -247,7 +246,6 @@ // MIPS32EL:#define __FLT_DENORM_MIN__ 1.40129846e-45F // MIPS32EL:#define __FLT_DIG__ 6 // MIPS32EL:#define __FLT_EPSILON__ 1.19209290e-7F -// MIPS32EL:#define __FLT_EVAL_METHOD__ 0 // MIPS32EL:#define __FLT_HAS_DENORM__ 1 // MIPS32EL:#define __FLT_HAS_INFINITY__ 1 // MIPS32EL:#define __FLT_HAS_QUIET_NAN__ 1 @@ -467,7 +465,6 @@ // MIPSN32BE: #define __FLT_DENORM_MIN__ 1.40129846e-45F // MIPSN32BE: #define __FLT_DIG__ 6 // MIPSN32BE: #define __FLT_EPSILON__ 1.19209290e-7F -// MIPSN32BE: #define __FLT_EVAL_METHOD__ 0 // MIPSN32BE: #define __FLT_HAS_DENORM__ 1 // MIPSN32BE: #define __FLT_HAS_INFINITY__ 1 // MIPSN32BE: #define __FLT_HAS_QUIET_NAN__ 1 @@ -774,7 +771,6 @@ // MIPSN32EL: #define __FLT_DENORM_MIN__ 1.40129846e-45F // MIPSN32EL: #define __FLT_DIG__ 6 // MIPSN32EL: #define __FLT_EPSILON__ 1.19209290e-7F -// MIPSN32EL: #define __FLT_EVAL_METHOD__ 0 // MIPSN32EL: #define __FLT_HAS_DENORM__ 1 // MIPSN32EL: #define __FLT_HAS_INFINITY__ 1 // MIPSN32EL: #define __FLT_HAS_QUIET_NAN__ 1 @@ -1074,7 +1070,6 @@ // MIPS64BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F // MIPS64BE:#define __FLT_DIG__ 6 // MIPS64BE:#define __FLT_EPSILON__ 1.19209290e-7F -// MIPS64BE:#define __FLT_EVAL_METHOD__ 0 // MIPS64BE:#define __FLT_HAS_DENORM__ 1 // MIPS64BE:#define __FLT_HAS_INFINITY__ 1 // MIPS64BE:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1284,7 +1279,6 @@ // MIPS64EL:#define __FLT_DENORM_MIN__ 1.40129846e-45F // MIPS64EL:#define __FLT_DIG__ 6 // MIPS64EL:#define __FLT_EPSILON__ 1.19209290e-7F -// MIPS64EL:#define __FLT_EVAL_METHOD__ 0 // MIPS64EL:#define __FLT_HAS_DENORM__ 1 // MIPS64EL:#define __FLT_HAS_INFINITY__ 1 // MIPS64EL:#define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init-ppc.c b/clang/test/Preprocessor/init-ppc.c index 611b16dfb8f7ef..45c8a5e53ad4f4 100644 --- a/clang/test/Preprocessor/init-ppc.c +++ b/clang/test/Preprocessor/init-ppc.c @@ -30,7 +30,6 @@ // PPC603E:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC603E:#define __FLT_DIG__ 6 // PPC603E:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC603E:#define __FLT_EVAL_METHOD__ 0 // PPC603E:#define __FLT_HAS_DENORM__ 1 // PPC603E:#define __FLT_HAS_INFINITY__ 1 // PPC603E:#define __FLT_HAS_QUIET_NAN__ 1 @@ -224,7 +223,6 @@ // PPC:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC:#define __FLT_DIG__ 6 // PPC:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC:#define __FLT_EVAL_METHOD__ 0 // PPC:#define __FLT_HAS_DENORM__ 1 // PPC:#define __FLT_HAS_INFINITY__ 1 // PPC:#define __FLT_HAS_QUIET_NAN__ 1 @@ -425,7 +423,6 @@ // PPC-AIX:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC-AIX:#define __FLT_DIG__ 6 // PPC-AIX:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC-AIX:#define __FLT_EVAL_METHOD__ 1 // PPC-AIX:#define __FLT_HAS_DENORM__ 1 // PPC-AIX:#define __FLT_HAS_INFINITY__ 1 // PPC-AIX:#define __FLT_HAS_QUIET_NAN__ 1 @@ -798,7 +795,6 @@ // PPC-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC-LINUX:#define __FLT_DIG__ 6 // PPC-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC-LINUX:#define __FLT_EVAL_METHOD__ 0 // PPC-LINUX:#define __FLT_HAS_DENORM__ 1 // PPC-LINUX:#define __FLT_HAS_INFINITY__ 1 // PPC-LINUX:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1006,7 +1002,6 @@ // PPC-DARWIN:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC-DARWIN:#define __FLT_DIG__ 6 // PPC-DARWIN:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC-DARWIN:#define __FLT_EVAL_METHOD__ 0 // PPC-DARWIN:#define __FLT_HAS_DENORM__ 1 // PPC-DARWIN:#define __FLT_HAS_INFINITY__ 1 // PPC-DARWIN:#define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init-ppc64.c b/clang/test/Preprocessor/init-ppc64.c index 7a9525228c3b62..f0ccd1638c04df 100644 --- a/clang/test/Preprocessor/init-ppc64.c +++ b/clang/test/Preprocessor/init-ppc64.c @@ -35,7 +35,6 @@ // PPC64:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC64:#define __FLT_DIG__ 6 // PPC64:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC64:#define __FLT_EVAL_METHOD__ 0 // PPC64:#define __FLT_HAS_DENORM__ 1 // PPC64:#define __FLT_HAS_INFINITY__ 1 // PPC64:#define __FLT_HAS_QUIET_NAN__ 1 @@ -240,7 +239,6 @@ // PPC64LE:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC64LE:#define __FLT_DIG__ 6 // PPC64LE:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC64LE:#define __FLT_EVAL_METHOD__ 0 // PPC64LE:#define __FLT_HAS_DENORM__ 1 // PPC64LE:#define __FLT_HAS_INFINITY__ 1 // PPC64LE:#define __FLT_HAS_QUIET_NAN__ 1 @@ -703,7 +701,6 @@ // PPC64-AIX:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC64-AIX:#define __FLT_DIG__ 6 // PPC64-AIX:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC64-AIX:#define __FLT_EVAL_METHOD__ 1 // PPC64-AIX:#define __FLT_HAS_DENORM__ 1 // PPC64-AIX:#define __FLT_HAS_INFINITY__ 1 // PPC64-AIX:#define __FLT_HAS_QUIET_NAN__ 1 @@ -902,7 +899,6 @@ // PPC64-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PPC64-LINUX:#define __FLT_DIG__ 6 // PPC64-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F -// PPC64-LINUX:#define __FLT_EVAL_METHOD__ 0 // PPC64-LINUX:#define __FLT_HAS_DENORM__ 1 // PPC64-LINUX:#define __FLT_HAS_INFINITY__ 1 // PPC64-LINUX:#define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init-s390x.c b/clang/test/Preprocessor/init-s390x.c index b0e45b5348ce95..6c646527f50f74 100644 --- a/clang/test/Preprocessor/init-s390x.c +++ b/clang/test/Preprocessor/init-s390x.c @@ -23,7 +23,6 @@ // S390X:#define __FLT_DENORM_MIN__ 1.40129846e-45F // S390X:#define __FLT_DIG__ 6 // S390X:#define __FLT_EPSILON__ 1.19209290e-7F -// S390X:#define __FLT_EVAL_METHOD__ 0 // S390X:#define __FLT_HAS_DENORM__ 1 // S390X:#define __FLT_HAS_INFINITY__ 1 // S390X:#define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init-v7k-compat.c b/clang/test/Preprocessor/init-v7k-compat.c index 482c7ad6ff6878..ff5d4bbdea53ad 100644 --- a/clang/test/Preprocessor/init-v7k-compat.c +++ b/clang/test/Preprocessor/init-v7k-compat.c @@ -28,7 +28,6 @@ // CHECK: #define __FLT_DENORM_MIN__ 1.40129846e-45F // CHECK: #define __FLT_DIG__ 6 // CHECK: #define __FLT_EPSILON__ 1.19209290e-7F -// CHECK: #define __FLT_EVAL_METHOD__ 0 // CHECK: #define __FLT_HAS_DENORM__ 1 // CHECK: #define __FLT_HAS_INFINITY__ 1 // CHECK: #define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init-x86.c b/clang/test/Preprocessor/init-x86.c index 527cd395088898..aa2e05ec807c7b 100644 --- a/clang/test/Preprocessor/init-x86.c +++ b/clang/test/Preprocessor/init-x86.c @@ -24,7 +24,6 @@ // I386:#define __FLT_DENORM_MIN__ 1.40129846e-45F // I386:#define __FLT_DIG__ 6 // I386:#define __FLT_EPSILON__ 1.19209290e-7F -// I386:#define __FLT_EVAL_METHOD__ 2 // I386:#define __FLT_HAS_DENORM__ 1 // I386:#define __FLT_HAS_INFINITY__ 1 // I386:#define __FLT_HAS_QUIET_NAN__ 1 @@ -213,7 +212,6 @@ // I386-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F // I386-LINUX:#define __FLT_DIG__ 6 // I386-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F -// I386-LINUX:#define __FLT_EVAL_METHOD__ 0 // I386-LINUX:#define __FLT_HAS_DENORM__ 1 // I386-LINUX:#define __FLT_HAS_INFINITY__ 1 // I386-LINUX:#define __FLT_HAS_QUIET_NAN__ 1 @@ -416,7 +414,6 @@ // I386-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F // I386-NETBSD:#define __FLT_DIG__ 6 // I386-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F -// I386-NETBSD:#define __FLT_EVAL_METHOD__ 2 // I386-NETBSD:#define __FLT_HAS_DENORM__ 1 // I386-NETBSD:#define __FLT_HAS_INFINITY__ 1 // I386-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1 @@ -590,13 +587,6 @@ // I386-NETBSD:#define __i386__ 1 // I386-NETBSD:#define i386 1 -// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd -target-feature +sse2 < /dev/null | FileCheck -match-full-lines -check-prefix I386-NETBSD-SSE %s -// I386-NETBSD-SSE:#define __FLT_EVAL_METHOD__ 0 -// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd6 < /dev/null | FileCheck -match-full-lines -check-prefix I386-NETBSD6 %s -// I386-NETBSD6:#define __FLT_EVAL_METHOD__ 1 -// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd6 -target-feature +sse2 < /dev/null | FileCheck -match-full-lines -check-prefix I386-NETBSD6-SSE %s -// I386-NETBSD6-SSE:#define __FLT_EVAL_METHOD__ 1 - // RUN: %clang_cc1 -E -dM -triple=i686-pc-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix I386-DECLSPEC %s // RUN: %clang_cc1 -E -dM -fms-extensions -triple=i686-pc-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix I386-DECLSPEC %s // RUN: %clang_cc1 -E -dM -triple=i686-unknown-cygwin < /dev/null | FileCheck -match-full-lines -check-prefix I386-DECLSPEC %s @@ -631,7 +621,6 @@ // X86_64:#define __FLT_DENORM_MIN__ 1.40129846e-45F // X86_64:#define __FLT_DIG__ 6 // X86_64:#define __FLT_EPSILON__ 1.19209290e-7F -// X86_64:#define __FLT_EVAL_METHOD__ 0 // X86_64:#define __FLT_HAS_DENORM__ 1 // X86_64:#define __FLT_HAS_INFINITY__ 1 // X86_64:#define __FLT_HAS_QUIET_NAN__ 1 @@ -839,7 +828,6 @@ // X32:#define __FLT_DENORM_MIN__ 1.40129846e-45F // X32:#define __FLT_DIG__ 6 // X32:#define __FLT_EPSILON__ 1.19209290e-7F -// X32:#define __FLT_EVAL_METHOD__ 0 // X32:#define __FLT_HAS_DENORM__ 1 // X32:#define __FLT_HAS_INFINITY__ 1 // X32:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1046,7 +1034,6 @@ // X86_64-CLOUDABI:#define __FLT_DENORM_MIN__ 1.40129846e-45F // X86_64-CLOUDABI:#define __FLT_DIG__ 6 // X86_64-CLOUDABI:#define __FLT_EPSILON__ 1.19209290e-7F -// X86_64-CLOUDABI:#define __FLT_EVAL_METHOD__ 0 // X86_64-CLOUDABI:#define __FLT_HAS_DENORM__ 1 // X86_64-CLOUDABI:#define __FLT_HAS_INFINITY__ 1 // X86_64-CLOUDABI:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1341,7 +1328,6 @@ // X86_64-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F // X86_64-LINUX:#define __FLT_DIG__ 6 // X86_64-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F -// X86_64-LINUX:#define __FLT_EVAL_METHOD__ 0 // X86_64-LINUX:#define __FLT_HAS_DENORM__ 1 // X86_64-LINUX:#define __FLT_HAS_INFINITY__ 1 // X86_64-LINUX:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1554,7 +1540,6 @@ // X86_64-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F // X86_64-NETBSD:#define __FLT_DIG__ 6 // X86_64-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F -// X86_64-NETBSD:#define __FLT_EVAL_METHOD__ 0 // X86_64-NETBSD:#define __FLT_HAS_DENORM__ 1 // X86_64-NETBSD:#define __FLT_HAS_INFINITY__ 1 // X86_64-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index dd645bf6003ced..a08e503570723c 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -325,7 +325,6 @@ // MSP430:#define __FLT_DENORM_MIN__ 1.40129846e-45F // MSP430:#define __FLT_DIG__ 6 // MSP430:#define __FLT_EPSILON__ 1.19209290e-7F -// MSP430:#define __FLT_EVAL_METHOD__ 0 // MSP430:#define __FLT_HAS_DENORM__ 1 // MSP430:#define __FLT_HAS_INFINITY__ 1 // MSP430:#define __FLT_HAS_QUIET_NAN__ 1 @@ -513,7 +512,6 @@ // NVPTX32:#define __FLT_DENORM_MIN__ 1.40129846e-45F // NVPTX32:#define __FLT_DIG__ 6 // NVPTX32:#define __FLT_EPSILON__ 1.19209290e-7F -// NVPTX32:#define __FLT_EVAL_METHOD__ 0 // NVPTX32:#define __FLT_HAS_DENORM__ 1 // NVPTX32:#define __FLT_HAS_INFINITY__ 1 // NVPTX32:#define __FLT_HAS_QUIET_NAN__ 1 @@ -702,7 +700,6 @@ // NVPTX64:#define __FLT_DENORM_MIN__ 1.40129846e-45F // NVPTX64:#define __FLT_DIG__ 6 // NVPTX64:#define __FLT_EPSILON__ 1.19209290e-7F -// NVPTX64:#define __FLT_EVAL_METHOD__ 0 // NVPTX64:#define __FLT_HAS_DENORM__ 1 // NVPTX64:#define __FLT_HAS_INFINITY__ 1 // NVPTX64:#define __FLT_HAS_QUIET_NAN__ 1 @@ -906,7 +903,6 @@ // SPARC:#define __FLT_DENORM_MIN__ 1.40129846e-45F // SPARC:#define __FLT_DIG__ 6 // SPARC:#define __FLT_EPSILON__ 1.19209290e-7F -// SPARC:#define __FLT_EVAL_METHOD__ 0 // SPARC:#define __FLT_HAS_DENORM__ 1 // SPARC:#define __FLT_HAS_INFINITY__ 1 // SPARC:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1107,7 +1103,6 @@ // TCE:#define __FLT_DENORM_MIN__ 1.40129846e-45F // TCE:#define __FLT_DIG__ 6 // TCE:#define __FLT_EPSILON__ 1.19209290e-7F -// TCE:#define __FLT_EVAL_METHOD__ 0 // TCE:#define __FLT_HAS_DENORM__ 1 // TCE:#define __FLT_HAS_INFINITY__ 1 // TCE:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1274,7 +1269,6 @@ // PS4:#define __FLT_DENORM_MIN__ 1.40129846e-45F // PS4:#define __FLT_DIG__ 6 // PS4:#define __FLT_EPSILON__ 1.19209290e-7F -// PS4:#define __FLT_EVAL_METHOD__ 0 // PS4:#define __FLT_HAS_DENORM__ 1 // PS4:#define __FLT_HAS_INFINITY__ 1 // PS4:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1576,7 +1570,6 @@ // WEBASSEMBLY-NEXT:#define __FLT_DENORM_MIN__ 1.40129846e-45F // WEBASSEMBLY-NEXT:#define __FLT_DIG__ 6 // WEBASSEMBLY-NEXT:#define __FLT_EPSILON__ 1.19209290e-7F -// WEBASSEMBLY-NEXT:#define __FLT_EVAL_METHOD__ 0 // WEBASSEMBLY-NEXT:#define __FLT_HAS_DENORM__ 1 // WEBASSEMBLY-NEXT:#define __FLT_HAS_INFINITY__ 1 // WEBASSEMBLY-NEXT:#define __FLT_HAS_QUIET_NAN__ 1 @@ -1946,7 +1939,6 @@ // AVR:#define __FLT_DENORM_MIN__ 1.40129846e-45F // AVR:#define __FLT_DIG__ 6 // AVR:#define __FLT_EPSILON__ 1.19209290e-7F -// AVR:#define __FLT_EVAL_METHOD__ 0 // AVR:#define __FLT_HAS_DENORM__ 1 // AVR:#define __FLT_HAS_INFINITY__ 1 // AVR:#define __FLT_HAS_QUIET_NAN__ 1 @@ -2083,7 +2075,6 @@ // AVR:#define __WCHAR_TYPE__ int // AVR:#define __WINT_TYPE__ int - // RUN: %clang_cc1 -E -dM -ffreestanding \ // RUN: -triple i686-windows-msvc -fms-compatibility -x c++ < /dev/null \ // RUN: | FileCheck -match-full-lines -check-prefix MSVC-X32 %s @@ -2229,7 +2220,6 @@ // RISCV32: #define __FLT_DENORM_MIN__ 1.40129846e-45F // RISCV32: #define __FLT_DIG__ 6 // RISCV32: #define __FLT_EPSILON__ 1.19209290e-7F -// RISCV32: #define __FLT_EVAL_METHOD__ 0 // RISCV32: #define __FLT_HAS_DENORM__ 1 // RISCV32: #define __FLT_HAS_INFINITY__ 1 // RISCV32: #define __FLT_HAS_QUIET_NAN__ 1 @@ -2437,7 +2427,6 @@ // RISCV64: #define __FLT_DENORM_MIN__ 1.40129846e-45F // RISCV64: #define __FLT_DIG__ 6 // RISCV64: #define __FLT_EPSILON__ 1.19209290e-7F -// RISCV64: #define __FLT_EVAL_METHOD__ 0 // RISCV64: #define __FLT_HAS_DENORM__ 1 // RISCV64: #define __FLT_HAS_INFINITY__ 1 // RISCV64: #define __FLT_HAS_QUIET_NAN__ 1 diff --git a/clang/test/Sema/fp-eval-pragma.cpp b/clang/test/Sema/fp-eval-pragma.cpp new file mode 100644 index 00000000000000..42d88fd438e81e --- /dev/null +++ b/clang/test/Sema/fp-eval-pragma.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify %s +// +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify %s \ +// RUN: -ffp-eval-method=source +// +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify %s \ +// RUN: -ffp-eval-method=double + +extern "C" int printf(const char *, ...); + +void foo1() { + printf("FP: %d\n", __FLT_EVAL_METHOD__); +} + +void apply_pragma() { + // expected-note@+1{{#pragma entered here}} +#pragma clang fp eval_method(double) + // expected-error@+1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}} + printf("FP: %d\n", __FLT_EVAL_METHOD__); +} + +int foo2() { + apply_pragma(); + return 0; +} + +void foo() { + auto a = __FLT_EVAL_METHOD__; + { + // expected-note@+1{{#pragma entered here}} +#pragma clang fp eval_method(double) + // expected-error@+1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}} + auto b = __FLT_EVAL_METHOD__; + } + auto c = __FLT_EVAL_METHOD__; +} + +void func() { + { + { +#pragma clang fp eval_method(source) + } + int i = __FLT_EVAL_METHOD__; // ok, not in a scope changed by the pragma + } + { + // expected-note@+1{{#pragma entered here}} +#pragma clang fp eval_method(source) + // expected-error@+1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}} + int i = __FLT_EVAL_METHOD__; + } +} + +float G; + +int f(float x, float y, float z) { + G = x * y + z; + return __FLT_EVAL_METHOD__; +} + +int foo(int flag, float x, float y, float z) { + if (flag) { + // expected-note@+1{{#pragma entered here}} +#pragma clang fp eval_method(double) + G = x + y + z; + // expected-error@+1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}} + return __FLT_EVAL_METHOD__; + } else { + // expected-note@+1{{#pragma entered here}} +#pragma clang fp eval_method(extended) + G = x + y + z; + // expected-error@+1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}} + return __FLT_EVAL_METHOD__; + } +} + +#if __FLT_EVAL_METHOD__ == 1 +#endif +#pragma clang fp eval_method(source) + +// expected-note@+1{{#pragma entered here}} +#pragma clang fp eval_method(double) +// expected-error@+1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}} +#if __FLT_EVAL_METHOD__ == 1 +#endif diff --git a/clang/test/Sema/x86-eval-method.c b/clang/test/Sema/x86-eval-method.c new file mode 100644 index 00000000000000..90f2fefc511c0d --- /dev/null +++ b/clang/test/Sema/x86-eval-method.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \ +// RUN: -emit-llvm -ffp-eval-method=source -o - -verify=warn %s +// +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple i386-pc-windows -target-cpu pentium4 \ +// RUN: -emit-llvm -ffp-eval-method=source -o - -verify=no-warn %s + +// no-warn-no-diagnostics + +float add1(float a, float b, float c) { + return a + b + c; +} // warn-warning{{Setting FPEvalMethod to source on a 32bit target, with no SSE is not supported.}} + +float add2(float a, float b, float c) { +#pragma clang fp eval_method(source) + return a + b + c; +} // warn-warning{{Setting FPEvalMethod to source on a 32bit target, with no SSE is not supported.}} diff --git a/clang/test/Sema/x86_64-eval-method.c b/clang/test/Sema/x86_64-eval-method.c new file mode 100644 index 00000000000000..728423dd1b65b2 --- /dev/null +++ b/clang/test/Sema/x86_64-eval-method.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -target-feature -sse -emit-llvm -o - -verify %s +// +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify=no-warn %s + +// no-warn-no-diagnostics + +float add2(float a, float b, float c) { +#pragma clang fp eval_method(source) + return a + b + c; +} // expected-warning{{Setting FPEvalMethod to source on a 32bit target, with no SSE is not supported.}}