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 fce82c0ed3.
This commit is contained in:
Melanie Blower 2020-05-01 10:32:06 -07:00
parent 67b466deda
commit f5360d4bb3
58 changed files with 1387 additions and 274 deletions

View File

@ -3197,6 +3197,41 @@ The pragma can also be used with ``off`` which turns FP contraction off for a
section of the code. This can be useful when fast contraction is otherwise section of the code. This can be useful when fast contraction is otherwise
enabled for the translation unit with the ``-ffp-contract=fast`` flag. enabled for the translation unit with the ``-ffp-contract=fast`` flag.
The ``#pragma float_control`` pragma allows precise floating-point
semantics and floating-point exception behavior to be specified
for a section of the source code. This pragma can only appear at file scope or
at the start of a compound statement (excluding comments). When using within a
compound statement, the pragma is active within the scope of the compound
statement. This pragma is modeled after a Microsoft pragma with the
same spelling and syntax. For pragmas specified at file scope, a stack
is supported so that the ``pragma float_control`` settings can be pushed or popped.
When ``pragma float_control(precise, on)`` is enabled, the section of code
governed by the pragma uses precise floating point semantics, effectively
``-ffast-math`` is disabled and ``-ffp-contract=on``
(fused multiply add) is enabled.
When ``pragma float_control(except, on)`` is enabled, the section of code governed
by the pragma behaves as though the command-line option
``-ffp-exception-behavior=strict`` is enabled,
when ``pragma float_control(precise, off)`` is enabled, the section of code
governed by the pragma behaves as though the command-line option
``-ffp-exception-behavior=ignore`` is enabled.
The full syntax this pragma supports is
``float_control(except|precise, on|off [, push])`` and
``float_control(push|pop)``.
The ``push`` and ``pop`` forms, including using ``push`` as the optional
third argument, can only occur at file scope.
.. code-block:: c++
for(...) {
// This block will be compiled with -fno-fast-math and -ffp-contract=on
#pragma float_control(precise, on)
a = b[i] * c[i] + e;
}
Specifying an attribute for multiple declarations (#pragma clang attribute) Specifying an attribute for multiple declarations (#pragma clang attribute)
=========================================================================== ===========================================================================

View File

@ -2107,26 +2107,48 @@ public:
/// applied to a non-complex value, the former returns its operand and the /// applied to a non-complex value, the former returns its operand and the
/// later returns zero in the type of the operand. /// later returns zero in the type of the operand.
/// ///
class UnaryOperator : public Expr { class UnaryOperator final
: public Expr,
private llvm::TrailingObjects<UnaryOperator, FPOptions> {
Stmt *Val; Stmt *Val;
size_t numTrailingObjects(OverloadToken<FPOptions>) const {
return UnaryOperatorBits.HasFPFeatures ? 1 : 0;
}
FPOptions &getTrailingFPFeatures() {
assert(UnaryOperatorBits.HasFPFeatures);
return *getTrailingObjects<FPOptions>();
}
const FPOptions &getTrailingFPFeatures() const {
assert(UnaryOperatorBits.HasFPFeatures);
return *getTrailingObjects<FPOptions>();
}
public: public:
typedef UnaryOperatorKind Opcode; typedef UnaryOperatorKind Opcode;
UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK, protected:
ExprObjectKind OK, SourceLocation l, bool CanOverflow) UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc, QualType type,
: Expr(UnaryOperatorClass, type, VK, OK), Val(input) { ExprValueKind VK, ExprObjectKind OK, SourceLocation l,
UnaryOperatorBits.Opc = opc; bool CanOverflow, FPOptions FPFeatures);
UnaryOperatorBits.CanOverflow = CanOverflow;
UnaryOperatorBits.Loc = l;
setDependence(computeDependence(this));
}
/// Build an empty unary operator. /// Build an empty unary operator.
explicit UnaryOperator(EmptyShell Empty) : Expr(UnaryOperatorClass, Empty) { explicit UnaryOperator(bool HasFPFeatures, EmptyShell Empty)
: Expr(UnaryOperatorClass, Empty) {
UnaryOperatorBits.Opc = UO_AddrOf; UnaryOperatorBits.Opc = UO_AddrOf;
UnaryOperatorBits.HasFPFeatures = HasFPFeatures;
} }
public:
static UnaryOperator *CreateEmpty(const ASTContext &C, bool hasFPFeatures);
static UnaryOperator *Create(const ASTContext &C, Expr *input, Opcode opc,
QualType type, ExprValueKind VK,
ExprObjectKind OK, SourceLocation l,
bool CanOverflow, FPOptions FPFeatures);
Opcode getOpcode() const { Opcode getOpcode() const {
return static_cast<Opcode>(UnaryOperatorBits.Opc); return static_cast<Opcode>(UnaryOperatorBits.Opc);
} }
@ -2148,6 +2170,18 @@ public:
bool canOverflow() const { return UnaryOperatorBits.CanOverflow; } bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; } void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
bool isFPContractableWithinStatement(const LangOptions &LO) const {
return getFPFeatures(LO).allowFPContractWithinStatement();
}
// Get the FENV_ACCESS status of this operator. Only meaningful for
// operations on floating point types.
bool isFEnvAccessOn(const LangOptions &LO) const {
return getFPFeatures(LO).allowFEnvAccess();
}
/// isPostfix - Return true if this is a postfix operation, like x++. /// isPostfix - Return true if this is a postfix operation, like x++.
static bool isPostfix(Opcode Op) { static bool isPostfix(Opcode Op) {
return Op == UO_PostInc || Op == UO_PostDec; return Op == UO_PostInc || Op == UO_PostDec;
@ -2214,6 +2248,30 @@ public:
const_child_range children() const { const_child_range children() const {
return const_child_range(&Val, &Val + 1); return const_child_range(&Val, &Val + 1);
} }
/// Is FPFeatures in Trailing Storage?
bool hasStoredFPFeatures() const { return UnaryOperatorBits.HasFPFeatures; }
protected:
/// Get FPFeatures from trailing storage
FPOptions getStoredFPFeatures() const { return getTrailingFPFeatures(); }
/// Set FPFeatures in trailing storage, used only by Serialization
void setStoredFPFeatures(FPOptions F) { getTrailingFPFeatures() = F; }
public:
// Get the FP features status of this operator. Only meaningful for
// operations on floating point types.
FPOptions getFPFeatures(const LangOptions &LO) const {
if (UnaryOperatorBits.HasFPFeatures)
return getStoredFPFeatures();
return FPOptions::defaultWithoutTrailingStorage(LO);
}
friend TrailingObjects;
friend class ASTReader;
friend class ASTStmtReader;
friend class ASTStmtWriter;
}; };
/// Helper class for OffsetOfExpr. /// Helper class for OffsetOfExpr.

View File

@ -427,6 +427,11 @@ protected:
unsigned Opc : 5; unsigned Opc : 5;
unsigned CanOverflow : 1; unsigned CanOverflow : 1;
//
/// This is only meaningful for operations on floating point
/// types when additional values need to be in trailing storage.
/// It is 0 otherwise.
unsigned HasFPFeatures : 1;
SourceLocation Loc; SourceLocation Loc;
}; };
@ -610,7 +615,7 @@ protected:
unsigned OperatorKind : 6; unsigned OperatorKind : 6;
// Only meaningful for floating point types. // Only meaningful for floating point types.
unsigned FPFeatures : 8; unsigned FPFeatures : 14;
}; };
class CXXRewrittenBinaryOperatorBitfields { class CXXRewrittenBinaryOperatorBitfields {

View File

@ -1097,9 +1097,9 @@ def warn_pragma_init_seg_unsupported_target : Warning<
"'#pragma init_seg' is only supported when targeting a " "'#pragma init_seg' is only supported when targeting a "
"Microsoft environment">, "Microsoft environment">,
InGroup<IgnoredPragmas>; InGroup<IgnoredPragmas>;
// - #pragma fp_contract // - #pragma restricted to file scope or start of compound statement
def err_pragma_fp_contract_scope : Error< def err_pragma_file_or_compound_scope : Error<
"'#pragma fp_contract' can only appear at file scope or at the start of a " "'#pragma %0' can only appear at file scope or at the start of a "
"compound statement">; "compound statement">;
// - #pragma stdc unknown // - #pragma stdc unknown
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, 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">,
def err_pragma_detect_mismatch_malformed : Error< def err_pragma_detect_mismatch_malformed : Error<
"pragma detect_mismatch is malformed; it requires two comma-separated " "pragma detect_mismatch is malformed; it requires two comma-separated "
"string literals">; "string literals">;
// - #pragma float_control
def err_pragma_float_control_malformed : Error<
"pragma float_control is malformed; use 'float_control({push|pop})' or "
"'float_control({precise|except}, {on|off} [,push])'">;
// - #pragma pointers_to_members // - #pragma pointers_to_members
def err_pragma_pointers_to_members_unknown_kind : Error< def err_pragma_pointers_to_members_unknown_kind : Error<
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1" "unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
@ -1332,9 +1336,6 @@ def err_pragma_fp_invalid_option : Error<
def err_pragma_fp_invalid_argument : Error< def err_pragma_fp_invalid_argument : Error<
"unexpected argument '%0' to '#pragma clang fp %1'; " "unexpected argument '%0' to '#pragma clang fp %1'; "
"expected 'on', 'fast' or 'off'">; "expected 'on', 'fast' or 'off'">;
def err_pragma_fp_scope : Error<
"'#pragma clang fp' can only appear at file scope or at the start of a "
"compound statement">;
def err_pragma_invalid_keyword : Error< def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">; "invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;

View File

@ -858,6 +858,16 @@ def warn_pragma_pack_pop_identifier_and_alignment : Warning<
"specifying both a name and alignment to 'pop' is undefined">; "specifying both a name and alignment to 'pop' is undefined">;
def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">, def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">,
InGroup<IgnoredPragmas>; InGroup<IgnoredPragmas>;
def err_pragma_fc_pp_scope : Error<
"'#pragma float_control push/pop' can only appear at file scope">;
def err_pragma_fc_noprecise_requires_nofenv : Error<
"'#pragma float_control(precise, off)' is illegal when fenv_access is enabled">;
def err_pragma_fc_except_requires_precise : Error<
"'#pragma float_control(except, on)' is illegal when precise is disabled">;
def err_pragma_fc_noprecise_requires_noexcept : Error<
"'#pragma float_control(precise, off)' is illegal when except is enabled">;
def err_pragma_fenv_requires_precise : Error<
"'#pragma STDC FENV_ACCESS ON' is illegal when precise is disabled">;
def warn_cxx_ms_struct : def warn_cxx_ms_struct :
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes " Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
"with base classes or virtual functions">, "with base classes or virtual functions">,

View File

@ -191,6 +191,12 @@ COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro") COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro")
COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro")
COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math") COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math")
COMPATIBLE_LANGOPT(AllowFPReassoc , 1, 0, "Permit Floating Point reassociation")
COMPATIBLE_LANGOPT(NoHonorNaNs , 1, 0, "Permit Floating Point optimization without regard to NaN")
COMPATIBLE_LANGOPT(NoHonorInfs , 1, 0, "Permit Floating Point optimization without regard to infinities")
COMPATIBLE_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization without regard to signed zeros")
COMPATIBLE_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal")
COMPATIBLE_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation")
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars") BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")

View File

@ -377,28 +377,33 @@ class FPOptions {
using RoundingMode = llvm::RoundingMode; using RoundingMode = llvm::RoundingMode;
public: public:
FPOptions() : fp_contract(LangOptions::FPC_Off), FPOptions()
fenv_access(LangOptions::FEA_Off), : fp_contract(LangOptions::FPC_Off), fenv_access(LangOptions::FEA_Off),
rounding(LangOptions::FPR_ToNearest), rounding(LangOptions::FPR_ToNearest),
exceptions(LangOptions::FPE_Ignore) exceptions(LangOptions::FPE_Ignore), allow_reassoc(0), no_nans(0),
{} no_infs(0), no_signed_zeros(0), allow_reciprocal(0), approx_func(0) {}
// Used for serializing. // Used for serializing.
explicit FPOptions(unsigned I) explicit FPOptions(unsigned I) { getFromOpaqueInt(I); }
: fp_contract(I & 3),
fenv_access((I >> 2) & 1),
rounding ((I >> 3) & 7),
exceptions ((I >> 6) & 3)
{}
explicit FPOptions(const LangOptions &LangOpts) explicit FPOptions(const LangOptions &LangOpts)
: fp_contract(LangOpts.getDefaultFPContractMode()), : fp_contract(LangOpts.getDefaultFPContractMode()),
fenv_access(LangOptions::FEA_Off), fenv_access(LangOptions::FEA_Off),
rounding(LangOptions::FPR_ToNearest), rounding(static_cast<unsigned>(LangOpts.getFPRoundingMode())),
exceptions(LangOptions::FPE_Ignore) exceptions(LangOpts.getFPExceptionMode()),
{} allow_reassoc(LangOpts.FastMath || LangOpts.AllowFPReassoc),
no_nans(LangOpts.FastMath || LangOpts.NoHonorNaNs),
no_infs(LangOpts.FastMath || LangOpts.NoHonorInfs),
no_signed_zeros(LangOpts.FastMath || LangOpts.NoSignedZero),
allow_reciprocal(LangOpts.FastMath || LangOpts.AllowRecip),
approx_func(LangOpts.FastMath || LangOpts.ApproxFunc) {}
// FIXME: Use getDefaultFEnvAccessMode() when available. // FIXME: Use getDefaultFEnvAccessMode() when available.
void setFastMath(bool B = true) {
allow_reassoc = no_nans = no_infs = no_signed_zeros = approx_func =
allow_reciprocal = B;
}
/// Return the default value of FPOptions that's used when trailing /// Return the default value of FPOptions that's used when trailing
/// storage isn't required. /// storage isn't required.
static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO); static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO);
@ -433,6 +438,18 @@ public:
fenv_access = LangOptions::FEA_On; fenv_access = LangOptions::FEA_On;
} }
void setFPPreciseEnabled(bool Value) {
if (Value) {
/* Precise mode implies fp_contract=on and disables ffast-math */
setFastMath(false);
setAllowFPContractWithinStatement();
} else {
/* Precise mode implies fp_contract=fast and enables ffast-math */
setFastMath(true);
setAllowFPContractAcrossStatement();
}
}
void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; } void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; }
RoundingMode getRoundingMode() const { RoundingMode getRoundingMode() const {
@ -451,6 +468,22 @@ public:
exceptions = EM; exceptions = EM;
} }
/// FMF Flag queries
bool allowAssociativeMath() const { return allow_reassoc; }
bool noHonorNaNs() const { return no_nans; }
bool noHonorInfs() const { return no_infs; }
bool noSignedZeros() const { return no_signed_zeros; }
bool allowReciprocalMath() const { return allow_reciprocal; }
bool allowApproximateFunctions() const { return approx_func; }
/// Flag setters
void setAllowAssociativeMath(bool B = true) { allow_reassoc = B; }
void setNoHonorNaNs(bool B = true) { no_nans = B; }
void setNoHonorInfs(bool B = true) { no_infs = B; }
void setNoSignedZeros(bool B = true) { no_signed_zeros = B; }
void setAllowReciprocalMath(bool B = true) { allow_reciprocal = B; }
void setAllowApproximateFunctions(bool B = true) { approx_func = B; }
bool isFPConstrained() const { bool isFPConstrained() const {
return getRoundingMode() != RoundingMode::NearestTiesToEven || return getRoundingMode() != RoundingMode::NearestTiesToEven ||
getExceptionMode() != LangOptions::FPE_Ignore || getExceptionMode() != LangOptions::FPE_Ignore ||
@ -460,7 +493,23 @@ public:
/// Used to serialize this. /// Used to serialize this.
unsigned getAsOpaqueInt() const { unsigned getAsOpaqueInt() const {
return fp_contract | (fenv_access << 2) | (rounding << 3) | return fp_contract | (fenv_access << 2) | (rounding << 3) |
(exceptions << 6); (exceptions << 6) | (allow_reassoc << 8) | (no_nans << 9) |
(no_infs << 10) | (no_signed_zeros << 11) |
(allow_reciprocal << 12) | (approx_func << 13);
}
/// Used with getAsOpaqueInt() to manage the float_control pragma stack.
void getFromOpaqueInt(unsigned I) {
fp_contract = (static_cast<LangOptions::FPContractModeKind>(I & 3));
fenv_access = (static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1));
rounding = static_cast<unsigned>(static_cast<RoundingMode>((I >> 3) & 7));
exceptions = (static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3));
allow_reassoc = ((I >> 8) & 1);
no_nans = ((I >> 9) & 1);
no_infs = ((I >> 10) & 1);
no_signed_zeros = ((I >> 11) & 1);
allow_reciprocal = ((I >> 12) & 1);
approx_func = ((I >> 13) & 1);
} }
private: private:
@ -471,6 +520,25 @@ private:
unsigned fenv_access : 1; unsigned fenv_access : 1;
unsigned rounding : 3; unsigned rounding : 3;
unsigned exceptions : 2; unsigned exceptions : 2;
/// Allow reassociation transformations for floating-point instructions.
unsigned allow_reassoc : 1;
/// No NaNs - Allow optimizations to assume the arguments and result
/// are not NaN. If an argument is a nan, or the result would be a nan,
/// it produces a :ref:`poison value <poisonvalues>` instead.
unsigned no_nans : 1;
/// No Infs - Allow optimizations to assume the arguments and result
/// are not +/-Inf. If an argument is +/-Inf, or the result would be +/-Inf,
/// it produces a :ref:`poison value <poisonvalues>` instead.
unsigned no_infs : 1;
/// No Signed Zeros - Allow optimizations to treat the sign of a zero
/// argument or result as insignificant.
unsigned no_signed_zeros : 1;
/// Allow Reciprocal - Allow optimizations to use the reciprocal
/// of an argument rather than perform division.
unsigned allow_reciprocal : 1;
/// Approximate functions - Allow substitution of approximate calculations
/// for functions (sin, log, sqrt, etc).
unsigned approx_func : 1;
}; };
/// Describes the kind of translation unit being processed. /// Describes the kind of translation unit being processed.

View File

@ -25,6 +25,15 @@ enum PragmaMSStructKind {
PMSST_ON // #pragms ms_struct on PMSST_ON // #pragms ms_struct on
}; };
enum PragmaFloatControlKind {
PFC_Unknown,
PFC_Precise, // #pragma float_control(precise, [,on])
PFC_NoPrecise, // #pragma float_control(precise, off)
PFC_Except, // #pragma float_control(except [,on])
PFC_NoExcept, // #pragma float_control(except, off)
PFC_Push, // #pragma float_control(push)
PFC_Pop // #pragma float_control(pop)
};
} }
#endif #endif

View File

@ -809,6 +809,11 @@ PRAGMA_ANNOTATION(pragma_fp_contract)
// handles them. // handles them.
PRAGMA_ANNOTATION(pragma_fenv_access) PRAGMA_ANNOTATION(pragma_fenv_access)
// Annotation for #pragma float_control
// The lexer produces these so that they only take effect when the parser
// handles them.
PRAGMA_ANNOTATION(pragma_float_control)
// Annotation for #pragma pointers_to_members... // Annotation for #pragma pointers_to_members...
// The lexer produces these so that they only take effect when the parser // The lexer produces these so that they only take effect when the parser
// handles them. // handles them.

View File

@ -182,6 +182,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> PCSectionHandler; std::unique_ptr<PragmaHandler> PCSectionHandler;
std::unique_ptr<PragmaHandler> MSCommentHandler; std::unique_ptr<PragmaHandler> MSCommentHandler;
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler; std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
std::unique_ptr<PragmaHandler> FloatControlHandler;
std::unique_ptr<PragmaHandler> MSPointersToMembers; std::unique_ptr<PragmaHandler> MSPointersToMembers;
std::unique_ptr<PragmaHandler> MSVtorDisp; std::unique_ptr<PragmaHandler> MSVtorDisp;
std::unique_ptr<PragmaHandler> MSInitSeg; std::unique_ptr<PragmaHandler> MSInitSeg;
@ -741,6 +742,10 @@ private:
/// #pragma STDC FENV_ACCESS... /// #pragma STDC FENV_ACCESS...
void HandlePragmaFEnvAccess(); void HandlePragmaFEnvAccess();
/// Handle the annotation token produced for
/// #pragma float_control
void HandlePragmaFloatControl();
/// \brief Handle the annotation token produced for /// \brief Handle the annotation token produced for
/// #pragma clang fp ... /// #pragma clang fp ...
void HandlePragmaFP(); void HandlePragmaFP();

View File

@ -555,6 +555,9 @@ public:
PragmaStack<StringLiteral *> ConstSegStack; PragmaStack<StringLiteral *> ConstSegStack;
PragmaStack<StringLiteral *> CodeSegStack; PragmaStack<StringLiteral *> CodeSegStack;
// This stack tracks the current state of Sema.CurFPFeatures.
PragmaStack<unsigned> FpPragmaStack;
// RAII object to push / pop sentinel slots for all MS #pragma stacks. // RAII object to push / pop sentinel slots for all MS #pragma stacks.
// Actions should be performed only if we enter / exit a C++ method body. // Actions should be performed only if we enter / exit a C++ method body.
class PragmaStackSentinelRAII { class PragmaStackSentinelRAII {
@ -1350,7 +1353,7 @@ public:
/// should not be used elsewhere. /// should not be used elsewhere.
void EmitCurrentDiagnostic(unsigned DiagID); void EmitCurrentDiagnostic(unsigned DiagID);
/// Records and restores the FPFeatures state on entry/exit of compound /// Records and restores the CurFPFeatures state on entry/exit of compound
/// statements. /// statements.
class FPFeaturesStateRAII { class FPFeaturesStateRAII {
public: public:
@ -9566,6 +9569,18 @@ public:
void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
StringRef Value); StringRef Value);
/// Are precise floating point semantics currently enabled?
bool isPreciseFPEnabled() {
return !CurFPFeatures.allowAssociativeMath() &&
!CurFPFeatures.noSignedZeros() &&
!CurFPFeatures.allowReciprocalMath() &&
!CurFPFeatures.allowApproximateFunctions();
}
/// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control
void ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action,
PragmaFloatControlKind Value);
/// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
void ActOnPragmaUnused(const Token &Identifier, void ActOnPragmaUnused(const Token &Identifier,
Scope *curScope, Scope *curScope,
@ -9606,7 +9621,8 @@ public:
/// ActOnPragmaFenvAccess - Called on well formed /// ActOnPragmaFenvAccess - Called on well formed
/// \#pragma STDC FENV_ACCESS /// \#pragma STDC FENV_ACCESS
void ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC); void ActOnPragmaFEnvAccess(SourceLocation Loc,
LangOptions::FEnvAccessModeKind FPC);
/// Called to set rounding mode for floating point operations. /// Called to set rounding mode for floating point operations.
void setRoundingMode(llvm::RoundingMode); void setRoundingMode(llvm::RoundingMode);

View File

@ -686,6 +686,9 @@ namespace serialization {
/// Record code for the Decls to be checked for deferred diags. /// Record code for the Decls to be checked for deferred diags.
DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64, DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64,
/// Record code for \#pragma float_control options.
FLOAT_CONTROL_PRAGMA_OPTIONS = 65,
}; };
/// Record types used within a source manager block. /// Record types used within a source manager block.

View File

@ -857,6 +857,18 @@ private:
int PragmaMSPointersToMembersState = -1; int PragmaMSPointersToMembersState = -1;
SourceLocation PointersToMembersPragmaLocation; SourceLocation PointersToMembersPragmaLocation;
/// The pragma float_control state.
Optional<unsigned> FpPragmaCurrentValue;
SourceLocation FpPragmaCurrentLocation;
struct FpPragmaStackEntry {
unsigned Value;
SourceLocation Location;
SourceLocation PushLocation;
StringRef SlotLabel;
};
llvm::SmallVector<FpPragmaStackEntry, 2> FpPragmaStack;
llvm::SmallVector<std::string, 2> FpPragmaStrings;
/// The pragma pack state. /// The pragma pack state.
Optional<unsigned> PragmaPackCurrentValue; Optional<unsigned> PragmaPackCurrentValue;
SourceLocation PragmaPackCurrentLocation; SourceLocation PragmaPackCurrentLocation;

View File

@ -505,6 +505,7 @@ private:
void WriteMSStructPragmaOptions(Sema &SemaRef); void WriteMSStructPragmaOptions(Sema &SemaRef);
void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef); void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef);
void WritePackPragmaOptions(Sema &SemaRef); void WritePackPragmaOptions(Sema &SemaRef);
void WriteFloatControlPragmaOptions(Sema &SemaRef);
void WriteModuleFileExtension(Sema &SemaRef, void WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer); ModuleFileExtensionWriter &Writer);

View File

@ -6660,9 +6660,10 @@ ExpectedStmt ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
if (Err) if (Err)
return std::move(Err); return std::move(Err);
return new (Importer.getToContext()) UnaryOperator( return UnaryOperator::Create(
ToSubExpr, E->getOpcode(), ToType, E->getValueKind(), E->getObjectKind(), Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType,
ToOperatorLoc, E->canOverflow()); E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(),
E->getFPFeatures(Importer.getFromContext().getLangOpts()));
} }
ExpectedStmt ExpectedStmt

View File

@ -1358,7 +1358,8 @@ CallExpr *CallExpr::CreateTemporary(void *Mem, Expr *Fn, QualType Ty,
assert(!(reinterpret_cast<uintptr_t>(Mem) % alignof(CallExpr)) && assert(!(reinterpret_cast<uintptr_t>(Mem) % alignof(CallExpr)) &&
"Misaligned memory in CallExpr::CreateTemporary!"); "Misaligned memory in CallExpr::CreateTemporary!");
return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty, return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty,
VK, RParenLoc, /*MinNumArgs=*/0, UsesADL); VK, RParenLoc,
/*MinNumArgs=*/0, UsesADL);
} }
CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
@ -4445,6 +4446,38 @@ CompoundAssignOperator *CompoundAssignOperator::Create(
CompLHSType, CompResultType); CompLHSType, CompResultType);
} }
UnaryOperator *UnaryOperator::CreateEmpty(const ASTContext &C,
bool hasFPFeatures) {
void *Mem = C.Allocate(totalSizeToAlloc<FPOptions>(hasFPFeatures),
alignof(UnaryOperator));
return new (Mem) UnaryOperator(hasFPFeatures, EmptyShell());
}
UnaryOperator::UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc,
QualType type, ExprValueKind VK, ExprObjectKind OK,
SourceLocation l, bool CanOverflow,
FPOptions FPFeatures)
: Expr(UnaryOperatorClass, type, VK, OK), Val(input) {
UnaryOperatorBits.Opc = opc;
UnaryOperatorBits.CanOverflow = CanOverflow;
UnaryOperatorBits.Loc = l;
UnaryOperatorBits.HasFPFeatures =
FPFeatures.requiresTrailingStorage(Ctx.getLangOpts());
setDependence(computeDependence(this));
}
UnaryOperator *UnaryOperator::Create(const ASTContext &C, Expr *input,
Opcode opc, QualType type,
ExprValueKind VK, ExprObjectKind OK,
SourceLocation l, bool CanOverflow,
FPOptions FPFeatures) {
bool HasFPFeatures = FPFeatures.requiresTrailingStorage(C.getLangOpts());
unsigned Size = totalSizeToAlloc<FPOptions>(HasFPFeatures);
void *Mem = C.Allocate(Size, alignof(UnaryOperator));
return new (Mem)
UnaryOperator(C, input, opc, type, VK, OK, l, CanOverflow, FPFeatures);
}
const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e)) if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
e = ewc->getSubExpr(); e = ewc->getSubExpr();

View File

@ -146,9 +146,10 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(
} }
UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty, return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,
VK_LValue, OK_Ordinary, SourceLocation(), VK_LValue, OK_Ordinary, SourceLocation(),
/*CanOverflow*/ false); /*CanOverflow*/ false,
FPOptions(C.getLangOpts()));
} }
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
@ -447,15 +448,16 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
QualType DerefType = Deref->getType(); QualType DerefType = Deref->getType();
// Negation predicate. // Negation predicate.
UnaryOperator *FlagCheck = new (C) UnaryOperator( UnaryOperator *FlagCheck = UnaryOperator::Create(
C,
/* input=*/ /* input=*/
M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType, M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
CK_IntegralToBoolean), CK_IntegralToBoolean),
/* opc=*/ UO_LNot, /* opc=*/UO_LNot,
/* QualType=*/ C.IntTy, /* QualType=*/C.IntTy,
/* ExprValueKind=*/ VK_RValue, /* ExprValueKind=*/VK_RValue,
/* ExprObjectKind=*/ OK_Ordinary, SourceLocation(), /* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
/* CanOverflow*/ false); /* CanOverflow*/ false, FPOptions(C.getLangOpts()));
// Create assignment. // Create assignment.
BinaryOperator *FlagAssignment = M.makeAssignment( BinaryOperator *FlagAssignment = M.makeAssignment(
@ -518,9 +520,9 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
// (2) Create the assignment to the predicate. // (2) Create the assignment to the predicate.
Expr *DoneValue = Expr *DoneValue =
new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
VK_RValue, OK_Ordinary, SourceLocation(), C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(),
/*CanOverflow*/false); /*CanOverflow*/ false, FPOptions(C.getLangOpts()));
BinaryOperator *B = BinaryOperator *B =
M.makeAssignment( M.makeAssignment(

View File

@ -217,7 +217,14 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions. /// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
static void updateFastMathFlags(llvm::FastMathFlags &FMF, static void updateFastMathFlags(llvm::FastMathFlags &FMF,
FPOptions FPFeatures) { FPOptions FPFeatures) {
FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement()); FMF.setAllowReassoc(FPFeatures.allowAssociativeMath());
FMF.setNoNaNs(FPFeatures.noHonorNaNs());
FMF.setNoInfs(FPFeatures.noHonorInfs());
FMF.setNoSignedZeros(FPFeatures.noSignedZeros());
FMF.setAllowReciprocal(FPFeatures.allowReciprocalMath());
FMF.setApproxFunc(FPFeatures.allowApproximateFunctions());
FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement() ||
FPFeatures.allowFPContractWithinStatement());
} }
/// Propagate fast-math flags from \p Op to the instruction in \p V. /// Propagate fast-math flags from \p Op to the instruction in \p V.
@ -230,6 +237,25 @@ static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) {
return V; return V;
} }
static void setBuilderFlagsFromFPFeatures(CGBuilderTy &Builder,
CodeGenFunction &CGF,
FPOptions FPFeatures) {
auto NewRoundingBehavior = FPFeatures.getRoundingMode();
Builder.setDefaultConstrainedRounding(NewRoundingBehavior);
auto NewExceptionBehavior =
ToConstrainedExceptMD(FPFeatures.getExceptionMode());
Builder.setDefaultConstrainedExcept(NewExceptionBehavior);
auto FMF = Builder.getFastMathFlags();
updateFastMathFlags(FMF, FPFeatures);
Builder.setFastMathFlags(FMF);
assert((CGF.CurFuncDecl == nullptr || Builder.getIsFPConstrained() ||
isa<CXXConstructorDecl>(CGF.CurFuncDecl) ||
isa<CXXDestructorDecl>(CGF.CurFuncDecl) ||
(NewExceptionBehavior == llvm::fp::ebIgnore &&
NewRoundingBehavior == llvm::RoundingMode::NearestTiesToEven)) &&
"FPConstrained should be enabled on entire function");
}
class ScalarExprEmitter class ScalarExprEmitter
: public StmtVisitor<ScalarExprEmitter, Value*> { : public StmtVisitor<ScalarExprEmitter, Value*> {
CodeGenFunction &CGF; CodeGenFunction &CGF;
@ -744,6 +770,9 @@ public:
return EmitOverflowCheckedBinOp(Ops); return EmitOverflowCheckedBinOp(Ops);
if (Ops.LHS->getType()->isFPOrFPVectorTy()) { if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
// Preserve the old values
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF, Ops.FPFeatures);
Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
return propagateFMFlags(V, Ops); return propagateFMFlags(V, Ops);
} }
@ -2333,13 +2362,14 @@ Value *ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
static BinOpInfo createBinOpInfoFromIncDec(const UnaryOperator *E, static BinOpInfo createBinOpInfoFromIncDec(const UnaryOperator *E,
llvm::Value *InVal, bool IsInc) { llvm::Value *InVal, bool IsInc,
FPOptions FPFeatures) {
BinOpInfo BinOp; BinOpInfo BinOp;
BinOp.LHS = InVal; BinOp.LHS = InVal;
BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false); BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false);
BinOp.Ty = E->getType(); BinOp.Ty = E->getType();
BinOp.Opcode = IsInc ? BO_Add : BO_Sub; BinOp.Opcode = IsInc ? BO_Add : BO_Sub;
// FIXME: once UnaryOperator carries FPFeatures, copy it here. BinOp.FPFeatures = FPFeatures;
BinOp.E = E; BinOp.E = E;
return BinOp; return BinOp;
} }
@ -2359,7 +2389,8 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
case LangOptions::SOB_Trapping: case LangOptions::SOB_Trapping:
if (!E->canOverflow()) if (!E->canOverflow())
return Builder.CreateNSWAdd(InVal, Amount, Name); return Builder.CreateNSWAdd(InVal, Amount, Name);
return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc)); return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
E, InVal, IsInc, E->getFPFeatures(CGF.getLangOpts())));
} }
llvm_unreachable("Unknown SignedOverflowBehaviorTy"); llvm_unreachable("Unknown SignedOverflowBehaviorTy");
} }
@ -2505,8 +2536,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
value = EmitIncDecConsiderOverflowBehavior(E, value, isInc); value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
} else if (E->canOverflow() && type->isUnsignedIntegerType() && } else if (E->canOverflow() && type->isUnsignedIntegerType() &&
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) { CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
value = value = EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc)); E, value, isInc, E->getFPFeatures(CGF.getLangOpts())));
} else { } else {
llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true); llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
@ -2706,7 +2737,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType()); BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
BinOp.Ty = E->getType(); BinOp.Ty = E->getType();
BinOp.Opcode = BO_Sub; BinOp.Opcode = BO_Sub;
// FIXME: once UnaryOperator carries FPFeatures, copy it here. BinOp.FPFeatures = E->getFPFeatures(CGF.getLangOpts());
BinOp.E = E; BinOp.E = E;
return EmitSub(BinOp); return EmitSub(BinOp);
} }
@ -2723,9 +2754,12 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
Value *Oper = Visit(E->getSubExpr()); Value *Oper = Visit(E->getSubExpr());
Value *Zero = llvm::Constant::getNullValue(Oper->getType()); Value *Zero = llvm::Constant::getNullValue(Oper->getType());
Value *Result; Value *Result;
if (Oper->getType()->isFPOrFPVectorTy()) if (Oper->getType()->isFPOrFPVectorTy()) {
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF,
E->getFPFeatures(CGF.getLangOpts()));
Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp"); Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp");
else } else
Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp"); Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext"); return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
} }
@ -3134,7 +3168,10 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
} }
if (Ops.LHS->getType()->isFPOrFPVectorTy()) { if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); llvm::Value *Val;
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF, Ops.FPFeatures);
Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
if (CGF.getLangOpts().OpenCL && if (CGF.getLangOpts().OpenCL &&
!CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) { !CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) {
// OpenCL v1.1 s7.4: minimum accuracy of single precision / is 2.5ulp // OpenCL v1.1 s7.4: minimum accuracy of single precision / is 2.5ulp
@ -3506,6 +3543,8 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
return EmitOverflowCheckedBinOp(op); return EmitOverflowCheckedBinOp(op);
if (op.LHS->getType()->isFPOrFPVectorTy()) { if (op.LHS->getType()->isFPOrFPVectorTy()) {
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures);
// Try to form an fmuladd. // Try to form an fmuladd.
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder)) if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
return FMulAdd; return FMulAdd;
@ -3688,6 +3727,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
return EmitOverflowCheckedBinOp(op); return EmitOverflowCheckedBinOp(op);
if (op.LHS->getType()->isFPOrFPVectorTy()) { if (op.LHS->getType()->isFPOrFPVectorTy()) {
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures);
// Try to form an fmuladd. // Try to form an fmuladd.
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true)) if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
return FMulAdd; return FMulAdd;
@ -4014,6 +4055,8 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
if (BOInfo.isFixedPointOp()) { if (BOInfo.isFixedPointOp()) {
Result = EmitFixedPointBinOp(BOInfo); Result = EmitFixedPointBinOp(BOInfo);
} else if (LHS->getType()->isFPOrFPVectorTy()) { } else if (LHS->getType()->isFPOrFPVectorTy()) {
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF, BOInfo.FPFeatures);
if (!IsSignaling) if (!IsSignaling)
Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp"); Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
else else
@ -4166,6 +4209,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
Value *RHS = Visit(E->getRHS()); Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
if (LHS->getType()->isFPOrFPVectorTy()) { if (LHS->getType()->isFPOrFPVectorTy()) {
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF,
E->getFPFeatures(CGF.getLangOpts()));
LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
} else { } else {
@ -4250,6 +4296,9 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
Value *RHS = Visit(E->getRHS()); Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
if (LHS->getType()->isFPOrFPVectorTy()) { if (LHS->getType()->isFPOrFPVectorTy()) {
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
setBuilderFlagsFromFPFeatures(Builder, CGF,
E->getFPFeatures(CGF.getLangOpts()));
LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
} else { } else {

View File

@ -3556,17 +3556,17 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
StartFunction(FD, ReturnTy, Fn, FI, args); StartFunction(FD, ReturnTy, Fn, FI, args);
DeclRefExpr DstExpr(getContext(), &DstDecl, false, DestTy, VK_RValue, DeclRefExpr DstExpr(C, &DstDecl, false, DestTy, VK_RValue, SourceLocation());
SourceLocation()); UnaryOperator *DST = UnaryOperator::Create(
UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(), C, &DstExpr, UO_Deref, DestTy->getPointeeType(), VK_LValue, OK_Ordinary,
VK_LValue, OK_Ordinary, SourceLocation(), false); SourceLocation(), false, FPOptions(C.getLangOpts()));
DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue, DeclRefExpr SrcExpr(C, &SrcDecl, false, SrcTy, VK_RValue, SourceLocation());
SourceLocation()); UnaryOperator *SRC = UnaryOperator::Create(
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(), C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
VK_LValue, OK_Ordinary, SourceLocation(), false); SourceLocation(), false, FPOptions(C.getLangOpts()));
Expr *Args[2] = { &DST, &SRC }; Expr *Args[2] = {DST, SRC};
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment()); CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(), C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
@ -3642,14 +3642,15 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue, DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
SourceLocation()); SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(), UnaryOperator *SRC = UnaryOperator::Create(
VK_LValue, OK_Ordinary, SourceLocation(), false); C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
SourceLocation(), false, FPOptions(C.getLangOpts()));
CXXConstructExpr *CXXConstExpr = CXXConstructExpr *CXXConstExpr =
cast<CXXConstructExpr>(PID->getGetterCXXConstructor()); cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
SmallVector<Expr*, 4> ConstructorArgs; SmallVector<Expr*, 4> ConstructorArgs;
ConstructorArgs.push_back(&SRC); ConstructorArgs.push_back(SRC);
ConstructorArgs.append(std::next(CXXConstExpr->arg_begin()), ConstructorArgs.append(std::next(CXXConstExpr->arg_begin()),
CXXConstExpr->arg_end()); CXXConstExpr->arg_end());

View File

@ -3055,8 +3055,9 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary, C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary,
S.getBeginLoc(), FPOptions(C.getLangOpts())); S.getBeginLoc(), FPOptions(C.getLangOpts()));
// Increment for loop counter. // Increment for loop counter.
UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary, UnaryOperator *Inc = UnaryOperator::Create(
S.getBeginLoc(), true); C, &IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
S.getBeginLoc(), true, FPOptions(C.getLangOpts()));
auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) { auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
// Iterate through all sections and emit a switch construct: // Iterate through all sections and emit a switch construct:
// switch (IV) { // switch (IV) {
@ -3126,7 +3127,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
// IV = LB; // IV = LB;
CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV); CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
// while (idx <= UB) { BODY; ++idx; } // while (idx <= UB) { BODY; ++idx; }
CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, &Inc, BodyGen, CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, Inc, BodyGen,
[](CodeGenFunction &) {}); [](CodeGenFunction &) {});
// Tell the runtime we are done. // Tell the runtime we are done.
auto &&CodeGen = [&S](CodeGenFunction &CGF) { auto &&CodeGen = [&S](CodeGenFunction &CGF) {

View File

@ -117,8 +117,8 @@ CodeGenFunction::~CodeGenFunction() {
// Map the LangOption for exception behavior into // Map the LangOption for exception behavior into
// the corresponding enum in the IR. // the corresponding enum in the IR.
static llvm::fp::ExceptionBehavior ToConstrainedExceptMD( llvm::fp::ExceptionBehavior
LangOptions::FPExceptionModeKind Kind) { clang::ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind) {
switch (Kind) { switch (Kind) {
case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore; case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore;
@ -133,15 +133,10 @@ void CodeGenFunction::SetFPModel() {
auto fpExceptionBehavior = ToConstrainedExceptMD( auto fpExceptionBehavior = ToConstrainedExceptMD(
getLangOpts().getFPExceptionMode()); getLangOpts().getFPExceptionMode());
if (fpExceptionBehavior == llvm::fp::ebIgnore && Builder.setDefaultConstrainedRounding(RM);
RM == llvm::RoundingMode::NearestTiesToEven) Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
// Constrained intrinsics are not used. Builder.setIsFPConstrained(fpExceptionBehavior != llvm::fp::ebIgnore ||
; RM != llvm::RoundingMode::NearestTiesToEven);
else {
Builder.setIsFPConstrained(true);
Builder.setDefaultConstrainedRounding(RM);
Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
}
} }
CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
@ -919,9 +914,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
Fn->addFnAttr(llvm::Attribute::NoRecurse); Fn->addFnAttr(llvm::Attribute::NoRecurse);
} }
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
Builder.setIsFPConstrained(FD->usesFPIntrin());
if (FD->usesFPIntrin()) if (FD->usesFPIntrin())
Fn->addFnAttr(llvm::Attribute::StrictFP); Fn->addFnAttr(llvm::Attribute::StrictFP);
}
// If a custom alignment is used, force realigning to this alignment on // If a custom alignment is used, force realigning to this alignment on
// any main function which certainly will need it. // any main function which certainly will need it.

View File

@ -4575,6 +4575,11 @@ inline llvm::Value *DominatingLLVMValue::restore(CodeGenFunction &CGF,
} }
} // end namespace CodeGen } // end namespace CodeGen
// Map the LangOption for floating point exception behavior into
// the corresponding enum in the IR.
llvm::fp::ExceptionBehavior
ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind);
} // end namespace clang } // end namespace clang
#endif #endif

View File

@ -2455,7 +2455,7 @@ static const StringRef GetInputKindName(InputKind IK) {
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
const TargetOptions &TargetOpts, const TargetOptions &TargetOpts,
PreprocessorOptions &PPOpts, PreprocessorOptions &PPOpts, CodeGenOptions &CGOpts,
DiagnosticsEngine &Diags) { DiagnosticsEngine &Diags) {
// FIXME: Cleanup per-file based stuff. // FIXME: Cleanup per-file based stuff.
LangStandard::Kind LangStd = LangStandard::lang_unspecified; LangStandard::Kind LangStd = LangStandard::lang_unspecified;
@ -3187,6 +3187,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) || Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math); Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.AllowFPReassoc = Opts.FastMath || CGOpts.Reassociate;
Opts.NoHonorNaNs =
Opts.FastMath || CGOpts.NoNaNsFPMath || Opts.FiniteMathOnly;
Opts.NoHonorInfs =
Opts.FastMath || CGOpts.NoInfsFPMath || Opts.FiniteMathOnly;
Opts.NoSignedZero = Opts.FastMath || CGOpts.NoSignedZeros;
Opts.AllowRecip = Opts.FastMath || CGOpts.ReciprocalMath;
// Currently there's no clang option to enable this individually
Opts.ApproxFunc = Opts.FastMath;
if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
StringRef Val = A->getValue(); StringRef Val = A->getValue();
@ -3640,7 +3649,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// Other LangOpts are only initialized when the input is not AST or LLVM IR. // Other LangOpts are only initialized when the input is not AST or LLVM IR.
// FIXME: Should we really be calling this for an Language::Asm input? // FIXME: Should we really be calling this for an Language::Asm input?
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(), ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
Res.getPreprocessorOpts(), Diags); Res.getPreprocessorOpts(), Res.getCodeGenOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC) if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1; LangOpts.ObjCExceptions = 1;
if (T.isOSDarwin() && DashX.isPreprocessed()) { if (T.isOSDarwin() && DashX.isPreprocessed()) {

View File

@ -2587,9 +2587,10 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
strType, nullptr, SC_Static); strType, nullptr, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr *DRE = new (Context)
DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation()); DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
Expr *Unop = new (Context) Expr *Unop = UnaryOperator::Create(
UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
VK_RValue, OK_Ordinary, SourceLocation(), false); Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false, FPOptions(Context->getLangOpts()));
// cast to NSConstantString * // cast to NSConstantString *
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
CK_CPointerToObjCPointerCast, Unop); CK_CPointerToObjCPointerCast, Unop);
@ -3283,10 +3284,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// we need the cast below. For example: // we need the cast below. For example:
// (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
// //
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = UnaryOperator::Create(
Context->getPointerType(SuperRep->getType()), const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
VK_RValue, OK_Ordinary, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false); SourceLocation(), false, FPOptions(Context->getLangOpts()));
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -3301,10 +3302,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
superType, VK_LValue, superType, VK_LValue,
ILE, false); ILE, false);
// struct __rw_objc_super * // struct __rw_objc_super *
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = UnaryOperator::Create(
Context->getPointerType(SuperRep->getType()), const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
VK_RValue, OK_Ordinary, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false); SourceLocation(), false, FPOptions(Context->getLangOpts()));
} }
MsgExprs.push_back(SuperRep); MsgExprs.push_back(SuperRep);
break; break;
@ -3378,10 +3379,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// we need the cast below. For example: // we need the cast below. For example:
// (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
// //
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = UnaryOperator::Create(
Context->getPointerType(SuperRep->getType()), const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
VK_RValue, OK_Ordinary, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false); SourceLocation(), false, FPOptions(Context->getLangOpts()));
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -4705,9 +4706,10 @@ Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
if (VarDecl *Var = dyn_cast<VarDecl>(VD)) if (VarDecl *Var = dyn_cast<VarDecl>(VD))
if (!ImportedLocalExternalDecls.count(Var)) if (!ImportedLocalExternalDecls.count(Var))
return DRE; return DRE;
Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), DRE,
VK_LValue, OK_Ordinary, UO_Deref, DRE->getType(), VK_LValue,
DRE->getLocation(), false); OK_Ordinary, DRE->getLocation(), false,
FPOptions(Context->getLangOpts()));
// Need parens to enforce precedence. // Need parens to enforce precedence.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
Exp); Exp);
@ -5293,11 +5295,12 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
VarDecl *NewVD = VarDecl::Create( VarDecl *NewVD = VarDecl::Create(
*Context, TUDecl, SourceLocation(), SourceLocation(), *Context, TUDecl, SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static); &Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static);
UnaryOperator *DescRefExpr = new (Context) UnaryOperator( UnaryOperator *DescRefExpr = UnaryOperator::Create(
const_cast<ASTContext &>(*Context),
new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy, new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy,
VK_LValue, SourceLocation()), VK_LValue, SourceLocation()),
UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue, UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
OK_Ordinary, SourceLocation(), false); OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts()));
InitExprs.push_back(DescRefExpr); InitExprs.push_back(DescRefExpr);
// Add initializers for any closure decl refs. // Add initializers for any closure decl refs.
@ -5314,9 +5317,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (HasLocalVariableExternalStorage(*I)) { if (HasLocalVariableExternalStorage(*I)) {
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
OK_Ordinary, SourceLocation(), UO_AddrOf, QT, VK_RValue, OK_Ordinary,
false); SourceLocation(), false,
FPOptions(Context->getLangOpts()));
} }
} else if (isTopLevelBlockPointerType((*I)->getType())) { } else if (isTopLevelBlockPointerType((*I)->getType())) {
FD = SynthBlockInitFunctionDecl((*I)->getName()); FD = SynthBlockInitFunctionDecl((*I)->getName());
@ -5331,9 +5335,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (HasLocalVariableExternalStorage(*I)) { if (HasLocalVariableExternalStorage(*I)) {
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
OK_Ordinary, SourceLocation(), UO_AddrOf, QT, VK_RValue, OK_Ordinary,
false); SourceLocation(), false,
FPOptions(Context->getLangOpts()));
} }
} }
@ -5371,10 +5376,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
// captured nested byref variable has its address passed. Do not take // captured nested byref variable has its address passed. Do not take
// its address again. // its address again.
if (!isNestedCapturedVar) if (!isNestedCapturedVar)
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, Exp = UnaryOperator::Create(
Context->getPointerType(Exp->getType()), const_cast<ASTContext &>(*Context), Exp, UO_AddrOf,
VK_RValue, OK_Ordinary, SourceLocation(), Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary,
false); SourceLocation(), false, FPOptions(Context->getLangOpts()));
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
InitExprs.push_back(Exp); InitExprs.push_back(Exp);
} }
@ -5398,9 +5403,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
NewRep = DRE; NewRep = DRE;
} }
NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, NewRep = UnaryOperator::Create(
Context->getPointerType(NewRep->getType()), const_cast<ASTContext &>(*Context), NewRep, UO_AddrOf,
VK_RValue, OK_Ordinary, SourceLocation(), false); Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false, FPOptions(Context->getLangOpts()));
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
NewRep); NewRep);
// Put Paren around the call. // Put Paren around the call.
@ -7539,10 +7545,10 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
CK_BitCast, CK_BitCast,
PE); PE);
Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context),
Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT, castExpr, UO_Deref, IvarT, VK_LValue,
VK_LValue, OK_Ordinary, OK_Ordinary, SourceLocation(), false,
SourceLocation(), false); FPOptions(Context->getLangOpts()));
PE = new (Context) ParenExpr(OldRange.getBegin(), PE = new (Context) ParenExpr(OldRange.getBegin(),
OldRange.getEnd(), OldRange.getEnd(),
Exp); Exp);

View File

@ -2514,9 +2514,10 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
strType, nullptr, SC_Static); strType, nullptr, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr *DRE = new (Context)
DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation()); DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
Expr *Unop = new (Context) Expr *Unop = UnaryOperator::Create(
UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
VK_RValue, OK_Ordinary, SourceLocation(), false); Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false, FPOptions(Context->getLangOpts()));
// cast to NSConstantString * // cast to NSConstantString *
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
CK_CPointerToObjCPointerCast, Unop); CK_CPointerToObjCPointerCast, Unop);
@ -2714,10 +2715,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// we need the cast below. For example: // we need the cast below. For example:
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
// //
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = UnaryOperator::Create(
Context->getPointerType(SuperRep->getType()), const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
VK_RValue, OK_Ordinary, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false); SourceLocation(), false, FPOptions(Context->getLangOpts()));
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -2732,10 +2733,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
superType, VK_LValue, superType, VK_LValue,
ILE, false); ILE, false);
// struct objc_super * // struct objc_super *
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = UnaryOperator::Create(
Context->getPointerType(SuperRep->getType()), const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
VK_RValue, OK_Ordinary, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false); SourceLocation(), false, FPOptions(Context->getLangOpts()));
} }
MsgExprs.push_back(SuperRep); MsgExprs.push_back(SuperRep);
break; break;
@ -2809,10 +2810,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// we need the cast below. For example: // we need the cast below. For example:
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
// //
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = UnaryOperator::Create(
Context->getPointerType(SuperRep->getType()), const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
VK_RValue, OK_Ordinary, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false); SourceLocation(), false, FPOptions(Context->getLangOpts()));
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -3048,9 +3049,10 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
nullptr, SC_Extern); nullptr, SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr( DeclRefExpr *DRE = new (Context) DeclRefExpr(
*Context, VD, false, getProtocolType(), VK_LValue, SourceLocation()); *Context, VD, false, getProtocolType(), VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, Expr *DerefExpr = UnaryOperator::Create(
Context->getPointerType(DRE->getType()), const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
VK_RValue, OK_Ordinary, SourceLocation(), false); Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false, FPOptions(Context->getLangOpts()));
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
CK_BitCast, CK_BitCast,
DerefExpr); DerefExpr);
@ -3875,9 +3877,10 @@ Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
if (VarDecl *Var = dyn_cast<VarDecl>(VD)) if (VarDecl *Var = dyn_cast<VarDecl>(VD))
if (!ImportedLocalExternalDecls.count(Var)) if (!ImportedLocalExternalDecls.count(Var))
return DRE; return DRE;
Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), DRE,
VK_LValue, OK_Ordinary, UO_Deref, DRE->getType(), VK_LValue,
DRE->getLocation(), false); OK_Ordinary, DRE->getLocation(), false,
FPOptions(Context->getLangOpts()));
// Need parens to enforce precedence. // Need parens to enforce precedence.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
Exp); Exp);
@ -4432,11 +4435,12 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
VarDecl *NewVD = VarDecl::Create( VarDecl *NewVD = VarDecl::Create(
*Context, TUDecl, SourceLocation(), SourceLocation(), *Context, TUDecl, SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static); &Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static);
UnaryOperator *DescRefExpr = new (Context) UnaryOperator( UnaryOperator *DescRefExpr = UnaryOperator::Create(
const_cast<ASTContext &>(*Context),
new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy, new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy,
VK_LValue, SourceLocation()), VK_LValue, SourceLocation()),
UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue, UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
OK_Ordinary, SourceLocation(), false); OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts()));
InitExprs.push_back(DescRefExpr); InitExprs.push_back(DescRefExpr);
// Add initializers for any closure decl refs. // Add initializers for any closure decl refs.
@ -4453,9 +4457,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (HasLocalVariableExternalStorage(*I)) { if (HasLocalVariableExternalStorage(*I)) {
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
OK_Ordinary, SourceLocation(), UO_AddrOf, QT, VK_RValue, OK_Ordinary,
false); SourceLocation(), false,
FPOptions(Context->getLangOpts()));
} }
} else if (isTopLevelBlockPointerType((*I)->getType())) { } else if (isTopLevelBlockPointerType((*I)->getType())) {
FD = SynthBlockInitFunctionDecl((*I)->getName()); FD = SynthBlockInitFunctionDecl((*I)->getName());
@ -4470,9 +4475,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (HasLocalVariableExternalStorage(*I)) { if (HasLocalVariableExternalStorage(*I)) {
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
OK_Ordinary, SourceLocation(), UO_AddrOf, QT, VK_RValue, OK_Ordinary,
false); SourceLocation(), false,
FPOptions(Context->getLangOpts()));
} }
} }
InitExprs.push_back(Exp); InitExprs.push_back(Exp);
@ -4509,9 +4515,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
// captured nested byref variable has its address passed. Do not take // captured nested byref variable has its address passed. Do not take
// its address again. // its address again.
if (!isNestedCapturedVar) if (!isNestedCapturedVar)
Exp = new (Context) UnaryOperator( Exp = UnaryOperator::Create(
Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue, const_cast<ASTContext &>(*Context), Exp, UO_AddrOf,
OK_Ordinary, SourceLocation(), false); Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false, FPOptions(Context->getLangOpts()));
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
InitExprs.push_back(Exp); InitExprs.push_back(Exp);
} }
@ -4527,9 +4534,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
} }
NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue, NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue,
SourceLocation()); SourceLocation());
NewRep = new (Context) UnaryOperator( NewRep = UnaryOperator::Create(
NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), VK_RValue, const_cast<ASTContext &>(*Context), NewRep, UO_AddrOf,
OK_Ordinary, SourceLocation(), false); Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary,
SourceLocation(), false, FPOptions(Context->getLangOpts()));
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
NewRep); NewRep);
BlockDeclRefs.clear(); BlockDeclRefs.clear();

View File

@ -3365,6 +3365,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// are complete and we can parse the delayed portions of method // are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions, along with any // declarations and the lexed inline method definitions, along with any
// delayed attributes. // delayed attributes.
// Save the state of Sema.FPFeatures, and change the setting
// to the levels specified on the command line. Previous level
// will be restored when the RAII object is destroyed.
Sema::FPFeaturesStateRAII SaveFPFeaturesState(Actions);
FPOptions fpOptions(getLangOpts());
Actions.CurFPFeatures.getFromOpaqueInt(fpOptions.getAsOpaqueInt());
SourceLocation SavedPrevTokLocation = PrevTokLocation; SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedPragmas(getCurrentClass()); ParseLexedPragmas(getCurrentClass());
ParseLexedAttributes(getCurrentClass()); ParseLexedAttributes(getCurrentClass());

View File

@ -184,6 +184,13 @@ private:
Sema &Actions; Sema &Actions;
}; };
struct PragmaFloatControlHandler : public PragmaHandler {
PragmaFloatControlHandler(Sema &Actions)
: PragmaHandler("float_control") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &FirstToken) override;
};
struct PragmaMSPointersToMembers : public PragmaHandler { struct PragmaMSPointersToMembers : public PragmaHandler {
explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {} explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
@ -334,6 +341,8 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler(MSCommentHandler.get()); PP.AddPragmaHandler(MSCommentHandler.get());
} }
FloatControlHandler = std::make_unique<PragmaFloatControlHandler>(Actions);
PP.AddPragmaHandler(FloatControlHandler.get());
if (getLangOpts().MicrosoftExt) { if (getLangOpts().MicrosoftExt) {
MSDetectMismatchHandler = MSDetectMismatchHandler =
std::make_unique<PragmaDetectMismatchHandler>(Actions); std::make_unique<PragmaDetectMismatchHandler>(Actions);
@ -438,6 +447,8 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler("clang", PCSectionHandler.get()); PP.RemovePragmaHandler("clang", PCSectionHandler.get());
PCSectionHandler.reset(); PCSectionHandler.reset();
PP.RemovePragmaHandler(FloatControlHandler.get());
FloatControlHandler.reset();
if (getLangOpts().MicrosoftExt) { if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSDetectMismatchHandler.get()); PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset(); MSDetectMismatchHandler.reset();
@ -646,6 +657,22 @@ void Parser::HandlePragmaFPContract() {
ConsumeAnnotationToken(); ConsumeAnnotationToken();
} }
void Parser::HandlePragmaFloatControl() {
assert(Tok.is(tok::annot_pragma_float_control));
// The value that is held on the PragmaFloatControlStack encodes
// the PragmaFloatControl kind and the MSStackAction kind
// into a single 32-bit word. The MsStackAction is the high 16 bits
// and the FloatControl is the lower 16 bits. Use shift and bit-and
// to decode the parts.
uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
Sema::PragmaMsStackAction Action =
static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
PragmaFloatControlKind Kind = PragmaFloatControlKind(Value & 0xFFFF);
SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaFloatControl(PragmaLoc, Action, Kind);
}
void Parser::HandlePragmaFEnvAccess() { void Parser::HandlePragmaFEnvAccess() {
assert(Tok.is(tok::annot_pragma_fenv_access)); assert(Tok.is(tok::annot_pragma_fenv_access));
tok::OnOffSwitch OOS = tok::OnOffSwitch OOS =
@ -665,8 +692,8 @@ void Parser::HandlePragmaFEnvAccess() {
break; break;
} }
Actions.ActOnPragmaFEnvAccess(FPC); SourceLocation PragmaLoc = ConsumeAnnotationToken();
ConsumeAnnotationToken(); Actions.ActOnPragmaFEnvAccess(PragmaLoc, FPC);
} }
@ -2489,6 +2516,129 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP,
PP.EnterToken(AnnotTok, /*IsReinject*/ false); PP.EnterToken(AnnotTok, /*IsReinject*/ false);
} }
/// Handle the \#pragma float_control extension.
///
/// The syntax is:
/// \code
/// #pragma float_control(keyword[, setting] [,push])
/// \endcode
/// Where 'keyword' and 'setting' are identifiers.
// 'keyword' can be: precise, except, push, pop
// 'setting' can be: on, off
/// The optional arguments 'setting' and 'push' are supported only
/// when the keyword is 'precise' or 'except'.
void PragmaFloatControlHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducer Introducer,
Token &Tok) {
Sema::PragmaMsStackAction Action = Sema::PSK_Set;
SourceLocation FloatControlLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(FloatControlLoc, diag::err_expected) << tok::l_paren;
return;
}
// Read the identifier.
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
}
// Verify that this is one of the float control options.
IdentifierInfo *II = Tok.getIdentifierInfo();
PragmaFloatControlKind Kind =
llvm::StringSwitch<PragmaFloatControlKind>(II->getName())
.Case("precise", PFC_Precise)
.Case("except", PFC_Except)
.Case("push", PFC_Push)
.Case("pop", PFC_Pop)
.Default(PFC_Unknown);
PP.Lex(Tok); // the identifier
if (Kind == PFC_Unknown) {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
} else if (Kind == PFC_Push || Kind == PFC_Pop) {
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
}
PP.Lex(Tok); // Eat the r_paren
Action = (Kind == PFC_Pop) ? Sema::PSK_Pop : Sema::PSK_Push;
} else {
if (Tok.is(tok::r_paren))
// Selecting Precise or Except
PP.Lex(Tok); // the r_paren
else if (Tok.isNot(tok::comma)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
} else {
PP.Lex(Tok); // ,
if (!Tok.isAnyIdentifier()) {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
}
StringRef PushOnOff = Tok.getIdentifierInfo()->getName();
if (PushOnOff == "on")
// Kind is set correctly
;
else if (PushOnOff == "off") {
if (Kind == PFC_Precise)
Kind = PFC_NoPrecise;
if (Kind == PFC_Except)
Kind = PFC_NoExcept;
} else if (PushOnOff == "push") {
Action = Sema::PSK_Push_Set;
} else {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
}
PP.Lex(Tok); // the identifier
if (Tok.is(tok::comma)) {
PP.Lex(Tok); // ,
if (!Tok.isAnyIdentifier()) {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
}
StringRef ExpectedPush = Tok.getIdentifierInfo()->getName();
if (ExpectedPush == "push") {
Action = Sema::PSK_Push_Set;
} else {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
}
PP.Lex(Tok); // the push identifier
}
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
return;
}
PP.Lex(Tok); // the r_paren
}
}
SourceLocation EndLoc = Tok.getLocation();
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "float_control";
return;
}
// Note: there is no accomodation for PP callback for this pragma.
// Enter the annotation.
auto TokenArray = std::make_unique<Token[]>(1);
TokenArray[0].startToken();
TokenArray[0].setKind(tok::annot_pragma_float_control);
TokenArray[0].setLocation(FloatControlLoc);
TokenArray[0].setAnnotationEndLoc(EndLoc);
// Create an encoding of Action and Value by shifting the Action into
// the high 16 bits then union with the Kind.
TokenArray[0].setAnnotationValue(reinterpret_cast<void *>(
static_cast<uintptr_t>((Action << 16) | (Kind & 0xFFFF))));
PP.EnterTokenStream(std::move(TokenArray), 1,
/*DisableMacroExpansion=*/false, /*IsReinject=*/false);
}
/// Handle the Microsoft \#pragma detect_mismatch extension. /// Handle the Microsoft \#pragma detect_mismatch extension.
/// ///
/// The syntax is: /// The syntax is:
@ -2749,7 +2899,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
auto *AnnotValue = new (PP.getPreprocessorAllocator()) auto *AnnotValue = new (PP.getPreprocessorAllocator())
TokFPAnnotValue{*FlagKind, *FlagValue}; TokFPAnnotValue{*FlagKind, *FlagValue};
// Generate the loop hint token. // Generate the fp annotation token.
Token FPTok; Token FPTok;
FPTok.startToken(); FPTok.startToken();
FPTok.setKind(tok::annot_pragma_fp); FPTok.setKind(tok::annot_pragma_fp);

View File

@ -354,13 +354,13 @@ Retry:
case tok::annot_pragma_fp_contract: case tok::annot_pragma_fp_contract:
ProhibitAttributes(Attrs); ProhibitAttributes(Attrs);
Diag(Tok, diag::err_pragma_fp_contract_scope); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract";
ConsumeAnnotationToken(); ConsumeAnnotationToken();
return StmtError(); return StmtError();
case tok::annot_pragma_fp: case tok::annot_pragma_fp:
ProhibitAttributes(Attrs); ProhibitAttributes(Attrs);
Diag(Tok, diag::err_pragma_fp_scope); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp";
ConsumeAnnotationToken(); ConsumeAnnotationToken();
return StmtError(); return StmtError();
@ -369,6 +369,12 @@ Retry:
HandlePragmaFEnvAccess(); HandlePragmaFEnvAccess();
return StmtEmpty(); return StmtEmpty();
case tok::annot_pragma_float_control:
ProhibitAttributes(Attrs);
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control";
ConsumeAnnotationToken();
return StmtError();
case tok::annot_pragma_opencl_extension: case tok::annot_pragma_opencl_extension:
ProhibitAttributes(Attrs); ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension(); HandlePragmaOpenCLExtension();
@ -937,6 +943,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_fenv_access: case tok::annot_pragma_fenv_access:
HandlePragmaFEnvAccess(); HandlePragmaFEnvAccess();
break; break;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
break;
case tok::annot_pragma_ms_pointers_to_members: case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers(); HandlePragmaMSPointersToMembers();
break; break;

View File

@ -752,6 +752,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_fenv_access: case tok::annot_pragma_fenv_access:
HandlePragmaFEnvAccess(); HandlePragmaFEnvAccess();
return nullptr; return nullptr;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
return nullptr;
case tok::annot_pragma_fp: case tok::annot_pragma_fp:
HandlePragmaFP(); HandlePragmaFP();
break; break;

View File

@ -159,7 +159,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LangOpts.getMSPointerToMemberRepresentationMethod()), LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0), VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr), CodeSegStack(nullptr), FpPragmaStack(CurFPFeatures.getAsOpaqueInt()),
CurInitSeg(nullptr), VisContext(nullptr),
PragmaAttributeCurrentTargetDecl(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),

View File

@ -407,6 +407,65 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD)); Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
} }
void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
PragmaMsStackAction Action,
PragmaFloatControlKind Value) {
auto NewValue = FpPragmaStack.CurrentValue;
FPOptions NewFPFeatures(NewValue);
if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) &&
!CurContext->isTranslationUnit()) {
// Push and pop can only occur at file scope.
Diag(Loc, diag::err_pragma_fc_pp_scope);
return;
}
switch (Value) {
default:
llvm_unreachable("invalid pragma float_control kind");
case PFC_Precise:
CurFPFeatures.setFPPreciseEnabled(true);
NewValue = CurFPFeatures.getAsOpaqueInt();
FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
break;
case PFC_NoPrecise:
if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict)
Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept);
else if (CurFPFeatures.allowFEnvAccess())
Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv);
else
CurFPFeatures.setFPPreciseEnabled(false);
NewValue = CurFPFeatures.getAsOpaqueInt();
FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
break;
case PFC_Except:
if (!isPreciseFPEnabled())
Diag(Loc, diag::err_pragma_fc_except_requires_precise);
else
CurFPFeatures.setExceptionMode(LangOptions::FPE_Strict);
NewValue = CurFPFeatures.getAsOpaqueInt();
FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
break;
case PFC_NoExcept:
CurFPFeatures.setExceptionMode(LangOptions::FPE_Ignore);
NewValue = CurFPFeatures.getAsOpaqueInt();
FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
break;
case PFC_Push:
Action = Sema::PSK_Push_Set;
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures.getAsOpaqueInt());
break;
case PFC_Pop:
if (FpPragmaStack.Stack.empty()) {
Diag(Loc, diag::warn_pragma_pop_failed) << "float_control"
<< "stack empty";
return;
}
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures.getAsOpaqueInt());
NewValue = FpPragmaStack.CurrentValue;
CurFPFeatures.getFromOpaqueInt(NewValue);
break;
}
}
void Sema::ActOnPragmaMSPointersToMembers( void Sema::ActOnPragmaMSPointersToMembers(
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod, LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
SourceLocation PragmaLoc) { SourceLocation PragmaLoc) {
@ -948,9 +1007,16 @@ void Sema::setExceptionMode(LangOptions::FPExceptionModeKind FPE) {
CurFPFeatures.setExceptionMode(FPE); CurFPFeatures.setExceptionMode(FPE);
} }
void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) { void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc,
LangOptions::FEnvAccessModeKind FPC) {
switch (FPC) { switch (FPC) {
case LangOptions::FEA_On: case LangOptions::FEA_On:
// Verify Microsoft restriction:
// You can't enable fenv_access unless precise semantics are enabled.
// Precise semantics can be enabled either by the float_control
// pragma, or by using the /fp:precise or /fp:strict compiler options
if (!isPreciseFPEnabled())
Diag(Loc, diag::err_pragma_fenv_requires_precise);
CurFPFeatures.setAllowFEnvAccess(); CurFPFeatures.setAllowFEnvAccess();
break; break;
case LangOptions::FEA_Off: case LangOptions::FEA_Off:
@ -959,7 +1025,6 @@ void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
} }
} }
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
SourceLocation Loc) { SourceLocation Loc) {
// Visibility calculations will consider the namespace's visibility. // Visibility calculations will consider the namespace's visibility.

View File

@ -13455,13 +13455,13 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
// directly construct UnaryOperators here because semantic analysis // directly construct UnaryOperators here because semantic analysis
// does not permit us to take the address of an xvalue. // does not permit us to take the address of an xvalue.
Expr *From = FromB.build(S, Loc); Expr *From = FromB.build(S, Loc);
From = new (S.Context) UnaryOperator(From, UO_AddrOf, From = UnaryOperator::Create(
S.Context.getPointerType(From->getType()), S.Context, From, UO_AddrOf, S.Context.getPointerType(From->getType()),
VK_RValue, OK_Ordinary, Loc, false); VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatures);
Expr *To = ToB.build(S, Loc); Expr *To = ToB.build(S, Loc);
To = new (S.Context) UnaryOperator(To, UO_AddrOf, To = UnaryOperator::Create(S.Context, To, UO_AddrOf,
S.Context.getPointerType(To->getType()), S.Context.getPointerType(To->getType()), VK_RValue,
VK_RValue, OK_Ordinary, Loc, false); OK_Ordinary, Loc, false, S.CurFPFeatures);
const Type *E = T->getBaseElementTypeUnsafe(); const Type *E = T->getBaseElementTypeUnsafe();
bool NeedsCollectableMemCpy = bool NeedsCollectableMemCpy =
@ -13703,9 +13703,9 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// Create the pre-increment of the iteration variable. We can determine // Create the pre-increment of the iteration variable. We can determine
// whether the increment will overflow based on the value of the array // whether the increment will overflow based on the value of the array
// bound. // bound.
Expr *Increment = new (S.Context) Expr *Increment = UnaryOperator::Create(
UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType, S.Context, IterationVarRef.build(S, Loc), UO_PreInc, SizeType, VK_LValue,
VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue()); OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatures);
// Construct the loop that copies all elements of this array. // Construct the loop that copies all elements of this array.
return S.ActOnForStmt( return S.ActOnForStmt(

View File

@ -13662,14 +13662,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError(); return ExprError();
if (ResultTy->isRealFloatingType() &&
(getLangOpts().getFPRoundingMode() != RoundingMode::NearestTiesToEven ||
getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore))
// Mark the current function as usng floating point constrained intrinsics
if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
F->setUsesFPIntrin(true);
}
// Some of the binary operations require promoting operands of half vector to // Some of the binary operations require promoting operands of half vector to
// float vectors and truncating the result back to half vector. For now, we do // float vectors and truncating the result back to half vector. For now, we do
// this only when HalfArgsAndReturn is set (that is, when the target is arm or // this only when HalfArgsAndReturn is set (that is, when the target is arm or
@ -14319,8 +14311,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Opc != UO_AddrOf && Opc != UO_Deref) if (Opc != UO_AddrOf && Opc != UO_Deref)
CheckArrayAccess(Input.get()); CheckArrayAccess(Input.get());
auto *UO = new (Context) auto *UO = UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK,
UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow); OK, OpLoc, CanOverflow, CurFPFeatures);
if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) && if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) &&
!isa<ArrayType>(UO->getType().getDesugaredType(Context))) !isa<ArrayType>(UO->getType().getDesugaredType(Context)))

View File

@ -4427,9 +4427,9 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
} else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) { } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
assert(uo->getOpcode() == UO_Extension); assert(uo->getOpcode() == UO_Extension);
Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
return new (Context) return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(),
UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(), sub->getValueKind(), sub->getObjectKind(),
sub->getObjectKind(), uo->getOperatorLoc(), false); uo->getOperatorLoc(), false, CurFPFeatures);
} else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
assert(!gse->isResultDependent()); assert(!gse->isResultDependent());

View File

@ -13001,8 +13001,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
if (Input->isTypeDependent()) { if (Input->isTypeDependent()) {
if (Fns.empty()) if (Fns.empty())
return new (Context) UnaryOperator(Input, Opc, Context.DependentTy, return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy,
VK_RValue, OK_Ordinary, OpLoc, false); VK_RValue, OK_Ordinary, OpLoc, false,
CurFPFeatures);
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create( UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(
@ -14802,9 +14803,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (Context.getTargetInfo().getCXXABI().isMicrosoft()) if (Context.getTargetInfo().getCXXABI().isMicrosoft())
(void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType); (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, return UnaryOperator::Create(
VK_RValue, OK_Ordinary, Context, SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary,
UnOp->getOperatorLoc(), false); UnOp->getOperatorLoc(), false, CurFPFeatures);
} }
} }
Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
@ -14812,10 +14813,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (SubExpr == UnOp->getSubExpr()) if (SubExpr == UnOp->getSubExpr())
return UnOp; return UnOp;
return new (Context) UnaryOperator(SubExpr, UO_AddrOf, return UnaryOperator::Create(
Context.getPointerType(SubExpr->getType()), Context, SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary, UnOp->getOperatorLoc(), false, CurFPFeatures);
UnOp->getOperatorLoc(), false);
} }
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {

View File

@ -127,12 +127,10 @@ namespace {
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) { if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
assert(uop->getOpcode() == UO_Extension); assert(uop->getOpcode() == UO_Extension);
e = rebuild(uop->getSubExpr()); e = rebuild(uop->getSubExpr());
return new (S.Context) UnaryOperator(e, uop->getOpcode(), return UnaryOperator::Create(
uop->getType(), S.Context, e, uop->getOpcode(), uop->getType(), uop->getValueKind(),
uop->getValueKind(), uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(),
uop->getObjectKind(), S.CurFPFeatures);
uop->getOperatorLoc(),
uop->canOverflow());
} }
if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
@ -526,12 +524,14 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
(result.get()->isTypeDependent() || CanCaptureValue(result.get()))) (result.get()->isTypeDependent() || CanCaptureValue(result.get())))
setResultToLastSemantic(); setResultToLastSemantic();
UnaryOperator *syntactic = new (S.Context) UnaryOperator( UnaryOperator *syntactic =
syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc, UnaryOperator::Create(S.Context, syntacticOp, opcode, resultType,
!resultType->isDependentType() VK_LValue, OK_Ordinary, opcLoc,
? S.Context.getTypeSize(resultType) >= !resultType->isDependentType()
S.Context.getTypeSize(S.Context.IntTy) ? S.Context.getTypeSize(resultType) >=
: false); S.Context.getTypeSize(S.Context.IntTy)
: false,
S.CurFPFeatures);
return complete(syntactic); return complete(syntactic);
} }
@ -1551,8 +1551,9 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
UnaryOperatorKind opcode, Expr *op) { UnaryOperatorKind opcode, Expr *op) {
// Do nothing if the operand is dependent. // Do nothing if the operand is dependent.
if (op->isTypeDependent()) if (op->isTypeDependent())
return new (Context) UnaryOperator(op, opcode, Context.DependentTy, return UnaryOperator::Create(Context, op, opcode, Context.DependentTy,
VK_RValue, OK_Ordinary, opcLoc, false); VK_RValue, OK_Ordinary, opcLoc, false,
CurFPFeatures);
assert(UnaryOperator::isIncrementDecrementOp(opcode)); assert(UnaryOperator::isIncrementDecrementOp(opcode));
Expr *opaqueRef = op->IgnoreParens(); Expr *opaqueRef = op->IgnoreParens();
@ -1636,9 +1637,10 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
Expr *syntax = E->getSyntacticForm(); Expr *syntax = E->getSyntacticForm();
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) { if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
return new (Context) UnaryOperator( return UnaryOperator::Create(Context, op, uop->getOpcode(), uop->getType(),
op, uop->getOpcode(), uop->getType(), uop->getValueKind(), uop->getValueKind(), uop->getObjectKind(),
uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow()); uop->getOperatorLoc(), uop->canOverflow(),
CurFPFeatures);
} else if (CompoundAssignOperator *cop } else if (CompoundAssignOperator *cop
= dyn_cast<CompoundAssignOperator>(syntax)) { = dyn_cast<CompoundAssignOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());

View File

@ -394,6 +394,11 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) { ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size(); const unsigned NumElts = Elts.size();
// Mark the current function as usng floating point constrained intrinsics
if (getCurFPFeatures().isFPConstrained())
if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext))
F->setUsesFPIntrin(true);
// If we're in C89 mode, check that we don't have any decls after stmts. If // If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic. // so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) { if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {

View File

@ -3779,6 +3779,29 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break; break;
} }
case FLOAT_CONTROL_PRAGMA_OPTIONS: {
if (Record.size() < 3) {
Error("invalid pragma pack record");
return Failure;
}
FpPragmaCurrentValue = Record[0];
FpPragmaCurrentLocation = ReadSourceLocation(F, Record[1]);
unsigned NumStackEntries = Record[2];
unsigned Idx = 3;
// Reset the stack when importing a new module.
FpPragmaStack.clear();
for (unsigned I = 0; I < NumStackEntries; ++I) {
FpPragmaStackEntry Entry;
Entry.Value = Record[Idx++];
Entry.Location = ReadSourceLocation(F, Record[Idx++]);
Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]);
FpPragmaStrings.push_back(ReadString(Record, Idx));
Entry.SlotLabel = FpPragmaStrings.back();
FpPragmaStack.push_back(Entry);
}
break;
}
case DECLS_TO_CHECK_FOR_DEFERRED_DIAGS: case DECLS_TO_CHECK_FOR_DEFERRED_DIAGS:
for (unsigned I = 0, N = Record.size(); I != N; ++I) for (unsigned I = 0, N = Record.size(); I != N; ++I)
DeclsToCheckForDeferredDiags.push_back(getGlobalDeclID(F, Record[I])); DeclsToCheckForDeferredDiags.push_back(getGlobalDeclID(F, Record[I]));
@ -7853,6 +7876,34 @@ void ASTReader::UpdateSema() {
SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation; SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation;
} }
} }
if (FpPragmaCurrentValue) {
// The bottom of the stack might have a default value. It must be adjusted
// to the current value to ensure that fp-pragma state is preserved after
// popping entries that were included/imported from a PCH/module.
bool DropFirst = false;
if (!FpPragmaStack.empty() && FpPragmaStack.front().Location.isInvalid()) {
assert(FpPragmaStack.front().Value ==
SemaObj->FpPragmaStack.DefaultValue &&
"Expected a default pragma float_control value");
SemaObj->FpPragmaStack.Stack.emplace_back(
FpPragmaStack.front().SlotLabel, SemaObj->FpPragmaStack.CurrentValue,
SemaObj->FpPragmaStack.CurrentPragmaLocation,
FpPragmaStack.front().PushLocation);
DropFirst = true;
}
for (const auto &Entry :
llvm::makeArrayRef(FpPragmaStack).drop_front(DropFirst ? 1 : 0))
SemaObj->FpPragmaStack.Stack.emplace_back(
Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation);
if (FpPragmaCurrentLocation.isInvalid()) {
assert(*FpPragmaCurrentValue == SemaObj->FpPragmaStack.DefaultValue &&
"Expected a default pragma float_control value");
// Keep the current values.
} else {
SemaObj->FpPragmaStack.CurrentValue = *FpPragmaCurrentValue;
SemaObj->FpPragmaStack.CurrentPragmaLocation = FpPragmaCurrentLocation;
}
}
} }
IdentifierInfo *ASTReader::get(StringRef Name) { IdentifierInfo *ASTReader::get(StringRef Name) {

View File

@ -682,10 +682,14 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) { void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
VisitExpr(E); VisitExpr(E);
bool hasFP_Features = Record.readInt();
assert(hasFP_Features == E->hasStoredFPFeatures());
E->setSubExpr(Record.readSubExpr()); E->setSubExpr(Record.readSubExpr());
E->setOpcode((UnaryOperator::Opcode)Record.readInt()); E->setOpcode((UnaryOperator::Opcode)Record.readInt());
E->setOperatorLoc(readSourceLocation()); E->setOperatorLoc(readSourceLocation());
E->setCanOverflow(Record.readInt()); E->setCanOverflow(Record.readInt());
if (hasFP_Features)
E->setStoredFPFeatures(FPOptions(Record.readInt()));
} }
void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
@ -2900,7 +2904,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break; break;
case EXPR_UNARY_OPERATOR: case EXPR_UNARY_OPERATOR:
S = new (Context) UnaryOperator(Empty); S = UnaryOperator::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields]);
break; break;
case EXPR_OFFSETOF: case EXPR_OFFSETOF:

View File

@ -4139,6 +4139,26 @@ void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) {
Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record); Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);
} }
/// Write the state of 'pragma float_control' at the end of the module.
void ASTWriter::WriteFloatControlPragmaOptions(Sema &SemaRef) {
// Don't serialize pragma float_control state for modules,
// since it should only take effect on a per-submodule basis.
if (WritingModule)
return;
RecordData Record;
Record.push_back(SemaRef.FpPragmaStack.CurrentValue);
AddSourceLocation(SemaRef.FpPragmaStack.CurrentPragmaLocation, Record);
Record.push_back(SemaRef.FpPragmaStack.Stack.size());
for (const auto &StackEntry : SemaRef.FpPragmaStack.Stack) {
Record.push_back(StackEntry.Value);
AddSourceLocation(StackEntry.PragmaLocation, Record);
AddSourceLocation(StackEntry.PragmaPushLocation, Record);
AddString(StackEntry.StackSlotLabel, Record);
}
Stream.EmitRecord(FLOAT_CONTROL_PRAGMA_OPTIONS, Record);
}
void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer) { ModuleFileExtensionWriter &Writer) {
// Enter the extension block. // Enter the extension block.
@ -4867,6 +4887,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
WriteMSPointersToMembersPragmaOptions(SemaRef); WriteMSPointersToMembersPragmaOptions(SemaRef);
} }
WritePackPragmaOptions(SemaRef); WritePackPragmaOptions(SemaRef);
WriteFloatControlPragmaOptions(SemaRef);
// Some simple statistics // Some simple statistics
RecordData::value_type Record[] = { RecordData::value_type Record[] = {

View File

@ -702,10 +702,16 @@ void ASTStmtWriter::VisitParenListExpr(ParenListExpr *E) {
void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) { void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
VisitExpr(E); VisitExpr(E);
bool HasFPFeatures = E->hasStoredFPFeatures();
// Write this first for easy access when deserializing, as they affect the
// size of the UnaryOperator.
Record.push_back(HasFPFeatures);
Record.AddStmt(E->getSubExpr()); Record.AddStmt(E->getSubExpr());
Record.push_back(E->getOpcode()); // FIXME: stable encoding Record.push_back(E->getOpcode()); // FIXME: stable encoding
Record.AddSourceLocation(E->getOperatorLoc()); Record.AddSourceLocation(E->getOperatorLoc());
Record.push_back(E->canOverflow()); Record.push_back(E->canOverflow());
if (HasFPFeatures)
Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
Code = serialization::EXPR_UNARY_OPERATOR; Code = serialization::EXPR_UNARY_OPERATOR;
} }

View File

@ -1,11 +1,11 @@
// REQUIRES: nvptx-registered-target // REQUIRES: nvptx-registered-target
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_60 \ // RUN: %clang_cc1 -ffp-contract=off -triple nvptx-unknown-unknown -target-cpu sm_60 \
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \ // RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP32 %s // RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP32 %s
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -target-cpu sm_60 \ // RUN: %clang_cc1 -ffp-contract=off -triple nvptx64-unknown-unknown -target-cpu sm_60 \
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \ // RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s // RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -target-cpu sm_61 \ // RUN: %clang_cc1 -ffp-contract=off -triple nvptx64-unknown-unknown -target-cpu sm_61 \
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \ // RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s // RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_53 \ // RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_53 \

View File

@ -154,9 +154,9 @@ void bar(float f) {
(double)f * f - f; (double)f * f - f;
(long double)-f * f + f; (long double)-f * f + f;
// CHECK: call float @llvm.experimental.constrained.fmuladd.f32 // CHECK: call contract float @llvm.experimental.constrained.fmuladd.f32
// CHECK: fneg // CHECK: fneg
// CHECK: call double @llvm.experimental.constrained.fmuladd.f64 // CHECK: call contract double @llvm.experimental.constrained.fmuladd.f64
// CHECK: fneg // CHECK: fneg
// CHECK: call x86_fp80 @llvm.experimental.constrained.fmuladd.f80 // CHECK: call contract x86_fp80 @llvm.experimental.constrained.fmuladd.f80
}; };

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s
float f0, f1, f2; float f0, f1, f2;
void foo(void) { void foo(void) {

View File

@ -3,7 +3,7 @@
// Is FP_CONTRACT honored in a simple case? // Is FP_CONTRACT honored in a simple case?
float fp_contract_1(float a, float b, float c) { float fp_contract_1(float a, float b, float c) {
// CHECK: _Z13fp_contract_1fff // CHECK: _Z13fp_contract_1fff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
#pragma clang fp contract(on) #pragma clang fp contract(on)
return a * b + c; return a * b + c;
} }
@ -31,7 +31,7 @@ T template_muladd(T a, T b, T c) {
float fp_contract_3(float a, float b, float c) { float fp_contract_3(float a, float b, float c) {
// CHECK: _Z13fp_contract_3fff // CHECK: _Z13fp_contract_3fff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
return template_muladd<float>(a, b, c); return template_muladd<float>(a, b, c);
} }
@ -45,13 +45,13 @@ class fp_contract_4 {
template class fp_contract_4<int>; template class fp_contract_4<int>;
// CHECK: _ZN13fp_contract_4IiE6methodEfff // CHECK: _ZN13fp_contract_4IiE6methodEfff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
// Check file-scoped FP_CONTRACT // Check file-scoped FP_CONTRACT
#pragma clang fp contract(on) #pragma clang fp contract(on)
float fp_contract_5(float a, float b, float c) { float fp_contract_5(float a, float b, float c) {
// CHECK: _Z13fp_contract_5fff // CHECK: _Z13fp_contract_5fff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
return a * b + c; return a * b + c;
} }
@ -69,8 +69,8 @@ float fp_contract_6(float a, float b, float c) {
float fp_contract_7(float a, float b, float c) { float fp_contract_7(float a, float b, float c) {
// CHECK: _Z13fp_contract_7fff // CHECK: _Z13fp_contract_7fff
// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00 // CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
// CHECK-NEXT: fsub float %[[M]], %c // CHECK-NEXT: fsub contract float %[[M]], %c
#pragma clang fp contract(on) #pragma clang fp contract(on)
return (a = 2 * b) - c; return (a = 2 * b) - c;
} }

View File

@ -2,9 +2,9 @@
// Is FP_CONTRACT honored in a simple case? // Is FP_CONTRACT honored in a simple case?
float fp_contract_1(float a, float b, float c) { float fp_contract_1(float a, float b, float c) {
// CHECK: _Z13fp_contract_1fff // CHECK: _Z13fp_contract_1fff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
#pragma STDC FP_CONTRACT ON #pragma STDC FP_CONTRACT ON
return a * b + c; return a * b + c;
} }
@ -30,8 +30,8 @@ T template_muladd(T a, T b, T c) {
} }
float fp_contract_3(float a, float b, float c) { float fp_contract_3(float a, float b, float c) {
// CHECK: _Z13fp_contract_3fff // CHECK: _Z13fp_contract_3fff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
return template_muladd<float>(a, b, c); return template_muladd<float>(a, b, c);
} }
@ -44,13 +44,13 @@ template<typename T> class fp_contract_4 {
template class fp_contract_4<int>; template class fp_contract_4<int>;
// CHECK: _ZN13fp_contract_4IiE6methodEfff // CHECK: _ZN13fp_contract_4IiE6methodEfff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
// Check file-scoped FP_CONTRACT // Check file-scoped FP_CONTRACT
#pragma STDC FP_CONTRACT ON #pragma STDC FP_CONTRACT ON
float fp_contract_5(float a, float b, float c) { float fp_contract_5(float a, float b, float c) {
// CHECK: _Z13fp_contract_5fff // CHECK: _Z13fp_contract_5fff
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
return a * b + c; return a * b + c;
} }
@ -67,25 +67,25 @@ float fp_contract_6(float a, float b, float c) {
// https://llvm.org/bugs/show_bug.cgi?id=25719 // https://llvm.org/bugs/show_bug.cgi?id=25719
float fp_contract_7(float a, float b, float c) { float fp_contract_7(float a, float b, float c) {
// CHECK: _Z13fp_contract_7fff // CHECK: _Z13fp_contract_7fff
// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00 // CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
// CHECK-NEXT: fsub float %[[M]], %c // CHECK-NEXT: fsub contract float %[[M]], %c
#pragma STDC FP_CONTRACT ON #pragma STDC FP_CONTRACT ON
return (a = 2 * b) - c; return (a = 2 * b) - c;
} }
float fp_contract_8(float a, float b, float c) { float fp_contract_8(float a, float b, float c) {
// CHECK: _Z13fp_contract_8fff // CHECK: _Z13fp_contract_8fff
// CHECK: fneg float %c // CHECK: fneg contract float %c
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
#pragma STDC FP_CONTRACT ON #pragma STDC FP_CONTRACT ON
return a * b - c; return a * b - c;
} }
float fp_contract_9(float a, float b, float c) { float fp_contract_9(float a, float b, float c) {
// CHECK: _Z13fp_contract_9fff // CHECK: _Z13fp_contract_9fff
// CHECK: fneg float %a // CHECK: fneg contract float %a
// CHECK: tail call float @llvm.fmuladd // CHECK: tail call contract float @llvm.fmuladd
#pragma STDC FP_CONTRACT ON #pragma STDC FP_CONTRACT ON
return c - a * b; return c - a * b;
} }

View File

@ -0,0 +1,21 @@
// RUN: %clang_cc1 -ffp-contract=on -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -ffp-contract=on -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -ffp-contract=on -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// Verify that float_control does not pertain to initializer expressions
float y();
float z();
#pragma float_control(except, on)
class ON {
float w = 2 + y() * z();
// CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
//CHECK: call contract float {{.*}}llvm.fmuladd
};
ON on;
#pragma float_control(except, off)
class OFF {
float w = 2 + y() * z();
// CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
//CHECK: call contract float {{.*}}llvm.fmuladd
};
OFF off;

View File

@ -0,0 +1,47 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
float fff(float x, float y) {
// CHECK-LABEL: define float @_Z3fffff{{.*}}
// CHECK: entry
#pragma float_control(except, on)
float z;
z = z * z;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
{
z = x * y;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
}
{
// This pragma has no effect since if there are any fp intrin in the
// function then all the operations need to be fp intrin
#pragma float_control(except, off)
z = z + x * y;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
}
z = z * z;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
return z;
}
float check_precise(float x, float y) {
// CHECK-LABEL: define float @_Z13check_preciseff{{.*}}
float z;
{
#pragma float_control(precise, on)
z = x * y + z;
//CHECK: llvm.fmuladd{{.*}}
}
{
#pragma float_control(precise, off)
z = x * y + z;
//CHECK: fmul fast float
//CHECK: fadd fast float
}
return z;
}
float fma_test1(float a, float b, float c) {
// CHECK-LABEL define float @_Z9fma_test1fff{{.*}}
#pragma float_control(precise, on)
float x = a * b + c;
//CHECK: fmuladd
return x;
}

View File

@ -0,0 +1,253 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DDEFAULT=1 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DEBSTRICT=1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -DFAST=1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-FAST %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DNOHONOR=1 -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s
#define FUN(n) \
(float z) { return n * z + n; }
float fun_default FUN(1)
//CHECK-LABEL: define {{.*}} @_Z11fun_defaultf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
// Note that backend wants constrained intrinsics used
// throughout the function if they are needed anywhere in the function.
// In that case, operations are built with constrained intrinsics operator
// but using default settings for exception behavior and rounding mode.
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(push)
#ifndef FAST
// Rule: precise must be enabled
#pragma float_control(except, on)
#endif
float exc_on FUN(2)
//CHECK-LABEL: define {{.*}} @_Z6exc_onf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.experimental.constrained.fmul{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
#endif
#if NOHONOR
//CHECK-NOHONOR: nnan ninf contract float {{.*}}llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
#endif
#if FAST
//Not possible to enable float_control(except) in FAST mode.
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(pop)
float exc_pop FUN(5)
//CHECK-LABEL: define {{.*}} @_Z7exc_popf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(except, off)
float exc_off FUN(5)
//CHECK-LABEL: define {{.*}} @_Z7exc_offf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: call contract float @llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(precise, on, push)
float precise_on FUN(3)
//CHECK-LABEL: define {{.*}} @_Z10precise_onf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
// If precise is pushed then all fast-math should be off!
//CHECK-NOHONOR: call contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#pragma float_control(pop)
float precise_pop FUN(3)
//CHECK-LABEL: define {{.*}} @_Z11precise_popf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(precise, off)
float precise_off FUN(4)
//CHECK-LABEL: define {{.*}} @_Z11precise_offf{{.*}}
#if DEFAULT
// Note: precise_off enables fp_contract=fast and the instructions
// generated do not include the contract flag, although it was enabled
// in IRBuilder.
//CHECK-DDEFAULT: fmul fast float
//CHECK-DDEFAULT: fadd fast float
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: fmul fast float
//CHECK-DEBSTRICT: fadd fast float
#endif
#if NOHONOR
// fast math should be enabled, and contract should be fast
//CHECK-NOHONOR: fmul fast float
//CHECK-NOHONOR: fadd fast float
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(precise, on)
float precise_on2 FUN(3)
//CHECK-LABEL: define {{.*}} @_Z11precise_on2f{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
// fast math should be off, and contract should be on
//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#pragma float_control(push)
float precise_push FUN(3)
//CHECK-LABEL: define {{.*}} @_Z12precise_pushf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#pragma float_control(precise, off)
float precise_off2 FUN(4)
//CHECK-LABEL: define {{.*}} @_Z12precise_off2f{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: fmul fast float
//CHECK-DDEFAULT: fadd fast float
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: fmul fast float
//CHECK-DEBSTRICT: fadd fast float
#endif
#if NOHONOR
// fast math settings since precise is off
//CHECK-NOHONOR: fmul fast float
//CHECK-NOHONOR: fadd fast float
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(pop)
float precise_pop2 FUN(3)
//CHECK-LABEL: define {{.*}} @_Z12precise_pop2f{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
#endif
#ifndef FAST
// Rule: precise must be enabled
#pragma float_control(except, on)
#endif
float y();
class ON {
// Settings for top level class initializer revert to command line
// source pragma's do not pertain.
float z = 2 + y() * 7;
//CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call contract float {{.*}}llvm.fmuladd
#endif
#if EBSTRICT
//Currently, same as default [command line options not considered]
//CHECK-DEBSTRICT: call contract float {{.*}}llvm.fmuladd
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
};
ON on;
#pragma float_control(except, off)
class OFF {
float w = 2 + y() * 7;
//CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call contract float {{.*}}llvm.fmuladd
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: call contract float {{.*}}llvm.fmuladd
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
};
OFF off;

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -ftrapping-math -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT // RUN: %clang_cc1 -ftrapping-math -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
// RUN: %clang_cc1 -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE // RUN: %clang_cc1 -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST // RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST // RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s -check-prefix=FASTNOCONTRACT
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST // RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT // RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP // RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
@ -17,6 +17,7 @@ void foo() {
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") // STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
// PRECISE: fadd contract float %{{.*}}, %{{.*}} // PRECISE: fadd contract float %{{.*}}, %{{.*}}
// FAST: fadd fast // FAST: fadd fast
// FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
f0 = f1 + f2; f0 = f1 + f2;
// CHECK: ret // CHECK: ret

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -x c++ -ftrapping-math -fexceptions -fcxx-exceptions -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT // RUN: %clang_cc1 -x c++ -ftrapping-math -fexceptions -fcxx-exceptions -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
// RUN: %clang_cc1 -x c++ -ffp-contract=fast -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE // RUN: %clang_cc1 -x c++ -ffp-contract=fast -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST // RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST // RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=FASTNOCONTRACT
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST // RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT // RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP // RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
@ -20,16 +20,17 @@ float f0, f1, f2;
// CHECK-LABEL: define {{.*}}void @_ZN4aaaaIiED2Ev{{.*}} // CHECK-LABEL: define {{.*}}void @_ZN4aaaaIiED2Ev{{.*}}
} catch (...) { } catch (...) {
// MAYTRAP: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap") // MAYTRAP: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
// EXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") // EXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
// FPMODELSTRICT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") // FPMODELSTRICT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
// STRICTEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") // STRICTEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") // STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
// PRECISE: fadd contract float %{{.*}}, %{{.*}} // PRECISE: fadd contract float %{{.*}}, %{{.*}}
// FAST: fadd fast // FAST: fadd fast
f0 = f1 + f2; // FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
f0 = f1 + f2;
// CHECK: ret void // CHECK: ret void
} }
} }

View File

@ -8,12 +8,12 @@
float spscalardiv(float a, float b) { float spscalardiv(float a, float b) {
// CHECK: @spscalardiv( // CHECK: @spscalardiv(
// NORMAL: fdiv float // NORMAL: fdiv contract float
// FAST: fdiv fast float // FAST: fdiv fast float
// FINITE: fdiv nnan ninf float // FINITE: fdiv nnan ninf contract float
// UNSAFE: fdiv nnan nsz float // UNSAFE: fdiv nnan nsz contract float
// MAD: fdiv float // MAD: fdiv contract float
// NOSIGNED: fdiv nsz float // NOSIGNED: fdiv nsz contract float
return a / b; return a / b;
} }
// CHECK: attributes // CHECK: attributes

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s
float fn(float f) { float fn(float f) {
// CHECK: tail call float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00) // CHECK: tail call contract float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00)
return f*2. + 1.; return f*2. + 1.;
} }

View File

@ -1,8 +1,8 @@
// REQUIRES: nvptx-registered-target // REQUIRES: nvptx-registered-target
// RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc // RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
// RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW // RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW
// RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math // RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math -ffp-contract=fast
// RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math | FileCheck %s --check-prefix=FAST // RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math -ffp-contract=fast | FileCheck %s --check-prefix=FAST
// expected-no-diagnostics // expected-no-diagnostics
#include <math.h> #include <math.h>

View File

@ -1,8 +1,8 @@
// REQUIRES: nvptx-registered-target // REQUIRES: nvptx-registered-target
// RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc // RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
// RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW // RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW
// RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math // RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math -ffp-contract=fast
// RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math | FileCheck %s --check-prefix=FAST // RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math -ffp-contract=fast | FileCheck %s --check-prefix=FAST
// expected-no-diagnostics // expected-no-diagnostics
#include <cmath> #include <cmath>

View File

@ -0,0 +1,55 @@
// Test this without pch.
// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DSET
// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DPUSH
// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DPUSH_POP
// Test with pch.
// RUN: %clang_cc1 %s -DSET -emit-pch -o %t
// RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s
// RUN: %clang_cc1 %s -DPUSH -emit-pch -o %t
// RUN: %clang_cc1 %s -DPUSH -verify -include-pch %t
// RUN: %clang_cc1 %s -DPUSH_POP -emit-pch -o %t
// RUN: %clang_cc1 %s -DPUSH_POP -verify -include-pch %t
#ifndef HEADER
#define HEADER
#ifdef SET
#pragma float_control(except, on)
#endif
#ifdef PUSH
#pragma float_control(precise, on)
#pragma float_control(push)
#pragma float_control(precise, off)
#endif
#ifdef PUSH_POP
#pragma float_control(precise, on, push)
#pragma float_control(push)
#pragma float_control(pop)
#endif
#else
#ifdef SET
float fun(float a, float b) {
// CHECK-LABEL: define float @fun{{.*}}
//CHECK-EBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
//CHECK-EBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}strict
return a * b + 2;
}
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
#endif
#ifdef PUSH
#pragma float_control(pop)
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
#endif
#ifdef PUSH_POP
#pragma float_control(pop)
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
#endif
#endif //ifndef HEADER

View File

@ -0,0 +1,60 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DCHECK_ERROR %s -verify
float function_scope(float a) {
#pragma float_control(precise, on) junk // expected-warning {{extra tokens at end of '#pragma float_control' - ignored}}
return a;
}
#ifdef CHECK_ERROR
#pragma float_control(push)
#pragma float_control(pop)
#pragma float_control(precise, on, push)
void check_stack() {
#pragma float_control(push) // expected-error {{can only appear at file scope}}
#pragma float_control(pop) // expected-error {{can only appear at file scope}}
#pragma float_control(precise, on, push) // expected-error {{can only appear at file scope}}
#pragma float_control(except, on, push) // expected-error {{can only appear at file scope}}
#pragma float_control(except, on, push, junk) // expected-error {{float_control is malformed}}
return;
}
#endif
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fdenormal-fp-math=preserve-sign,preserve-sign -ftrapping-math -fsyntax-only %s -DDEFAULT -verify
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only %s -ffp-contract=fast -DPRECISE -verify
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only %s -ftrapping-math -ffp-contract=off -frounding-math -ffp-exception-behavior=strict -DSTRICT -verify
// RUN: %clang_cc1 -triple x86_64-linux-gnu -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -ffp-contract=fast -ffast-math -ffinite-math-only -fsyntax-only %s -DFAST -verify
double a = 0.0;
double b = 1.0;
//FIXME At some point this warning will be removed, until then
// document the warning
#ifdef FAST
// expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
#pragma STDC FENV_ACCESS ON // expected-error{{'#pragma STDC FENV_ACCESS ON' is illegal when precise is disabled}}
#else
#pragma STDC FENV_ACCESS ON // expected-warning{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
#endif
#ifdef STRICT
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
#else
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}}
#endif
#pragma float_control(precise, on)
#pragma float_control(except, on) // OK
#ifndef STRICT
#pragma float_control(except, on)
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
#endif
int main() {
#ifdef STRICT
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
#else
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
#endif
#pragma float_control(except, on)
// error: '#pragma float_control(except, on)' is illegal when precise is disabled
double x = b / a; // only used for fp flag setting
if (a == a) // only used for fp flag setting
return 0; //(int)x;
}

View File

@ -244,6 +244,8 @@ public:
/// Get the flags to be applied to created floating point ops /// Get the flags to be applied to created floating point ops
FastMathFlags getFastMathFlags() const { return FMF; } FastMathFlags getFastMathFlags() const { return FMF; }
FastMathFlags &getFastMathFlags() { return FMF; }
/// Clear the fast-math flags. /// Clear the fast-math flags.
void clearFastMathFlags() { FMF.clear(); } void clearFastMathFlags() { FMF.clear(); }
@ -332,10 +334,16 @@ public:
IRBuilderBase &Builder; IRBuilderBase &Builder;
FastMathFlags FMF; FastMathFlags FMF;
MDNode *FPMathTag; MDNode *FPMathTag;
bool IsFPConstrained;
fp::ExceptionBehavior DefaultConstrainedExcept;
RoundingMode DefaultConstrainedRounding;
public: public:
FastMathFlagGuard(IRBuilderBase &B) FastMathFlagGuard(IRBuilderBase &B)
: Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag) {} : Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag),
IsFPConstrained(B.IsFPConstrained),
DefaultConstrainedExcept(B.DefaultConstrainedExcept),
DefaultConstrainedRounding(B.DefaultConstrainedRounding) {}
FastMathFlagGuard(const FastMathFlagGuard &) = delete; FastMathFlagGuard(const FastMathFlagGuard &) = delete;
FastMathFlagGuard &operator=(const FastMathFlagGuard &) = delete; FastMathFlagGuard &operator=(const FastMathFlagGuard &) = delete;
@ -343,6 +351,9 @@ public:
~FastMathFlagGuard() { ~FastMathFlagGuard() {
Builder.FMF = FMF; Builder.FMF = FMF;
Builder.DefaultFPMathTag = FPMathTag; Builder.DefaultFPMathTag = FPMathTag;
Builder.IsFPConstrained = IsFPConstrained;
Builder.DefaultConstrainedExcept = DefaultConstrainedExcept;
Builder.DefaultConstrainedRounding = DefaultConstrainedRounding;
} }
}; };