Skip to content

Commit f5360d4

Browse files
author
Melanie Blower
committed
Reapply "Add support for #pragma float_control" with buildbot fixes
Add support for #pragma float_control Reviewers: rjmccall, erichkeane, sepavloff Differential Revision: https://reviews.llvm.org/D72841 This reverts commit fce82c0.
1 parent 67b466d commit f5360d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1387
-274
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3197,6 +3197,41 @@ The pragma can also be used with ``off`` which turns FP contraction off for a
31973197
section of the code. This can be useful when fast contraction is otherwise
31983198
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
31993199
3200+
The ``#pragma float_control`` pragma allows precise floating-point
3201+
semantics and floating-point exception behavior to be specified
3202+
for a section of the source code. This pragma can only appear at file scope or
3203+
at the start of a compound statement (excluding comments). When using within a
3204+
compound statement, the pragma is active within the scope of the compound
3205+
statement. This pragma is modeled after a Microsoft pragma with the
3206+
same spelling and syntax. For pragmas specified at file scope, a stack
3207+
is supported so that the ``pragma float_control`` settings can be pushed or popped.
3208+
3209+
When ``pragma float_control(precise, on)`` is enabled, the section of code
3210+
governed by the pragma uses precise floating point semantics, effectively
3211+
``-ffast-math`` is disabled and ``-ffp-contract=on``
3212+
(fused multiply add) is enabled.
3213+
3214+
When ``pragma float_control(except, on)`` is enabled, the section of code governed
3215+
by the pragma behaves as though the command-line option
3216+
``-ffp-exception-behavior=strict`` is enabled,
3217+
when ``pragma float_control(precise, off)`` is enabled, the section of code
3218+
governed by the pragma behaves as though the command-line option
3219+
``-ffp-exception-behavior=ignore`` is enabled.
3220+
3221+
The full syntax this pragma supports is
3222+
``float_control(except|precise, on|off [, push])`` and
3223+
``float_control(push|pop)``.
3224+
The ``push`` and ``pop`` forms, including using ``push`` as the optional
3225+
third argument, can only occur at file scope.
3226+
3227+
.. code-block:: c++
3228+
3229+
for(...) {
3230+
// This block will be compiled with -fno-fast-math and -ffp-contract=on
3231+
#pragma float_control(precise, on)
3232+
a = b[i] * c[i] + e;
3233+
}
3234+
32003235
Specifying an attribute for multiple declarations (#pragma clang attribute)
32013236
===========================================================================
32023237

clang/include/clang/AST/Expr.h

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,26 +2107,48 @@ class ParenExpr : public Expr {
21072107
/// applied to a non-complex value, the former returns its operand and the
21082108
/// later returns zero in the type of the operand.
21092109
///
2110-
class UnaryOperator : public Expr {
2110+
class UnaryOperator final
2111+
: public Expr,
2112+
private llvm::TrailingObjects<UnaryOperator, FPOptions> {
21112113
Stmt *Val;
21122114

2115+
size_t numTrailingObjects(OverloadToken<FPOptions>) const {
2116+
return UnaryOperatorBits.HasFPFeatures ? 1 : 0;
2117+
}
2118+
2119+
FPOptions &getTrailingFPFeatures() {
2120+
assert(UnaryOperatorBits.HasFPFeatures);
2121+
return *getTrailingObjects<FPOptions>();
2122+
}
2123+
2124+
const FPOptions &getTrailingFPFeatures() const {
2125+
assert(UnaryOperatorBits.HasFPFeatures);
2126+
return *getTrailingObjects<FPOptions>();
2127+
}
2128+
21132129
public:
21142130
typedef UnaryOperatorKind Opcode;
21152131

2116-
UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK,
2117-
ExprObjectKind OK, SourceLocation l, bool CanOverflow)
2118-
: Expr(UnaryOperatorClass, type, VK, OK), Val(input) {
2119-
UnaryOperatorBits.Opc = opc;
2120-
UnaryOperatorBits.CanOverflow = CanOverflow;
2121-
UnaryOperatorBits.Loc = l;
2122-
setDependence(computeDependence(this));
2123-
}
2132+
protected:
2133+
UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc, QualType type,
2134+
ExprValueKind VK, ExprObjectKind OK, SourceLocation l,
2135+
bool CanOverflow, FPOptions FPFeatures);
21242136

21252137
/// Build an empty unary operator.
2126-
explicit UnaryOperator(EmptyShell Empty) : Expr(UnaryOperatorClass, Empty) {
2138+
explicit UnaryOperator(bool HasFPFeatures, EmptyShell Empty)
2139+
: Expr(UnaryOperatorClass, Empty) {
21272140
UnaryOperatorBits.Opc = UO_AddrOf;
2141+
UnaryOperatorBits.HasFPFeatures = HasFPFeatures;
21282142
}
21292143

2144+
public:
2145+
static UnaryOperator *CreateEmpty(const ASTContext &C, bool hasFPFeatures);
2146+
2147+
static UnaryOperator *Create(const ASTContext &C, Expr *input, Opcode opc,
2148+
QualType type, ExprValueKind VK,
2149+
ExprObjectKind OK, SourceLocation l,
2150+
bool CanOverflow, FPOptions FPFeatures);
2151+
21302152
Opcode getOpcode() const {
21312153
return static_cast<Opcode>(UnaryOperatorBits.Opc);
21322154
}
@@ -2148,6 +2170,18 @@ class UnaryOperator : public Expr {
21482170
bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
21492171
void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; }
21502172

2173+
// Get the FP contractability status of this operator. Only meaningful for
2174+
// operations on floating point types.
2175+
bool isFPContractableWithinStatement(const LangOptions &LO) const {
2176+
return getFPFeatures(LO).allowFPContractWithinStatement();
2177+
}
2178+
2179+
// Get the FENV_ACCESS status of this operator. Only meaningful for
2180+
// operations on floating point types.
2181+
bool isFEnvAccessOn(const LangOptions &LO) const {
2182+
return getFPFeatures(LO).allowFEnvAccess();
2183+
}
2184+
21512185
/// isPostfix - Return true if this is a postfix operation, like x++.
21522186
static bool isPostfix(Opcode Op) {
21532187
return Op == UO_PostInc || Op == UO_PostDec;
@@ -2214,6 +2248,30 @@ class UnaryOperator : public Expr {
22142248
const_child_range children() const {
22152249
return const_child_range(&Val, &Val + 1);
22162250
}
2251+
2252+
/// Is FPFeatures in Trailing Storage?
2253+
bool hasStoredFPFeatures() const { return UnaryOperatorBits.HasFPFeatures; }
2254+
2255+
protected:
2256+
/// Get FPFeatures from trailing storage
2257+
FPOptions getStoredFPFeatures() const { return getTrailingFPFeatures(); }
2258+
2259+
/// Set FPFeatures in trailing storage, used only by Serialization
2260+
void setStoredFPFeatures(FPOptions F) { getTrailingFPFeatures() = F; }
2261+
2262+
public:
2263+
// Get the FP features status of this operator. Only meaningful for
2264+
// operations on floating point types.
2265+
FPOptions getFPFeatures(const LangOptions &LO) const {
2266+
if (UnaryOperatorBits.HasFPFeatures)
2267+
return getStoredFPFeatures();
2268+
return FPOptions::defaultWithoutTrailingStorage(LO);
2269+
}
2270+
2271+
friend TrailingObjects;
2272+
friend class ASTReader;
2273+
friend class ASTStmtReader;
2274+
friend class ASTStmtWriter;
22172275
};
22182276

22192277
/// Helper class for OffsetOfExpr.

clang/include/clang/AST/Stmt.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@ class alignas(void *) Stmt {
427427

428428
unsigned Opc : 5;
429429
unsigned CanOverflow : 1;
430+
//
431+
/// This is only meaningful for operations on floating point
432+
/// types when additional values need to be in trailing storage.
433+
/// It is 0 otherwise.
434+
unsigned HasFPFeatures : 1;
430435

431436
SourceLocation Loc;
432437
};
@@ -610,7 +615,7 @@ class alignas(void *) Stmt {
610615
unsigned OperatorKind : 6;
611616

612617
// Only meaningful for floating point types.
613-
unsigned FPFeatures : 8;
618+
unsigned FPFeatures : 14;
614619
};
615620

616621
class CXXRewrittenBinaryOperatorBitfields {

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,9 +1097,9 @@ def warn_pragma_init_seg_unsupported_target : Warning<
10971097
"'#pragma init_seg' is only supported when targeting a "
10981098
"Microsoft environment">,
10991099
InGroup<IgnoredPragmas>;
1100-
// - #pragma fp_contract
1101-
def err_pragma_fp_contract_scope : Error<
1102-
"'#pragma fp_contract' can only appear at file scope or at the start of a "
1100+
// - #pragma restricted to file scope or start of compound statement
1101+
def err_pragma_file_or_compound_scope : Error<
1102+
"'#pragma %0' can only appear at file scope or at the start of a "
11031103
"compound statement">;
11041104
// - #pragma stdc unknown
11051105
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
@@ -1118,6 +1118,10 @@ def warn_pragma_comment_ignored : Warning<"'#pragma comment %0' ignored">,
11181118
def err_pragma_detect_mismatch_malformed : Error<
11191119
"pragma detect_mismatch is malformed; it requires two comma-separated "
11201120
"string literals">;
1121+
// - #pragma float_control
1122+
def err_pragma_float_control_malformed : Error<
1123+
"pragma float_control is malformed; use 'float_control({push|pop})' or "
1124+
"'float_control({precise|except}, {on|off} [,push])'">;
11211125
// - #pragma pointers_to_members
11221126
def err_pragma_pointers_to_members_unknown_kind : Error<
11231127
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
@@ -1332,9 +1336,6 @@ def err_pragma_fp_invalid_option : Error<
13321336
def err_pragma_fp_invalid_argument : Error<
13331337
"unexpected argument '%0' to '#pragma clang fp %1'; "
13341338
"expected 'on', 'fast' or 'off'">;
1335-
def err_pragma_fp_scope : Error<
1336-
"'#pragma clang fp' can only appear at file scope or at the start of a "
1337-
"compound statement">;
13381339

13391340
def err_pragma_invalid_keyword : Error<
13401341
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,16 @@ def warn_pragma_pack_pop_identifier_and_alignment : Warning<
858858
"specifying both a name and alignment to 'pop' is undefined">;
859859
def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">,
860860
InGroup<IgnoredPragmas>;
861+
def err_pragma_fc_pp_scope : Error<
862+
"'#pragma float_control push/pop' can only appear at file scope">;
863+
def err_pragma_fc_noprecise_requires_nofenv : Error<
864+
"'#pragma float_control(precise, off)' is illegal when fenv_access is enabled">;
865+
def err_pragma_fc_except_requires_precise : Error<
866+
"'#pragma float_control(except, on)' is illegal when precise is disabled">;
867+
def err_pragma_fc_noprecise_requires_noexcept : Error<
868+
"'#pragma float_control(precise, off)' is illegal when except is enabled">;
869+
def err_pragma_fenv_requires_precise : Error<
870+
"'#pragma STDC FENV_ACCESS ON' is illegal when precise is disabled">;
861871
def warn_cxx_ms_struct :
862872
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
863873
"with base classes or virtual functions">,

clang/include/clang/Basic/LangOptions.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
191191
COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro")
192192
COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro")
193193
COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math")
194+
COMPATIBLE_LANGOPT(AllowFPReassoc , 1, 0, "Permit Floating Point reassociation")
195+
COMPATIBLE_LANGOPT(NoHonorNaNs , 1, 0, "Permit Floating Point optimization without regard to NaN")
196+
COMPATIBLE_LANGOPT(NoHonorInfs , 1, 0, "Permit Floating Point optimization without regard to infinities")
197+
COMPATIBLE_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization without regard to signed zeros")
198+
COMPATIBLE_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal")
199+
COMPATIBLE_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation")
194200

195201
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
196202

clang/include/clang/Basic/LangOptions.h

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -377,28 +377,33 @@ class FPOptions {
377377
using RoundingMode = llvm::RoundingMode;
378378

379379
public:
380-
FPOptions() : fp_contract(LangOptions::FPC_Off),
381-
fenv_access(LangOptions::FEA_Off),
382-
rounding(LangOptions::FPR_ToNearest),
383-
exceptions(LangOptions::FPE_Ignore)
384-
{}
380+
FPOptions()
381+
: fp_contract(LangOptions::FPC_Off), fenv_access(LangOptions::FEA_Off),
382+
rounding(LangOptions::FPR_ToNearest),
383+
exceptions(LangOptions::FPE_Ignore), allow_reassoc(0), no_nans(0),
384+
no_infs(0), no_signed_zeros(0), allow_reciprocal(0), approx_func(0) {}
385385

386386
// Used for serializing.
387-
explicit FPOptions(unsigned I)
388-
: fp_contract(I & 3),
389-
fenv_access((I >> 2) & 1),
390-
rounding ((I >> 3) & 7),
391-
exceptions ((I >> 6) & 3)
392-
{}
387+
explicit FPOptions(unsigned I) { getFromOpaqueInt(I); }
393388

394389
explicit FPOptions(const LangOptions &LangOpts)
395390
: fp_contract(LangOpts.getDefaultFPContractMode()),
396391
fenv_access(LangOptions::FEA_Off),
397-
rounding(LangOptions::FPR_ToNearest),
398-
exceptions(LangOptions::FPE_Ignore)
399-
{}
392+
rounding(static_cast<unsigned>(LangOpts.getFPRoundingMode())),
393+
exceptions(LangOpts.getFPExceptionMode()),
394+
allow_reassoc(LangOpts.FastMath || LangOpts.AllowFPReassoc),
395+
no_nans(LangOpts.FastMath || LangOpts.NoHonorNaNs),
396+
no_infs(LangOpts.FastMath || LangOpts.NoHonorInfs),
397+
no_signed_zeros(LangOpts.FastMath || LangOpts.NoSignedZero),
398+
allow_reciprocal(LangOpts.FastMath || LangOpts.AllowRecip),
399+
approx_func(LangOpts.FastMath || LangOpts.ApproxFunc) {}
400400
// FIXME: Use getDefaultFEnvAccessMode() when available.
401401

402+
void setFastMath(bool B = true) {
403+
allow_reassoc = no_nans = no_infs = no_signed_zeros = approx_func =
404+
allow_reciprocal = B;
405+
}
406+
402407
/// Return the default value of FPOptions that's used when trailing
403408
/// storage isn't required.
404409
static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO);
@@ -433,6 +438,18 @@ class FPOptions {
433438
fenv_access = LangOptions::FEA_On;
434439
}
435440

441+
void setFPPreciseEnabled(bool Value) {
442+
if (Value) {
443+
/* Precise mode implies fp_contract=on and disables ffast-math */
444+
setFastMath(false);
445+
setAllowFPContractWithinStatement();
446+
} else {
447+
/* Precise mode implies fp_contract=fast and enables ffast-math */
448+
setFastMath(true);
449+
setAllowFPContractAcrossStatement();
450+
}
451+
}
452+
436453
void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; }
437454

438455
RoundingMode getRoundingMode() const {
@@ -451,6 +468,22 @@ class FPOptions {
451468
exceptions = EM;
452469
}
453470

471+
/// FMF Flag queries
472+
bool allowAssociativeMath() const { return allow_reassoc; }
473+
bool noHonorNaNs() const { return no_nans; }
474+
bool noHonorInfs() const { return no_infs; }
475+
bool noSignedZeros() const { return no_signed_zeros; }
476+
bool allowReciprocalMath() const { return allow_reciprocal; }
477+
bool allowApproximateFunctions() const { return approx_func; }
478+
479+
/// Flag setters
480+
void setAllowAssociativeMath(bool B = true) { allow_reassoc = B; }
481+
void setNoHonorNaNs(bool B = true) { no_nans = B; }
482+
void setNoHonorInfs(bool B = true) { no_infs = B; }
483+
void setNoSignedZeros(bool B = true) { no_signed_zeros = B; }
484+
void setAllowReciprocalMath(bool B = true) { allow_reciprocal = B; }
485+
void setAllowApproximateFunctions(bool B = true) { approx_func = B; }
486+
454487
bool isFPConstrained() const {
455488
return getRoundingMode() != RoundingMode::NearestTiesToEven ||
456489
getExceptionMode() != LangOptions::FPE_Ignore ||
@@ -460,7 +493,23 @@ class FPOptions {
460493
/// Used to serialize this.
461494
unsigned getAsOpaqueInt() const {
462495
return fp_contract | (fenv_access << 2) | (rounding << 3) |
463-
(exceptions << 6);
496+
(exceptions << 6) | (allow_reassoc << 8) | (no_nans << 9) |
497+
(no_infs << 10) | (no_signed_zeros << 11) |
498+
(allow_reciprocal << 12) | (approx_func << 13);
499+
}
500+
501+
/// Used with getAsOpaqueInt() to manage the float_control pragma stack.
502+
void getFromOpaqueInt(unsigned I) {
503+
fp_contract = (static_cast<LangOptions::FPContractModeKind>(I & 3));
504+
fenv_access = (static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1));
505+
rounding = static_cast<unsigned>(static_cast<RoundingMode>((I >> 3) & 7));
506+
exceptions = (static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3));
507+
allow_reassoc = ((I >> 8) & 1);
508+
no_nans = ((I >> 9) & 1);
509+
no_infs = ((I >> 10) & 1);
510+
no_signed_zeros = ((I >> 11) & 1);
511+
allow_reciprocal = ((I >> 12) & 1);
512+
approx_func = ((I >> 13) & 1);
464513
}
465514

466515
private:
@@ -471,6 +520,25 @@ class FPOptions {
471520
unsigned fenv_access : 1;
472521
unsigned rounding : 3;
473522
unsigned exceptions : 2;
523+
/// Allow reassociation transformations for floating-point instructions.
524+
unsigned allow_reassoc : 1;
525+
/// No NaNs - Allow optimizations to assume the arguments and result
526+
/// are not NaN. If an argument is a nan, or the result would be a nan,
527+
/// it produces a :ref:`poison value <poisonvalues>` instead.
528+
unsigned no_nans : 1;
529+
/// No Infs - Allow optimizations to assume the arguments and result
530+
/// are not +/-Inf. If an argument is +/-Inf, or the result would be +/-Inf,
531+
/// it produces a :ref:`poison value <poisonvalues>` instead.
532+
unsigned no_infs : 1;
533+
/// No Signed Zeros - Allow optimizations to treat the sign of a zero
534+
/// argument or result as insignificant.
535+
unsigned no_signed_zeros : 1;
536+
/// Allow Reciprocal - Allow optimizations to use the reciprocal
537+
/// of an argument rather than perform division.
538+
unsigned allow_reciprocal : 1;
539+
/// Approximate functions - Allow substitution of approximate calculations
540+
/// for functions (sin, log, sqrt, etc).
541+
unsigned approx_func : 1;
474542
};
475543

476544
/// Describes the kind of translation unit being processed.

clang/include/clang/Basic/PragmaKinds.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ enum PragmaMSStructKind {
2525
PMSST_ON // #pragms ms_struct on
2626
};
2727

28+
enum PragmaFloatControlKind {
29+
PFC_Unknown,
30+
PFC_Precise, // #pragma float_control(precise, [,on])
31+
PFC_NoPrecise, // #pragma float_control(precise, off)
32+
PFC_Except, // #pragma float_control(except [,on])
33+
PFC_NoExcept, // #pragma float_control(except, off)
34+
PFC_Push, // #pragma float_control(push)
35+
PFC_Pop // #pragma float_control(pop)
36+
};
2837
}
2938

3039
#endif

0 commit comments

Comments
 (0)