Skip to content

Commit 706e89d

Browse files
committed
Fix interaction of pragma FENV_ACCESS with other pragmas
Previously `#pragma STDC FENV_ACCESS ON` always set dynamic rounding mode and strict exception handling. It is not correct in the presence of other pragmas that also modify rounding mode and exception handling. For example, the effect of previous pragma FENV_ROUND could be cancelled, which is not conformant with the C standard. Also `#pragma STDC FENV_ACCESS OFF` turned off only FEnvAccess flag, leaving rounding mode and exception handling unchanged, which is incorrect in general case. Concrete rounding and exception mode depend on a combination of several factors like various pragmas and command-line options. During the review of this patch an idea was proposed that the semantic actions associated with such pragmas should only set appropriate flags. Actual rounding mode and exception handling should be calculated taking into account the state of all relevant options. In such implementation the pragma FENV_ACCESS should not override properties set by other pragmas but should set them if such setting is absent. To implement this approach the following main changes are made: - Field `FPRoundingMode` is removed from `LangOptions`. Actually there are no options that set it to arbitrary rounding mode, the choice was only `dynamic` or `tonearest`. Instead, a new boolean flag `RoundingMath` is added, with the same meaning as the corresponding command-line option. - Type `FPExceptionModeKind` now has possible value `FPE_Default`. It does not represent any particular exception mode but indicates that such mode was not set and default value should be used. It allows to distinguish the case: { #pragma STDC FENV_ACCESS ON ... } where the pragma must set FPE_Strict, from the case: { #pragma clang fp exceptions(ignore) #pragma STDC FENV_ACCESS ON ... } where exception mode should remain `FPE_Ignore`. - Class `FPOptions` has now methods `getRoundingMode` and `getExceptionMode`, which calculates the respective properties from other specified FP properties. - Class `LangOptions` has now methods `getDefaultRoundingMode` and `getDefaultExceptionMode`, which calculates default modes from the specified options and should be used instead of `getRoundingMode` and `getFPExceptionMode` of the same class. Differential Revision: https://reviews.llvm.org/D126364
1 parent 681cde7 commit 706e89d

File tree

13 files changed

+246
-73
lines changed

13 files changed

+246
-73
lines changed

clang/include/clang/Basic/FPOptions.def

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414

1515
// OPTION(name, type, width, previousName)
1616
OPTION(FPContractMode, LangOptions::FPModeKind, 2, First)
17-
OPTION(RoundingMode, LangOptions::RoundingMode, 3, FPContractMode)
18-
OPTION(FPExceptionMode, LangOptions::FPExceptionModeKind, 2, RoundingMode)
19-
OPTION(AllowFEnvAccess, bool, 1, FPExceptionMode)
17+
OPTION(RoundingMath, bool, 1, FPContractMode)
18+
OPTION(ConstRoundingMode, LangOptions::RoundingMode, 3, RoundingMath)
19+
OPTION(SpecifiedExceptionMode, LangOptions::FPExceptionModeKind, 2, ConstRoundingMode)
20+
OPTION(AllowFEnvAccess, bool, 1, SpecifiedExceptionMode)
2021
OPTION(AllowFPReassociate, bool, 1, AllowFEnvAccess)
2122
OPTION(NoHonorNaNs, bool, 1, AllowFPReassociate)
2223
OPTION(NoHonorInfs, bool, 1, NoHonorNaNs)

clang/include/clang/Basic/LangOptions.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,8 @@ COMPATIBLE_LANGOPT(CLFiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined mac
311311
/// FP_CONTRACT mode (on/off/fast).
312312
BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type")
313313
COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating point")
314-
BENIGN_ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type")
315-
BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type")
314+
BENIGN_LANGOPT(RoundingMath, 1, false, "Do not assume default floating-point rounding behavior")
315+
BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Default, "FP Exception Behavior Mode type")
316316
BENIGN_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_UnsetOnCommandLine, "FP type used for floating point arithmetic")
317317
LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
318318
LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")

clang/include/clang/Basic/LangOptions.h

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -259,18 +259,16 @@ class LangOptions : public LangOptionsBase {
259259
FPM_FastHonorPragmas
260260
};
261261

262-
/// Alias for RoundingMode::NearestTiesToEven.
263-
static constexpr unsigned FPR_ToNearest =
264-
static_cast<unsigned>(llvm::RoundingMode::NearestTiesToEven);
265-
266262
/// Possible floating point exception behavior.
267263
enum FPExceptionModeKind {
268264
/// Assume that floating-point exceptions are masked.
269265
FPE_Ignore,
270266
/// Transformations do not cause new exceptions but may hide some.
271267
FPE_MayTrap,
272268
/// Strictly preserve the floating-point exception semantics.
273-
FPE_Strict
269+
FPE_Strict,
270+
/// Used internally to represent initial unspecified value.
271+
FPE_Default
274272
};
275273

276274
/// Possible float expression evaluation method choices.
@@ -610,14 +608,26 @@ class LangOptions : public LangOptionsBase {
610608

611609
/// Remap path prefix according to -fmacro-prefix-path option.
612610
void remapPathPrefix(SmallVectorImpl<char> &Path) const;
611+
612+
RoundingMode getDefaultRoundingMode() const {
613+
return RoundingMath ? RoundingMode::Dynamic
614+
: RoundingMode::NearestTiesToEven;
615+
}
616+
617+
FPExceptionModeKind getDefaultExceptionMode() const {
618+
FPExceptionModeKind EM = getFPExceptionMode();
619+
if (EM == FPExceptionModeKind::FPE_Default)
620+
return FPExceptionModeKind::FPE_Ignore;
621+
return EM;
622+
}
613623
};
614624

615625
/// Floating point control options
616626
class FPOptionsOverride;
617627
class FPOptions {
618628
public:
619629
// We start by defining the layout.
620-
using storage_type = uint16_t;
630+
using storage_type = uint32_t;
621631

622632
using RoundingMode = llvm::RoundingMode;
623633

@@ -646,8 +656,8 @@ class FPOptions {
646656
public:
647657
FPOptions() : Value(0) {
648658
setFPContractMode(LangOptions::FPM_Off);
649-
setRoundingMode(static_cast<RoundingMode>(LangOptions::FPR_ToNearest));
650-
setFPExceptionMode(LangOptions::FPE_Ignore);
659+
setConstRoundingMode(RoundingMode::Dynamic);
660+
setSpecifiedExceptionMode(LangOptions::FPE_Default);
651661
}
652662
explicit FPOptions(const LangOptions &LO) {
653663
Value = 0;
@@ -658,8 +668,9 @@ class FPOptions {
658668
if (LangOptContractMode == LangOptions::FPM_FastHonorPragmas)
659669
LangOptContractMode = LangOptions::FPM_Fast;
660670
setFPContractMode(LangOptContractMode);
661-
setRoundingMode(LO.getFPRoundingMode());
662-
setFPExceptionMode(LO.getFPExceptionMode());
671+
setRoundingMath(LO.RoundingMath);
672+
setConstRoundingMode(LangOptions::RoundingMode::Dynamic);
673+
setSpecifiedExceptionMode(LO.getFPExceptionMode());
663674
setAllowFPReassociate(LO.AllowFPReassoc);
664675
setNoHonorNaNs(LO.NoHonorNaNs);
665676
setNoHonorInfs(LO.NoHonorInfs);
@@ -668,7 +679,7 @@ class FPOptions {
668679
setAllowApproxFunc(LO.ApproxFunc);
669680
if (getFPContractMode() == LangOptions::FPM_On &&
670681
getRoundingMode() == llvm::RoundingMode::Dynamic &&
671-
getFPExceptionMode() == LangOptions::FPE_Strict)
682+
getExceptionMode() == LangOptions::FPE_Strict)
672683
// If the FP settings are set to the "strict" model, then
673684
// FENV access is set to true. (ffp-model=strict)
674685
setAllowFEnvAccess(true);
@@ -692,10 +703,33 @@ class FPOptions {
692703

693704
bool isFPConstrained() const {
694705
return getRoundingMode() != llvm::RoundingMode::NearestTiesToEven ||
695-
getFPExceptionMode() != LangOptions::FPE_Ignore ||
706+
getExceptionMode() != LangOptions::FPE_Ignore ||
696707
getAllowFEnvAccess();
697708
}
698709

710+
RoundingMode getRoundingMode() const {
711+
RoundingMode RM = getConstRoundingMode();
712+
if (RM == RoundingMode::Dynamic) {
713+
// C2x: 7.6.2p3 If the FE_DYNAMIC mode is specified and FENV_ACCESS is
714+
// "off", the translator may assume that the default rounding mode is in
715+
// effect.
716+
if (!getAllowFEnvAccess() && !getRoundingMath())
717+
RM = RoundingMode::NearestTiesToEven;
718+
}
719+
return RM;
720+
}
721+
722+
LangOptions::FPExceptionModeKind getExceptionMode() const {
723+
LangOptions::FPExceptionModeKind EM = getSpecifiedExceptionMode();
724+
if (EM == LangOptions::FPExceptionModeKind::FPE_Default) {
725+
if (getAllowFEnvAccess())
726+
return LangOptions::FPExceptionModeKind::FPE_Strict;
727+
else
728+
return LangOptions::FPExceptionModeKind::FPE_Ignore;
729+
}
730+
return EM;
731+
}
732+
699733
bool operator==(FPOptions other) const { return Value == other.Value; }
700734

701735
/// Return the default value of FPOptions that's used when trailing
@@ -743,7 +777,7 @@ class FPOptionsOverride {
743777

744778
/// The type suitable for storing values of FPOptionsOverride. Must be twice
745779
/// as wide as bit size of FPOption.
746-
using storage_type = uint32_t;
780+
using storage_type = uint64_t;
747781
static_assert(sizeof(storage_type) >= 2 * sizeof(FPOptions::storage_type),
748782
"Too short type for FPOptionsOverride");
749783

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,7 +1544,7 @@ def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group<
15441544
HelpText<"Specifies the exception behavior of floating-point operations.">,
15451545
Values<"ignore,maytrap,strict">, NormalizedValuesScope<"LangOptions">,
15461546
NormalizedValues<["FPE_Ignore", "FPE_MayTrap", "FPE_Strict"]>,
1547-
MarshallingInfoEnum<LangOpts<"FPExceptionMode">, "FPE_Ignore">;
1547+
MarshallingInfoEnum<LangOpts<"FPExceptionMode">, "FPE_Default">;
15481548
defm fast_math : BoolFOption<"fast-math",
15491549
LangOpts<"FastMath">, DefaultFalse,
15501550
PosFlag<SetTrue, [CC1Option], "Allow aggressive, lossy floating-point optimizations",
@@ -1866,7 +1866,7 @@ def fno_honor_infinities : Flag<["-"], "fno-honor-infinities">, Group<f_Group>;
18661866
def : Flag<["-"], "fhonor-infinites">, Alias<fhonor_infinities>;
18671867
def : Flag<["-"], "fno-honor-infinites">, Alias<fno_honor_infinities>;
18681868
def frounding_math : Flag<["-"], "frounding-math">, Group<f_Group>, Flags<[CC1Option]>,
1869-
MarshallingInfoFlag<LangOpts<"FPRoundingMode">, "llvm::RoundingMode::NearestTiesToEven">,
1869+
MarshallingInfoFlag<LangOpts<"RoundingMath">>,
18701870
Normalizer<"makeFlagToValueNormalizer(llvm::RoundingMode::Dynamic)">;
18711871
def fno_rounding_math : Flag<["-"], "fno-rounding-math">, Group<f_Group>, Flags<[CC1Option]>;
18721872
def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>;

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10311,7 +10311,7 @@ class Sema final {
1031110311
LangOptions::FPExceptionModeKind);
1031210312

1031310313
/// Called to set constant rounding mode for floating point operations.
10314-
void setRoundingMode(SourceLocation Loc, llvm::RoundingMode);
10314+
void ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode);
1031510315

1031610316
/// Called to set exception behavior for floating point operations.
1031710317
void setExceptionMode(SourceLocation Loc, LangOptions::FPExceptionModeKind);

clang/lib/AST/ExprConstant.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,14 +2584,14 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
25842584

25852585
if ((St != APFloat::opOK) &&
25862586
(FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
2587-
FPO.getFPExceptionMode() != LangOptions::FPE_Ignore ||
2587+
FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
25882588
FPO.getAllowFEnvAccess())) {
25892589
Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
25902590
return false;
25912591
}
25922592

25932593
if ((St & APFloat::opStatus::opInvalidOp) &&
2594-
FPO.getFPExceptionMode() != LangOptions::FPE_Ignore) {
2594+
FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
25952595
// There is no usefully definable result.
25962596
Info.FFDiag(E);
25972597
return false;

clang/lib/CodeGen/CGCall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1849,7 +1849,7 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
18491849
CodeGenOpts.FP32DenormalMode.str());
18501850
}
18511851

1852-
if (LangOpts.getFPExceptionMode() == LangOptions::FPE_Ignore)
1852+
if (LangOpts.getDefaultExceptionMode() == LangOptions::FPE_Ignore)
18531853
FuncAttrs.addAttribute("no-trapping-math", "true");
18541854

18551855
// TODO: Are these all needed?

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ clang::ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind) {
105105
case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore;
106106
case LangOptions::FPE_MayTrap: return llvm::fp::ebMayTrap;
107107
case LangOptions::FPE_Strict: return llvm::fp::ebStrict;
108+
default:
109+
llvm_unreachable("Unsupported FP Exception Behavior");
108110
}
109-
llvm_unreachable("Unsupported FP Exception Behavior");
110111
}
111112

112113
void CodeGenFunction::SetFastMathFlags(FPOptions FPFeatures) {
@@ -145,12 +146,11 @@ void CodeGenFunction::CGFPOptionsRAII::ConstructorHelper(FPOptions FPFeatures) {
145146

146147
FMFGuard.emplace(CGF.Builder);
147148

148-
llvm::RoundingMode NewRoundingBehavior =
149-
static_cast<llvm::RoundingMode>(FPFeatures.getRoundingMode());
149+
llvm::RoundingMode NewRoundingBehavior = FPFeatures.getRoundingMode();
150150
CGF.Builder.setDefaultConstrainedRounding(NewRoundingBehavior);
151151
auto NewExceptionBehavior =
152152
ToConstrainedExceptMD(static_cast<LangOptions::FPExceptionModeKind>(
153-
FPFeatures.getFPExceptionMode()));
153+
FPFeatures.getExceptionMode()));
154154
CGF.Builder.setDefaultConstrainedExcept(NewExceptionBehavior);
155155

156156
CGF.SetFastMathFlags(FPFeatures);
@@ -971,9 +971,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
971971
(getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>())))
972972
Fn->addFnAttr(llvm::Attribute::NoRecurse);
973973

974-
llvm::RoundingMode RM = getLangOpts().getFPRoundingMode();
974+
llvm::RoundingMode RM = getLangOpts().getDefaultRoundingMode();
975975
llvm::fp::ExceptionBehavior FPExceptionBehavior =
976-
ToConstrainedExceptMD(getLangOpts().getFPExceptionMode());
976+
ToConstrainedExceptMD(getLangOpts().getDefaultExceptionMode());
977977
Builder.setDefaultConstrainedRounding(RM);
978978
Builder.setDefaultConstrainedExcept(FPExceptionBehavior);
979979
if ((FD && (FD->UsesFPIntrin() || FD->hasAttr<StrictFPAttr>())) ||

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ bool CompilerInstance::createTarget() {
123123
}
124124

125125
if (!getTarget().hasStrictFP() && !getLangOpts().ExpStrictFP) {
126-
if (getLangOpts().getFPRoundingMode() !=
127-
llvm::RoundingMode::NearestTiesToEven) {
126+
if (getLangOpts().RoundingMath) {
128127
getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_rounding);
129-
getLangOpts().setFPRoundingMode(llvm::RoundingMode::NearestTiesToEven);
128+
getLangOpts().RoundingMath = false;
130129
}
131-
if (getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore) {
130+
auto FPExc = getLangOpts().getFPExceptionMode();
131+
if (FPExc != LangOptions::FPE_Default && FPExc != LangOptions::FPE_Ignore) {
132132
getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_exceptions);
133133
getLangOpts().setFPExceptionMode(LangOptions::FPE_Ignore);
134134
}

clang/lib/Parse/ParsePragma.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ void Parser::HandlePragmaFEnvRound() {
804804
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
805805

806806
SourceLocation PragmaLoc = ConsumeAnnotationToken();
807-
Actions.setRoundingMode(PragmaLoc, RM);
807+
Actions.ActOnPragmaFEnvRound(PragmaLoc, RM);
808808
}
809809

810810
StmtResult Parser::HandlePragmaCaptured()

0 commit comments

Comments
 (0)