Skip to content

Commit 69aacaf

Browse files
author
Melanie Blower
committed
Reapply "Add support for #pragma float_control" with improvements to
test cases Add support for #pragma float_control Reviewers: rjmccall, erichkeane, sepavloff Differential Revision: https://reviews.llvm.org/D72841 This reverts commit 85dc033, and makes corrections to the test cases that failed on buildbots.
1 parent d805ab7 commit 69aacaf

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

+1399
-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: 85 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ class LangOptions : public LangOptionsBase {
304304
/// input is a header file (i.e. -x c-header).
305305
bool IsHeaderFile = false;
306306

307+
bool denormalIsIEEE = false;
308+
307309
LangOptions();
308310

309311
// Define accessors/mutators for language options of enumeration type.
@@ -377,28 +379,33 @@ class FPOptions {
377379
using RoundingMode = llvm::RoundingMode;
378380

379381
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-
{}
382+
FPOptions()
383+
: fp_contract(LangOptions::FPC_Off), fenv_access(LangOptions::FEA_Off),
384+
rounding(LangOptions::FPR_ToNearest),
385+
exceptions(LangOptions::FPE_Ignore), allow_reassoc(0), no_nans(0),
386+
no_infs(0), no_signed_zeros(0), allow_reciprocal(0), approx_func(0) {}
385387

386388
// 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-
{}
389+
explicit FPOptions(unsigned I) { getFromOpaqueInt(I); }
393390

394391
explicit FPOptions(const LangOptions &LangOpts)
395392
: fp_contract(LangOpts.getDefaultFPContractMode()),
396393
fenv_access(LangOptions::FEA_Off),
397-
rounding(LangOptions::FPR_ToNearest),
398-
exceptions(LangOptions::FPE_Ignore)
399-
{}
394+
rounding(static_cast<unsigned>(LangOpts.getFPRoundingMode())),
395+
exceptions(LangOpts.getFPExceptionMode()),
396+
allow_reassoc(LangOpts.FastMath || LangOpts.AllowFPReassoc),
397+
no_nans(LangOpts.FastMath || LangOpts.NoHonorNaNs),
398+
no_infs(LangOpts.FastMath || LangOpts.NoHonorInfs),
399+
no_signed_zeros(LangOpts.FastMath || LangOpts.NoSignedZero),
400+
allow_reciprocal(LangOpts.FastMath || LangOpts.AllowRecip),
401+
approx_func(LangOpts.FastMath || LangOpts.ApproxFunc) {}
400402
// FIXME: Use getDefaultFEnvAccessMode() when available.
401403

404+
void setFastMath(bool B = true) {
405+
allow_reassoc = no_nans = no_infs = no_signed_zeros = approx_func =
406+
allow_reciprocal = B;
407+
}
408+
402409
/// Return the default value of FPOptions that's used when trailing
403410
/// storage isn't required.
404411
static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO);
@@ -433,6 +440,18 @@ class FPOptions {
433440
fenv_access = LangOptions::FEA_On;
434441
}
435442

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

438457
RoundingMode getRoundingMode() const {
@@ -451,6 +470,22 @@ class FPOptions {
451470
exceptions = EM;
452471
}
453472

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

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

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

0 commit comments

Comments
 (0)