Skip to content

Commit 66ddac2

Browse files
author
Melanie Blower
committed
[CLANG][PATCH][FPEnv] Add support for option -ffp-eval-method and extend #pragma float_control similarly
The Intel compiler ICC 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 extends pragma float_control syntax, and also adds support for a new floating point option "-ffp-eval-method=(source|double|extended)". source: intermediate results use source precision double: intermediate results use double precision extended: intermediate results use extended precision Reviewed By: Aaron Ballman Differential Revision: https://reviews.llvm.org/D93769
1 parent 23326b9 commit 66ddac2

31 files changed

+303
-88
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3554,7 +3554,7 @@ specification, a stack is supported so that the ``pragma float_control``
35543554
settings can be pushed or popped.
35553555
35563556
When ``pragma float_control(precise, on)`` is enabled, the section of code
3557-
governed by the pragma uses precise floating point semantics, effectively
3557+
governed by the pragma uses precise floating-point semantics, effectively
35583558
``-ffast-math`` is disabled and ``-ffp-contract=on``
35593559
(fused multiply add) is enabled.
35603560
@@ -3565,8 +3565,29 @@ when ``pragma float_control(precise, off)`` is enabled, the section of code
35653565
governed by the pragma behaves as though the command-line option
35663566
``-ffp-exception-behavior=ignore`` is enabled.
35673567
3568+
When ``pragma float_control(source, on)`` is enabled, the section of code governed
3569+
by the pragma behaves as though the command-line option
3570+
``-ffp-eval-method=source`` is enabled. Note: The default
3571+
floating-point evaluation method is target-specific, typically ``source``.
3572+
3573+
When ``pragma float_control(double, on)`` is enabled, the section of code governed
3574+
by the pragma behaves as though the command-line option
3575+
``-ffp-eval-method=double`` is enabled.
3576+
3577+
When ``pragma float_control(extended, on)`` is enabled, the section of code governed
3578+
by the pragma behaves as though the command-line option
3579+
``-ffp-eval-method=extended`` is enabled.
3580+
3581+
When ``pragma float_control(source, off)`` or
3582+
``pragma float_control(double, off)`` or
3583+
``pragma float_control(extended, off)`` is enabled,
3584+
the section of code governed
3585+
by the pragma behaves as though the command-line option
3586+
``-ffp-eval-method=source`` is enabled, returning floating-point evaluation
3587+
method to the default setting.
3588+
35683589
The full syntax this pragma supports is
3569-
``float_control(except|precise, on|off [, push])`` and
3590+
``float_control(except|precise|source|double|extended, on|off [, push])`` and
35703591
``float_control(push|pop)``.
35713592
The ``push`` and ``pop`` forms, including using ``push`` as the optional
35723593
third argument, can only occur at file scope.

clang/docs/UsersManual.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,17 @@ Note that floating-point operations performed as part of constant initialization
15201520
* ``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.
15211521
* ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code.
15221522

1523+
.. option:: -ffp-eval-method=<value>
1524+
1525+
Specify the floating-point evaluation method.
1526+
1527+
Valid values are: ``source``, ``double``, and ``extended``.
1528+
The default value is target-specific, typically ``source``. Details:
1529+
1530+
* ``source`` The compiler uses the floating-point type declared in the source program as the evaluation method.
1531+
* ``double`` The compiler uses ``double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``double``.
1532+
* ``extended`` The compiler uses ``long double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``long double``.
1533+
15231534
.. option:: -f[no-]protect-parens:
15241535

15251536
This option pertains to floating-point types, complex types with

clang/include/clang/Basic/FPOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ OPTION(NoHonorInfs, bool, 1, NoHonorNaNs)
2323
OPTION(NoSignedZero, bool, 1, NoHonorInfs)
2424
OPTION(AllowReciprocal, bool, 1, NoSignedZero)
2525
OPTION(AllowApproxFunc, bool, 1, AllowReciprocal)
26+
OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
2627
#undef OPTION

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contracti
296296
COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating point")
297297
BENIGN_ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type")
298298
BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type")
299+
BENIGN_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_TargetDefault, "FP type used for floating point arithmetic")
299300
LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
300301
LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
301302
LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")

clang/include/clang/Basic/LangOptions.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,19 @@ class LangOptions : public LangOptionsBase {
233233
/// Possible exception handling behavior.
234234
enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm };
235235

236+
/// Possible float expression evaluation method choices.
237+
enum FPEvalMethodKind {
238+
/// Use the declared type for fp arithmetic.
239+
FEM_Source,
240+
/// Use the type double for fp arithmetic.
241+
FEM_Double,
242+
/// Use extended type for fp arithmetic.
243+
FEM_Extended,
244+
/// Use the default float eval method specified by Target:
245+
// most targets are defined with evaluation method FEM_Source.
246+
FEM_TargetDefault
247+
};
248+
236249
enum class LaxVectorConversionKind {
237250
/// Permit no implicit vector bitcasts.
238251
None,
@@ -524,6 +537,7 @@ class FPOptions {
524537
setAllowFEnvAccess(true);
525538
else
526539
setAllowFEnvAccess(LangOptions::FPM_Off);
540+
setFPEvalMethod(LO.getFPEvalMethod());
527541
}
528542

529543
bool allowFPContractWithinStatement() const {

clang/include/clang/Basic/PragmaKinds.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ enum PragmaFloatControlKind {
3232
PFC_Except, // #pragma float_control(except [,on])
3333
PFC_NoExcept, // #pragma float_control(except, off)
3434
PFC_Push, // #pragma float_control(push)
35-
PFC_Pop // #pragma float_control(pop)
35+
PFC_Pop, // #pragma float_control(pop)
36+
PFC_Source, // #pragma float_control(source, {on|off} [,push])
37+
PFC_Double, // #pragma float_control(double, {on|off} [,push])
38+
PFC_Extended, // #pragma float_control(extended, {on|off} [,push])
3639
};
3740
}
3841

clang/include/clang/Basic/TargetInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,8 @@ class TargetInfo : public virtual TransferrableTargetInfo,
687687
}
688688

689689
/// Return the value for the C99 FLT_EVAL_METHOD macro.
690-
virtual unsigned getFloatEvalMethod() const { return 0; }
690+
// Note: implementation defined values may be negative.
691+
virtual int getFPEvalMethod() const { return 0; }
691692

692693
// getLargeArrayMinWidth/Align - Return the minimum array size that is
693694
// 'large' and its alignment.

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,11 @@ def : Flag<["-"], "fextended-identifiers">, Group<clang_ignored_f_Group>;
14341434
def : Flag<["-"], "fno-extended-identifiers">, Group<f_Group>, Flags<[Unsupported]>;
14351435
def fhosted : Flag<["-"], "fhosted">, Group<f_Group>;
14361436
def fdenormal_fp_math_EQ : Joined<["-"], "fdenormal-fp-math=">, Group<f_Group>, Flags<[CC1Option]>;
1437+
def ffp_eval_method_EQ : Joined<["-"], "ffp-eval-method=">, Group<f_Group>, Flags<[CC1Option]>,
1438+
HelpText<"Specifies the evaluation method to use for floating-point arithmetic.">,
1439+
Values<"source,double,extended">, NormalizedValuesScope<"LangOptions">,
1440+
NormalizedValues<["FEM_Source", "FEM_Double", "FEM_Extended"]>,
1441+
MarshallingInfoEnum<LangOpts<"FPEvalMethod">, "FEM_TargetDefault">;
14371442
def ffp_model_EQ : Joined<["-"], "ffp-model=">, Group<f_Group>, Flags<[NoXarchOption]>,
14381443
HelpText<"Controls the semantics of floating-point calculations.">;
14391444
def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group<f_Group>, Flags<[CC1Option]>,

clang/include/clang/Lex/Preprocessor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,17 @@ class Preprocessor {
178178
IdentifierInfo *Ident__is_target_vendor; // __is_target_vendor
179179
IdentifierInfo *Ident__is_target_os; // __is_target_os
180180
IdentifierInfo *Ident__is_target_environment; // __is_target_environment
181+
IdentifierInfo *Ident__FLT_EVAL_METHOD__ = nullptr; // __FLT_EVAL_METHOD__
181182

182183
// Weak, only valid (and set) while InMacroArgs is true.
183184
Token* ArgMacro;
184185

185186
SourceLocation DATELoc, TIMELoc;
186187

188+
// Corresponding to __FLT_EVAL_METHOD__. Initialized from TargetInfo
189+
// or the command line. Implementation-defined values can be negative.
190+
int CurrentFPEvalMethod = 0;
191+
187192
// Next __COUNTER__ value, starts at 0.
188193
unsigned CounterValue = 0;
189194

@@ -1988,6 +1993,8 @@ class Preprocessor {
19881993
}
19891994
unsigned getCounterValue() const { return CounterValue; }
19901995
void setCounterValue(unsigned V) { CounterValue = V; }
1996+
int getCurrentFPEvalMethod() const { return CurrentFPEvalMethod; }
1997+
void setCurrentFPEvalMethod(int V) { CurrentFPEvalMethod = V; }
19911998

19921999
/// Retrieves the module that we're currently building, if any.
19932000
Module *getCurrentModule();

clang/include/clang/Lex/PreprocessorOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ class PreprocessorOptions {
146146
/// When enabled, the preprocessor will construct editor placeholder tokens.
147147
bool LexEditorPlaceholders = true;
148148

149+
/// When enabled, the preprocessor will expand special builtin macros.
150+
bool LexExpandSpecialBuiltins = true;
151+
149152
/// True if the SourceManager should report the original file name for
150153
/// contents of files that were remapped to other files. Defaults to true.
151154
bool RemappedFilesKeepOriginalName = true;
@@ -249,6 +252,7 @@ class PreprocessorOptions {
249252
ImplicitPCHInclude.clear();
250253
SingleFileParseMode = false;
251254
LexEditorPlaceholders = true;
255+
LexExpandSpecialBuiltins = true;
252256
RetainRemappedFileBuffers = true;
253257
PrecompiledPreambleBytes.first = 0;
254258
PrecompiledPreambleBytes.second = false;

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,19 +1502,15 @@ class Sema final {
15021502
/// statements.
15031503
class FPFeaturesStateRAII {
15041504
public:
1505-
FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.CurFPFeatures) {
1506-
OldOverrides = S.FpPragmaStack.CurrentValue;
1507-
}
1508-
~FPFeaturesStateRAII() {
1509-
S.CurFPFeatures = OldFPFeaturesState;
1510-
S.FpPragmaStack.CurrentValue = OldOverrides;
1511-
}
1505+
FPFeaturesStateRAII(Sema &S);
1506+
~FPFeaturesStateRAII();
15121507
FPOptionsOverride getOverrides() { return OldOverrides; }
15131508

15141509
private:
15151510
Sema& S;
15161511
FPOptions OldFPFeaturesState;
15171512
FPOptionsOverride OldOverrides;
1513+
int OldEvalMethod;
15181514
};
15191515

15201516
void addImplicitTypedef(StringRef Name, QualType T);

clang/lib/Basic/Targets/OSTargets.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ class AIXTargetInfo : public OSTargetInfo<Target> {
735735
}
736736

737737
// AIX sets FLT_EVAL_METHOD to be 1.
738-
unsigned getFloatEvalMethod() const override { return 1; }
738+
int getFPEvalMethod() const override { return 1; }
739739
bool hasInt128Type() const override { return false; }
740740

741741
bool defaultsToAIXPowerAlignment() const override { return true; }

clang/lib/Basic/Targets/X86.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
165165
return LongDoubleFormat == &llvm::APFloat::IEEEquad() ? "g" : "e";
166166
}
167167

168-
unsigned getFloatEvalMethod() const override {
168+
int getFPEvalMethod() const override {
169169
// X87 evaluates with 80 bits "long double" precision.
170170
return SSELevel == NoSSE ? 2 : 0;
171171
}
@@ -468,12 +468,12 @@ class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
468468
NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
469469
: NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}
470470

471-
unsigned getFloatEvalMethod() const override {
471+
int getFPEvalMethod() const override {
472472
unsigned Major, Minor, Micro;
473473
getTriple().getOSVersion(Major, Minor, Micro);
474474
// New NetBSD uses the default rounding mode.
475475
if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 0)
476-
return X86_32TargetInfo::getFloatEvalMethod();
476+
return X86_32TargetInfo::getFPEvalMethod();
477477
// NetBSD before 6.99.26 defaults to "double" rounding.
478478
return 1;
479479
}

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,6 +2631,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
26312631
StringRef FPModel = "";
26322632
// -ffp-exception-behavior options: strict, maytrap, ignore
26332633
StringRef FPExceptionBehavior = "";
2634+
// -ffp-eval-method options: double, extended, source
2635+
StringRef FPEvalMethod = "";
26342636
const llvm::DenormalMode DefaultDenormalFPMath =
26352637
TC.getDefaultDenormalModeForType(Args, JA);
26362638
const llvm::DenormalMode DefaultDenormalFP32Math =
@@ -2822,6 +2824,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
28222824
break;
28232825
}
28242826

2827+
// Validate and pass through -ffp-eval-method option.
2828+
case options::OPT_ffp_eval_method_EQ: {
2829+
StringRef Val = A->getValue();
2830+
if (Val.equals("double") || Val.equals("extended") ||
2831+
Val.equals("source"))
2832+
FPEvalMethod = Val;
2833+
else
2834+
D.Diag(diag::err_drv_unsupported_option_argument)
2835+
<< A->getOption().getName() << Val;
2836+
break;
2837+
}
2838+
28252839
case options::OPT_ffinite_math_only:
28262840
HonorINFs = false;
28272841
HonorNaNs = false;
@@ -2965,6 +2979,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
29652979
CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" +
29662980
FPExceptionBehavior));
29672981

2982+
if (!FPEvalMethod.empty())
2983+
CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" + FPEvalMethod));
2984+
29682985
ParseMRecip(D, Args, CmdArgs);
29692986

29702987
// -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4242,8 +4242,13 @@ static bool ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
42424242
// Always avoid lexing editor placeholders when we're just running the
42434243
// preprocessor as we never want to emit the
42444244
// "editor placeholder in source file" error in PP only mode.
4245-
if (isStrictlyPreprocessorAction(Action))
4245+
// Certain predefined macros which depend upon semantic processing,
4246+
// for example __FLT_EVAL_METHOD__, are not expanded in PP mode, they
4247+
// appear in the preprocessed output as an unexpanded macro name.
4248+
if (isStrictlyPreprocessorAction(Action)) {
42464249
Opts.LexEditorPlaceholders = false;
4250+
Opts.LexExpandSpecialBuiltins = false;
4251+
}
42474252

42484253
return Diags.getNumErrors() == NumErrorsBefore;
42494254
}

clang/lib/Frontend/InitPreprocessor.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
10771077
}
10781078

10791079
// Macros to control C99 numerics and <float.h>
1080-
Builder.defineMacro("__FLT_EVAL_METHOD__", Twine(TI.getFloatEvalMethod()));
1080+
// Note: __FLT_EVAL_METHOD__ is not defined here since it is a special
1081+
// builtin macro, its value may fluctuate during compilation.
10811082
Builder.defineMacro("__FLT_RADIX__", "2");
10821083
Builder.defineMacro("__DECIMAL_DIG__", "__LDBL_DECIMAL_DIG__");
10831084

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@ void Preprocessor::RegisterBuiltinMacros() {
345345
Ident__TIME__ = RegisterBuiltinMacro(*this, "__TIME__");
346346
Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__");
347347
Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma");
348+
if (PPOpts->LexExpandSpecialBuiltins)
349+
// Suppress macro expansion if compiler stops before semantic analysis,
350+
// the macro identifier will appear in the preprocessed output.
351+
Ident__FLT_EVAL_METHOD__ =
352+
RegisterBuiltinMacro(*this, "__FLT_EVAL_METHOD__");
348353

349354
// C++ Standing Document Extensions.
350355
if (getLangOpts().CPlusPlus)
@@ -1607,6 +1612,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
16071612
// Surround the string with " and strip the trailing newline.
16081613
OS << '"' << StringRef(Result).drop_back() << '"';
16091614
Tok.setKind(tok::string_literal);
1615+
} else if (II == Ident__FLT_EVAL_METHOD__) {
1616+
// __FLT_EVAL_METHOD__ expands to a simple numeric value.
1617+
OS << getCurrentFPEvalMethod();
1618+
Tok.setKind(tok::numeric_constant);
16101619
} else if (II == Ident__COUNTER__) {
16111620
// __COUNTER__ expands to a simple numeric value.
16121621
OS << CounterValue++;
@@ -1704,8 +1713,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
17041713

17051714
return false;
17061715
});
1707-
} else if (II == Ident__has_cpp_attribute ||
1708-
II == Ident__has_c_attribute) {
1716+
} else if (II == Ident__has_cpp_attribute || II == Ident__has_c_attribute) {
17091717
bool IsCXX = II == Ident__has_cpp_attribute;
17101718
EvaluateFeatureLikeBuiltinMacro(
17111719
OS, Tok, II, *this, [&](Token &Tok, bool &HasLexedNextToken) -> int {
@@ -1732,8 +1740,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
17321740
getLangOpts())
17331741
: 0;
17341742
});
1735-
} else if (II == Ident__has_include ||
1736-
II == Ident__has_include_next) {
1743+
} else if (II == Ident__has_include || II == Ident__has_include_next) {
17371744
// The argument to these two builtins should be a parenthesized
17381745
// file name string literal using angle brackets (<>) or
17391746
// double-quotes ("").

0 commit comments

Comments
 (0)