[llvm] 4f1e9a1 - Add support for #pragma float_control
Roman Lebedev via llvm-commits
llvm-commits at lists.llvm.org
Fri May 1 06:31:20 PDT 2020
On Fri, May 1, 2020 at 4:15 PM Melanie Blower via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
>
>
> Author: Melanie Blower
> Date: 2020-05-01T06:14:24-07:00
> New Revision: 4f1e9a17e9d28bdfd035313c96b3a5d4c91a7733
>
> URL: https://github.com/llvm/llvm-project/commit/4f1e9a17e9d28bdfd035313c96b3a5d4c91a7733
> DIFF: https://github.com/llvm/llvm-project/commit/4f1e9a17e9d28bdfd035313c96b3a5d4c91a7733.diff
>
> LOG: Add support for #pragma float_control
>
It might be good for commit messages for large changes to me somewhat
descriptive of the changes..
> Reviewers: rjmccall, erichkeane, sepavloff
>
> Differential Revision: https://reviews.llvm.org/D72841
>
> Added:
> clang/test/CodeGen/fp-floatcontrol-class.cpp
> clang/test/CodeGen/fp-floatcontrol-pragma.cpp
> clang/test/CodeGen/fp-floatcontrol-stack.cpp
> clang/test/PCH/pragma-floatcontrol.c
> clang/test/Parser/fp-floatcontrol-syntax.cpp
>
> Modified:
> clang/docs/LanguageExtensions.rst
> clang/include/clang/AST/Expr.h
> clang/include/clang/AST/Stmt.h
> clang/include/clang/Basic/DiagnosticParseKinds.td
> clang/include/clang/Basic/DiagnosticSemaKinds.td
> clang/include/clang/Basic/LangOptions.def
> clang/include/clang/Basic/LangOptions.h
> clang/include/clang/Basic/PragmaKinds.h
> clang/include/clang/Basic/TokenKinds.def
> clang/include/clang/Parse/Parser.h
> clang/include/clang/Sema/Sema.h
> clang/include/clang/Serialization/ASTBitCodes.h
> clang/include/clang/Serialization/ASTReader.h
> clang/include/clang/Serialization/ASTWriter.h
> clang/lib/AST/ASTImporter.cpp
> clang/lib/AST/Expr.cpp
> clang/lib/Analysis/BodyFarm.cpp
> clang/lib/CodeGen/CGExprScalar.cpp
> clang/lib/CodeGen/CGObjC.cpp
> clang/lib/CodeGen/CGStmtOpenMP.cpp
> clang/lib/CodeGen/CodeGenFunction.cpp
> clang/lib/CodeGen/CodeGenFunction.h
> clang/lib/Frontend/CompilerInvocation.cpp
> clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
> clang/lib/Frontend/Rewrite/RewriteObjC.cpp
> clang/lib/Parse/ParseDeclCXX.cpp
> clang/lib/Parse/ParsePragma.cpp
> clang/lib/Parse/ParseStmt.cpp
> clang/lib/Parse/Parser.cpp
> clang/lib/Sema/Sema.cpp
> clang/lib/Sema/SemaAttr.cpp
> clang/lib/Sema/SemaDeclCXX.cpp
> clang/lib/Sema/SemaExpr.cpp
> clang/lib/Sema/SemaExprObjC.cpp
> clang/lib/Sema/SemaOverload.cpp
> clang/lib/Sema/SemaPseudoObject.cpp
> clang/lib/Sema/SemaStmt.cpp
> clang/lib/Serialization/ASTReader.cpp
> clang/lib/Serialization/ASTReaderStmt.cpp
> clang/lib/Serialization/ASTWriter.cpp
> clang/lib/Serialization/ASTWriterStmt.cpp
> clang/test/CodeGen/builtins-nvptx.c
> clang/test/CodeGen/constrained-math-builtins.c
> clang/test/CodeGen/fast-math.c
> clang/test/CodeGen/fp-contract-on-pragma.cpp
> clang/test/CodeGen/fp-contract-pragma.cpp
> clang/test/CodeGen/fpconstrained.c
> clang/test/CodeGen/fpconstrained.cpp
> clang/test/CodeGenOpenCL/relaxed-fpmath.cl
> clang/test/CodeGenOpenCL/single-precision-constant.cl
> clang/test/Headers/nvptx_device_math_sin.c
> clang/test/Headers/nvptx_device_math_sin.cpp
> llvm/include/llvm/IR/IRBuilder.h
>
> Removed:
>
>
>
> ################################################################################
> diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
> index 11114e82a6e5..1c753ea0e569 100644
> --- a/clang/docs/LanguageExtensions.rst
> +++ b/clang/docs/LanguageExtensions.rst
> @@ -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
> 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)
> ===========================================================================
>
>
> diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
> index 4d89234b0da7..6c83bc6c649d 100644
> --- a/clang/include/clang/AST/Expr.h
> +++ b/clang/include/clang/AST/Expr.h
> @@ -2107,26 +2107,48 @@ class ParenExpr : public Expr {
> /// applied to a non-complex value, the former returns its operand and the
> /// 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;
>
> + 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:
> typedef UnaryOperatorKind Opcode;
>
> - UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK,
> - ExprObjectKind OK, SourceLocation l, bool CanOverflow)
> - : Expr(UnaryOperatorClass, type, VK, OK), Val(input) {
> - UnaryOperatorBits.Opc = opc;
> - UnaryOperatorBits.CanOverflow = CanOverflow;
> - UnaryOperatorBits.Loc = l;
> - setDependence(computeDependence(this));
> - }
> +protected:
> + UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc, QualType type,
> + ExprValueKind VK, ExprObjectKind OK, SourceLocation l,
> + bool CanOverflow, FPOptions FPFeatures);
>
> /// 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.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 {
> return static_cast<Opcode>(UnaryOperatorBits.Opc);
> }
> @@ -2148,6 +2170,18 @@ class UnaryOperator : public Expr {
> bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
> 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++.
> static bool isPostfix(Opcode Op) {
> return Op == UO_PostInc || Op == UO_PostDec;
> @@ -2214,6 +2248,30 @@ class UnaryOperator : public Expr {
> const_child_range children() const {
> 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.
>
> diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
> index 58c03291c1ed..5db3ad3a138c 100644
> --- a/clang/include/clang/AST/Stmt.h
> +++ b/clang/include/clang/AST/Stmt.h
> @@ -427,6 +427,11 @@ class alignas(void *) Stmt {
>
> unsigned Opc : 5;
> 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;
> };
> @@ -610,7 +615,7 @@ class alignas(void *) Stmt {
> unsigned OperatorKind : 6;
>
> // Only meaningful for floating point types.
> - unsigned FPFeatures : 8;
> + unsigned FPFeatures : 14;
> };
>
> class CXXRewrittenBinaryOperatorBitfields {
>
> diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
> index 337614c33661..9400a87c0ef3 100644
> --- a/clang/include/clang/Basic/DiagnosticParseKinds.td
> +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
> @@ -1097,9 +1097,9 @@ def warn_pragma_init_seg_unsupported_target : Warning<
> "'#pragma init_seg' is only supported when targeting a "
> "Microsoft environment">,
> InGroup<IgnoredPragmas>;
> -// - #pragma fp_contract
> -def err_pragma_fp_contract_scope : Error<
> - "'#pragma fp_contract' can only appear at file scope or at the start of a "
> +// - #pragma restricted to file scope or start of compound statement
> +def err_pragma_file_or_compound_scope : Error<
> + "'#pragma %0' can only appear at file scope or at the start of a "
> "compound statement">;
> // - #pragma stdc unknown
> 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<
> "pragma detect_mismatch is malformed; it requires two comma-separated "
> "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
> def err_pragma_pointers_to_members_unknown_kind : Error<
> "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<
> "unexpected argument '%0' to '#pragma clang fp %1'; "
> "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<
> "invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
>
> diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
> index 154da867d00b..ac53ad6ab344 100644
> --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
> +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
> @@ -858,6 +858,16 @@ def warn_pragma_pack_pop_identifier_and_alignment : Warning<
> "specifying both a name and alignment to 'pop' is undefined">;
> def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">,
> 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 :
> Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
> "with base classes or virtual functions">,
>
> diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
> index 1464aac8df7e..289f9c3f50e2 100644
> --- a/clang/include/clang/Basic/LangOptions.def
> +++ b/clang/include/clang/Basic/LangOptions.def
> @@ -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(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro")
> 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")
>
>
> diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
> index 76ddd7051fd3..61b4b87ebd0e 100644
> --- a/clang/include/clang/Basic/LangOptions.h
> +++ b/clang/include/clang/Basic/LangOptions.h
> @@ -304,6 +304,8 @@ class LangOptions : public LangOptionsBase {
> /// input is a header file (i.e. -x c-header).
> bool IsHeaderFile = false;
>
> + bool denormalIsIEEE = false;
> +
> LangOptions();
>
> // Define accessors/mutators for language options of enumeration type.
> @@ -377,28 +379,33 @@ class FPOptions {
> using RoundingMode = llvm::RoundingMode;
>
> public:
> - FPOptions() : fp_contract(LangOptions::FPC_Off),
> - fenv_access(LangOptions::FEA_Off),
> - rounding(LangOptions::FPR_ToNearest),
> - exceptions(LangOptions::FPE_Ignore)
> - {}
> + FPOptions()
> + : fp_contract(LangOptions::FPC_Off), fenv_access(LangOptions::FEA_Off),
> + rounding(LangOptions::FPR_ToNearest),
> + 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.
> - explicit FPOptions(unsigned I)
> - : fp_contract(I & 3),
> - fenv_access((I >> 2) & 1),
> - rounding ((I >> 3) & 7),
> - exceptions ((I >> 6) & 3)
> - {}
> + explicit FPOptions(unsigned I) { getFromOpaqueInt(I); }
>
> explicit FPOptions(const LangOptions &LangOpts)
> : fp_contract(LangOpts.getDefaultFPContractMode()),
> fenv_access(LangOptions::FEA_Off),
> - rounding(LangOptions::FPR_ToNearest),
> - exceptions(LangOptions::FPE_Ignore)
> - {}
> + rounding(static_cast<unsigned>(LangOpts.getFPRoundingMode())),
> + 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.
>
> + 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
> /// storage isn't required.
> static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO);
> @@ -433,6 +440,18 @@ class FPOptions {
> 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; }
>
> RoundingMode getRoundingMode() const {
> @@ -451,6 +470,22 @@ class FPOptions {
> 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 {
> return getRoundingMode() != RoundingMode::NearestTiesToEven ||
> getExceptionMode() != LangOptions::FPE_Ignore ||
> @@ -460,7 +495,23 @@ class FPOptions {
> /// Used to serialize this.
> unsigned getAsOpaqueInt() const {
> 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:
> @@ -471,6 +522,25 @@ class FPOptions {
> unsigned fenv_access : 1;
> unsigned rounding : 3;
> 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.
>
> diff --git a/clang/include/clang/Basic/PragmaKinds.h b/clang/include/clang/Basic/PragmaKinds.h
> index 103b97db718b..82c0d5f0a551 100644
> --- a/clang/include/clang/Basic/PragmaKinds.h
> +++ b/clang/include/clang/Basic/PragmaKinds.h
> @@ -25,6 +25,15 @@ enum PragmaMSStructKind {
> 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
>
> diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
> index 07058962fc85..6ca5f0e30ade 100644
> --- a/clang/include/clang/Basic/TokenKinds.def
> +++ b/clang/include/clang/Basic/TokenKinds.def
> @@ -809,6 +809,11 @@ PRAGMA_ANNOTATION(pragma_fp_contract)
> // handles them.
> 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...
> // The lexer produces these so that they only take effect when the parser
> // handles them.
>
> diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
> index d8642996de79..4a8acf5cd196 100644
> --- a/clang/include/clang/Parse/Parser.h
> +++ b/clang/include/clang/Parse/Parser.h
> @@ -182,6 +182,7 @@ class Parser : public CodeCompletionHandler {
> std::unique_ptr<PragmaHandler> PCSectionHandler;
> std::unique_ptr<PragmaHandler> MSCommentHandler;
> std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
> + std::unique_ptr<PragmaHandler> FloatControlHandler;
> std::unique_ptr<PragmaHandler> MSPointersToMembers;
> std::unique_ptr<PragmaHandler> MSVtorDisp;
> std::unique_ptr<PragmaHandler> MSInitSeg;
> @@ -741,6 +742,10 @@ class Parser : public CodeCompletionHandler {
> /// #pragma STDC FENV_ACCESS...
> void HandlePragmaFEnvAccess();
>
> + /// Handle the annotation token produced for
> + /// #pragma float_control
> + void HandlePragmaFloatControl();
> +
> /// \brief Handle the annotation token produced for
> /// #pragma clang fp ...
> void HandlePragmaFP();
>
> diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
> index 0c1241f45ef5..394a7838351e 100644
> --- a/clang/include/clang/Sema/Sema.h
> +++ b/clang/include/clang/Sema/Sema.h
> @@ -555,6 +555,9 @@ class Sema final {
> PragmaStack<StringLiteral *> ConstSegStack;
> 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.
> // Actions should be performed only if we enter / exit a C++ method body.
> class PragmaStackSentinelRAII {
> @@ -1350,7 +1353,7 @@ class Sema final {
> /// should not be used elsewhere.
> 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.
> class FPFeaturesStateRAII {
> public:
> @@ -9566,6 +9569,18 @@ class Sema final {
> void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
> StringRef Value);
>
> + /// Are precise floating point semantics currently enabled?
> + bool isPreciseFPEnabled() {
> + return LangOpts.denormalIsIEEE && !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'.
> void ActOnPragmaUnused(const Token &Identifier,
> Scope *curScope,
> @@ -9606,7 +9621,8 @@ class Sema final {
>
> /// ActOnPragmaFenvAccess - Called on well formed
> /// \#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.
> void setRoundingMode(llvm::RoundingMode);
>
> diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
> index d5a27f487fa9..14d052a62719 100644
> --- a/clang/include/clang/Serialization/ASTBitCodes.h
> +++ b/clang/include/clang/Serialization/ASTBitCodes.h
> @@ -686,6 +686,9 @@ namespace serialization {
>
> /// Record code for the Decls to be checked for deferred diags.
> 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.
>
> diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
> index 11a537fad5d5..beaacefbc5c7 100644
> --- a/clang/include/clang/Serialization/ASTReader.h
> +++ b/clang/include/clang/Serialization/ASTReader.h
> @@ -857,6 +857,18 @@ class ASTReader
> int PragmaMSPointersToMembersState = -1;
> 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.
> Optional<unsigned> PragmaPackCurrentValue;
> SourceLocation PragmaPackCurrentLocation;
>
> diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
> index bc5a782f20cc..398fa40f95eb 100644
> --- a/clang/include/clang/Serialization/ASTWriter.h
> +++ b/clang/include/clang/Serialization/ASTWriter.h
> @@ -505,6 +505,7 @@ class ASTWriter : public ASTDeserializationListener,
> void WriteMSStructPragmaOptions(Sema &SemaRef);
> void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef);
> void WritePackPragmaOptions(Sema &SemaRef);
> + void WriteFloatControlPragmaOptions(Sema &SemaRef);
> void WriteModuleFileExtension(Sema &SemaRef,
> ModuleFileExtensionWriter &Writer);
>
>
> diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
> index 477c035d8a59..10035162299e 100644
> --- a/clang/lib/AST/ASTImporter.cpp
> +++ b/clang/lib/AST/ASTImporter.cpp
> @@ -6660,9 +6660,10 @@ ExpectedStmt ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
> if (Err)
> return std::move(Err);
>
> - return new (Importer.getToContext()) UnaryOperator(
> - ToSubExpr, E->getOpcode(), ToType, E->getValueKind(), E->getObjectKind(),
> - ToOperatorLoc, E->canOverflow());
> + return UnaryOperator::Create(
> + Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType,
> + E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(),
> + E->getFPFeatures(Importer.getFromContext().getLangOpts()));
> }
>
> ExpectedStmt
>
> diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
> index bb27f40994dc..36083d3227c7 100644
> --- a/clang/lib/AST/Expr.cpp
> +++ b/clang/lib/AST/Expr.cpp
> @@ -1358,7 +1358,8 @@ CallExpr *CallExpr::CreateTemporary(void *Mem, Expr *Fn, QualType Ty,
> assert(!(reinterpret_cast<uintptr_t>(Mem) % alignof(CallExpr)) &&
> "Misaligned memory in CallExpr::CreateTemporary!");
> 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,
> @@ -4445,6 +4446,38 @@ CompoundAssignOperator *CompoundAssignOperator::Create(
> 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) {
> if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
> e = ewc->getSubExpr();
>
> diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
> index 852954618463..e10fbce71146 100644
> --- a/clang/lib/Analysis/BodyFarm.cpp
> +++ b/clang/lib/Analysis/BodyFarm.cpp
> @@ -146,9 +146,10 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(
> }
>
> 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(),
> - /*CanOverflow*/ false);
> + /*CanOverflow*/ false,
> + FPOptions(C.getLangOpts()));
> }
>
> 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();
>
> // Negation predicate.
> - UnaryOperator *FlagCheck = new (C) UnaryOperator(
> + UnaryOperator *FlagCheck = UnaryOperator::Create(
> + C,
> /* input=*/
> M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
> CK_IntegralToBoolean),
> - /* opc=*/ UO_LNot,
> - /* QualType=*/ C.IntTy,
> - /* ExprValueKind=*/ VK_RValue,
> - /* ExprObjectKind=*/ OK_Ordinary, SourceLocation(),
> - /* CanOverflow*/ false);
> + /* opc=*/UO_LNot,
> + /* QualType=*/C.IntTy,
> + /* ExprValueKind=*/VK_RValue,
> + /* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
> + /* CanOverflow*/ false, FPOptions(C.getLangOpts()));
>
> // Create assignment.
> 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.
> Expr *DoneValue =
> - new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy,
> - VK_RValue, OK_Ordinary, SourceLocation(),
> - /*CanOverflow*/false);
> + UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
> + C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(),
> + /*CanOverflow*/ false, FPOptions(C.getLangOpts()));
>
> BinaryOperator *B =
> M.makeAssignment(
>
> diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
> index c3f2352f68f2..76f58b284eeb 100644
> --- a/clang/lib/CodeGen/CGExprScalar.cpp
> +++ b/clang/lib/CodeGen/CGExprScalar.cpp
> @@ -217,7 +217,14 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
> /// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
> static void updateFastMathFlags(llvm::FastMathFlags &FMF,
> 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.
> @@ -230,6 +237,25 @@ static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) {
> 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
> : public StmtVisitor<ScalarExprEmitter, Value*> {
> CodeGenFunction &CGF;
> @@ -744,6 +770,9 @@ class ScalarExprEmitter
> return EmitOverflowCheckedBinOp(Ops);
>
> 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");
> return propagateFMFlags(V, Ops);
> }
> @@ -2333,13 +2362,14 @@ Value *ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
> //===----------------------------------------------------------------------===//
>
> static BinOpInfo createBinOpInfoFromIncDec(const UnaryOperator *E,
> - llvm::Value *InVal, bool IsInc) {
> + llvm::Value *InVal, bool IsInc,
> + FPOptions FPFeatures) {
> BinOpInfo BinOp;
> BinOp.LHS = InVal;
> BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false);
> BinOp.Ty = E->getType();
> BinOp.Opcode = IsInc ? BO_Add : BO_Sub;
> - // FIXME: once UnaryOperator carries FPFeatures, copy it here.
> + BinOp.FPFeatures = FPFeatures;
> BinOp.E = E;
> return BinOp;
> }
> @@ -2359,7 +2389,8 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
> case LangOptions::SOB_Trapping:
> if (!E->canOverflow())
> 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");
> }
> @@ -2505,8 +2536,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
> value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
> } else if (E->canOverflow() && type->isUnsignedIntegerType() &&
> CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
> - value =
> - EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc));
> + value = EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
> + E, value, isInc, E->getFPFeatures(CGF.getLangOpts())));
> } else {
> llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
> 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.Ty = E->getType();
> BinOp.Opcode = BO_Sub;
> - // FIXME: once UnaryOperator carries FPFeatures, copy it here.
> + BinOp.FPFeatures = E->getFPFeatures(CGF.getLangOpts());
> BinOp.E = E;
> return EmitSub(BinOp);
> }
> @@ -2723,9 +2754,12 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
> Value *Oper = Visit(E->getSubExpr());
> Value *Zero = llvm::Constant::getNullValue(Oper->getType());
> 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");
> - else
> + } else
> Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
> return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
> }
> @@ -3134,7 +3168,10 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
> }
>
> 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 &&
> !CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) {
> // 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);
>
> if (op.LHS->getType()->isFPOrFPVectorTy()) {
> + llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
> + setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures);
> // Try to form an fmuladd.
> if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
> return FMulAdd;
> @@ -3688,6 +3727,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
> return EmitOverflowCheckedBinOp(op);
>
> if (op.LHS->getType()->isFPOrFPVectorTy()) {
> + llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
> + setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures);
> // Try to form an fmuladd.
> if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
> return FMulAdd;
> @@ -4014,6 +4055,8 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
> if (BOInfo.isFixedPointOp()) {
> Result = EmitFixedPointBinOp(BOInfo);
> } else if (LHS->getType()->isFPOrFPVectorTy()) {
> + llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
> + setBuilderFlagsFromFPFeatures(Builder, CGF, BOInfo.FPFeatures);
> if (!IsSignaling)
> Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
> else
> @@ -4166,6 +4209,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
> Value *RHS = Visit(E->getRHS());
> Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
> 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");
> RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
> } else {
> @@ -4250,6 +4296,9 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
> Value *RHS = Visit(E->getRHS());
> Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
> 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");
> RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
> } else {
>
> diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
> index e3df22aef2c1..ff4591a3c446 100644
> --- a/clang/lib/CodeGen/CGObjC.cpp
> +++ b/clang/lib/CodeGen/CGObjC.cpp
> @@ -3556,17 +3556,17 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
>
> StartFunction(FD, ReturnTy, Fn, FI, args);
>
> - DeclRefExpr DstExpr(getContext(), &DstDecl, false, DestTy, VK_RValue,
> - SourceLocation());
> - UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
> - VK_LValue, OK_Ordinary, SourceLocation(), false);
> + DeclRefExpr DstExpr(C, &DstDecl, false, DestTy, VK_RValue, SourceLocation());
> + UnaryOperator *DST = UnaryOperator::Create(
> + C, &DstExpr, UO_Deref, DestTy->getPointeeType(), VK_LValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(C.getLangOpts()));
>
> - DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
> - SourceLocation());
> - UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
> - VK_LValue, OK_Ordinary, SourceLocation(), false);
> + DeclRefExpr SrcExpr(C, &SrcDecl, false, SrcTy, VK_RValue, SourceLocation());
> + UnaryOperator *SRC = UnaryOperator::Create(
> + C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(C.getLangOpts()));
>
> - Expr *Args[2] = { &DST, &SRC };
> + Expr *Args[2] = {DST, SRC};
> CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
> CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
> C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
> @@ -3642,14 +3642,15 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
> DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
> SourceLocation());
>
> - UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
> - VK_LValue, OK_Ordinary, SourceLocation(), false);
> + UnaryOperator *SRC = UnaryOperator::Create(
> + C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(C.getLangOpts()));
>
> CXXConstructExpr *CXXConstExpr =
> cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
>
> SmallVector<Expr*, 4> ConstructorArgs;
> - ConstructorArgs.push_back(&SRC);
> + ConstructorArgs.push_back(SRC);
> ConstructorArgs.append(std::next(CXXConstExpr->arg_begin()),
> CXXConstExpr->arg_end());
>
>
> diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
> index 19bbcb83b8db..2f4e825823b6 100644
> --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
> +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
> @@ -2934,8 +2934,9 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
> C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary,
> S.getBeginLoc(), FPOptions(C.getLangOpts()));
> // Increment for loop counter.
> - UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
> - S.getBeginLoc(), true);
> + UnaryOperator *Inc = UnaryOperator::Create(
> + C, &IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
> + S.getBeginLoc(), true, FPOptions(C.getLangOpts()));
> auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
> // Iterate through all sections and emit a switch construct:
> // switch (IV) {
> @@ -3005,7 +3006,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
> // IV = LB;
> CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
> // while (idx <= UB) { BODY; ++idx; }
> - CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, &Inc, BodyGen,
> + CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, Inc, BodyGen,
> [](CodeGenFunction &) {});
> // Tell the runtime we are done.
> auto &&CodeGen = [&S](CodeGenFunction &CGF) {
>
> diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
> index 24e01c46045e..4fcf31a5f1aa 100644
> --- a/clang/lib/CodeGen/CodeGenFunction.cpp
> +++ b/clang/lib/CodeGen/CodeGenFunction.cpp
> @@ -117,8 +117,8 @@ CodeGenFunction::~CodeGenFunction() {
>
> // Map the LangOption for exception behavior into
> // the corresponding enum in the IR.
> -static llvm::fp::ExceptionBehavior ToConstrainedExceptMD(
> - LangOptions::FPExceptionModeKind Kind) {
> +llvm::fp::ExceptionBehavior
> +clang::ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind) {
>
> switch (Kind) {
> case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore;
> @@ -133,15 +133,10 @@ void CodeGenFunction::SetFPModel() {
> auto fpExceptionBehavior = ToConstrainedExceptMD(
> getLangOpts().getFPExceptionMode());
>
> - if (fpExceptionBehavior == llvm::fp::ebIgnore &&
> - RM == llvm::RoundingMode::NearestTiesToEven)
> - // Constrained intrinsics are not used.
> - ;
> - else {
> - Builder.setIsFPConstrained(true);
> - Builder.setDefaultConstrainedRounding(RM);
> - Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
> - }
> + Builder.setDefaultConstrainedRounding(RM);
> + Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
> + Builder.setIsFPConstrained(fpExceptionBehavior != llvm::fp::ebIgnore ||
> + RM != llvm::RoundingMode::NearestTiesToEven);
> }
>
> CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
> @@ -919,9 +914,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
> 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())
> Fn->addFnAttr(llvm::Attribute::StrictFP);
> + }
>
> // If a custom alignment is used, force realigning to this alignment on
> // any main function which certainly will need it.
>
> diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
> index 0e09eb75e8ad..2639fd815ea1 100644
> --- a/clang/lib/CodeGen/CodeGenFunction.h
> +++ b/clang/lib/CodeGen/CodeGenFunction.h
> @@ -4575,6 +4575,11 @@ inline llvm::Value *DominatingLLVMValue::restore(CodeGenFunction &CGF,
> }
>
> } // 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
>
> #endif
>
> diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
> index b327fa902f67..391f0e929eb5 100644
> --- a/clang/lib/Frontend/CompilerInvocation.cpp
> +++ b/clang/lib/Frontend/CompilerInvocation.cpp
> @@ -2455,7 +2455,7 @@ static const StringRef GetInputKindName(InputKind IK) {
>
> static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
> const TargetOptions &TargetOpts,
> - PreprocessorOptions &PPOpts,
> + PreprocessorOptions &PPOpts, CodeGenOptions &CGOpts,
> DiagnosticsEngine &Diags) {
> // FIXME: Cleanup per-file based stuff.
> LangStandard::Kind LangStd = LangStandard::lang_unspecified;
> @@ -3187,6 +3187,19 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
> Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
> Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
> 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;
> + Opts.denormalIsIEEE =
> + !(CGOpts.FPDenormalMode.isValid() && CGOpts.FP32DenormalMode.isValid()) ||
> + (CGOpts.FPDenormalMode == llvm::DenormalMode::getIEEE() &&
> + CGOpts.FP32DenormalMode == llvm::DenormalMode::getIEEE());
>
> if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
> StringRef Val = A->getValue();
> @@ -3640,7 +3653,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
> // 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?
> ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
> - Res.getPreprocessorOpts(), Diags);
> + Res.getPreprocessorOpts(), Res.getCodeGenOpts(), Diags);
> if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
> LangOpts.ObjCExceptions = 1;
> if (T.isOSDarwin() && DashX.isPreprocessed()) {
>
> diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
> index c46ba9832c0d..bb195ade1409 100644
> --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
> +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
> @@ -2587,9 +2587,10 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
> strType, nullptr, SC_Static);
> DeclRefExpr *DRE = new (Context)
> DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
> - Expr *Unop = new (Context)
> - UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()),
> - VK_RValue, OK_Ordinary, SourceLocation(), false);
> + Expr *Unop = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
> + Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> // cast to NSConstantString *
> CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
> CK_CPointerToObjCPointerCast, Unop);
> @@ -3283,10 +3284,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
> // we need the cast below. For example:
> // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
> //
> - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
> - Context->getPointerType(SuperRep->getType()),
> - VK_RValue, OK_Ordinary,
> - SourceLocation(), false);
> + SuperRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
> + Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> SuperRep = NoTypeInfoCStyleCastExpr(Context,
> Context->getPointerType(superType),
> CK_BitCast, SuperRep);
> @@ -3301,10 +3302,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
> superType, VK_LValue,
> ILE, false);
> // struct __rw_objc_super *
> - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
> - Context->getPointerType(SuperRep->getType()),
> - VK_RValue, OK_Ordinary,
> - SourceLocation(), false);
> + SuperRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
> + Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> }
> MsgExprs.push_back(SuperRep);
> break;
> @@ -3378,10 +3379,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
> // we need the cast below. For example:
> // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
> //
> - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
> - Context->getPointerType(SuperRep->getType()),
> - VK_RValue, OK_Ordinary,
> - SourceLocation(), false);
> + SuperRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
> + Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> SuperRep = NoTypeInfoCStyleCastExpr(Context,
> Context->getPointerType(superType),
> CK_BitCast, SuperRep);
> @@ -4705,9 +4706,10 @@ Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
> if (VarDecl *Var = dyn_cast<VarDecl>(VD))
> if (!ImportedLocalExternalDecls.count(Var))
> return DRE;
> - Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
> - VK_LValue, OK_Ordinary,
> - DRE->getLocation(), false);
> + Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), DRE,
> + UO_Deref, DRE->getType(), VK_LValue,
> + OK_Ordinary, DRE->getLocation(), false,
> + FPOptions(Context->getLangOpts()));
> // Need parens to enforce precedence.
> ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
> Exp);
> @@ -5293,11 +5295,12 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
> VarDecl *NewVD = VarDecl::Create(
> *Context, TUDecl, SourceLocation(), SourceLocation(),
> &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,
> VK_LValue, SourceLocation()),
> UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
> - OK_Ordinary, SourceLocation(), false);
> + OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts()));
> InitExprs.push_back(DescRefExpr);
>
> // Add initializers for any closure decl refs.
> @@ -5314,9 +5317,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
> if (HasLocalVariableExternalStorage(*I)) {
> QualType QT = (*I)->getType();
> QT = Context->getPointerType(QT);
> - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
> - OK_Ordinary, SourceLocation(),
> - false);
> + Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
> + UO_AddrOf, QT, VK_RValue, OK_Ordinary,
> + SourceLocation(), false,
> + FPOptions(Context->getLangOpts()));
> }
> } else if (isTopLevelBlockPointerType((*I)->getType())) {
> FD = SynthBlockInitFunctionDecl((*I)->getName());
> @@ -5331,9 +5335,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
> if (HasLocalVariableExternalStorage(*I)) {
> QualType QT = (*I)->getType();
> QT = Context->getPointerType(QT);
> - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
> - OK_Ordinary, SourceLocation(),
> - false);
> + Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
> + UO_AddrOf, QT, VK_RValue, OK_Ordinary,
> + 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
> // its address again.
> if (!isNestedCapturedVar)
> - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
> - Context->getPointerType(Exp->getType()),
> - VK_RValue, OK_Ordinary, SourceLocation(),
> - false);
> + Exp = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), Exp, UO_AddrOf,
> + Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
> InitExprs.push_back(Exp);
> }
> @@ -5398,9 +5403,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
> NewRep = DRE;
> }
>
> - NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
> - Context->getPointerType(NewRep->getType()),
> - VK_RValue, OK_Ordinary, SourceLocation(), false);
> + NewRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), NewRep, UO_AddrOf,
> + Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
> NewRep);
> // Put Paren around the call.
> @@ -7539,10 +7545,10 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
> CK_BitCast,
> PE);
>
> -
> - Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT,
> - VK_LValue, OK_Ordinary,
> - SourceLocation(), false);
> + Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context),
> + castExpr, UO_Deref, IvarT, VK_LValue,
> + OK_Ordinary, SourceLocation(), false,
> + FPOptions(Context->getLangOpts()));
> PE = new (Context) ParenExpr(OldRange.getBegin(),
> OldRange.getEnd(),
> Exp);
>
> diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
> index 4674f7c6a38c..8b618d90b47e 100644
> --- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
> +++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
> @@ -2514,9 +2514,10 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
> strType, nullptr, SC_Static);
> DeclRefExpr *DRE = new (Context)
> DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
> - Expr *Unop = new (Context)
> - UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()),
> - VK_RValue, OK_Ordinary, SourceLocation(), false);
> + Expr *Unop = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
> + Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> // cast to NSConstantString *
> CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
> CK_CPointerToObjCPointerCast, Unop);
> @@ -2714,10 +2715,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
> // we need the cast below. For example:
> // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
> //
> - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
> - Context->getPointerType(SuperRep->getType()),
> - VK_RValue, OK_Ordinary,
> - SourceLocation(), false);
> + SuperRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
> + Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> SuperRep = NoTypeInfoCStyleCastExpr(Context,
> Context->getPointerType(superType),
> CK_BitCast, SuperRep);
> @@ -2732,10 +2733,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
> superType, VK_LValue,
> ILE, false);
> // struct objc_super *
> - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
> - Context->getPointerType(SuperRep->getType()),
> - VK_RValue, OK_Ordinary,
> - SourceLocation(), false);
> + SuperRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
> + Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> }
> MsgExprs.push_back(SuperRep);
> break;
> @@ -2809,10 +2810,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
> // we need the cast below. For example:
> // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
> //
> - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
> - Context->getPointerType(SuperRep->getType()),
> - VK_RValue, OK_Ordinary,
> - SourceLocation(), false);
> + SuperRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
> + Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> SuperRep = NoTypeInfoCStyleCastExpr(Context,
> Context->getPointerType(superType),
> CK_BitCast, SuperRep);
> @@ -3048,9 +3049,10 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
> nullptr, SC_Extern);
> DeclRefExpr *DRE = new (Context) DeclRefExpr(
> *Context, VD, false, getProtocolType(), VK_LValue, SourceLocation());
> - Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
> - Context->getPointerType(DRE->getType()),
> - VK_RValue, OK_Ordinary, SourceLocation(), false);
> + Expr *DerefExpr = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
> + Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
> CK_BitCast,
> DerefExpr);
> @@ -3875,9 +3877,10 @@ Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
> if (VarDecl *Var = dyn_cast<VarDecl>(VD))
> if (!ImportedLocalExternalDecls.count(Var))
> return DRE;
> - Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
> - VK_LValue, OK_Ordinary,
> - DRE->getLocation(), false);
> + Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), DRE,
> + UO_Deref, DRE->getType(), VK_LValue,
> + OK_Ordinary, DRE->getLocation(), false,
> + FPOptions(Context->getLangOpts()));
> // Need parens to enforce precedence.
> ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
> Exp);
> @@ -4432,11 +4435,12 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
> VarDecl *NewVD = VarDecl::Create(
> *Context, TUDecl, SourceLocation(), SourceLocation(),
> &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,
> VK_LValue, SourceLocation()),
> UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
> - OK_Ordinary, SourceLocation(), false);
> + OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts()));
> InitExprs.push_back(DescRefExpr);
>
> // Add initializers for any closure decl refs.
> @@ -4453,9 +4457,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
> if (HasLocalVariableExternalStorage(*I)) {
> QualType QT = (*I)->getType();
> QT = Context->getPointerType(QT);
> - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
> - OK_Ordinary, SourceLocation(),
> - false);
> + Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
> + UO_AddrOf, QT, VK_RValue, OK_Ordinary,
> + SourceLocation(), false,
> + FPOptions(Context->getLangOpts()));
> }
> } else if (isTopLevelBlockPointerType((*I)->getType())) {
> FD = SynthBlockInitFunctionDecl((*I)->getName());
> @@ -4470,9 +4475,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
> if (HasLocalVariableExternalStorage(*I)) {
> QualType QT = (*I)->getType();
> QT = Context->getPointerType(QT);
> - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
> - OK_Ordinary, SourceLocation(),
> - false);
> + Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
> + UO_AddrOf, QT, VK_RValue, OK_Ordinary,
> + SourceLocation(), false,
> + FPOptions(Context->getLangOpts()));
> }
> }
> InitExprs.push_back(Exp);
> @@ -4509,9 +4515,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
> // captured nested byref variable has its address passed. Do not take
> // its address again.
> if (!isNestedCapturedVar)
> - Exp = new (Context) UnaryOperator(
> - Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue,
> - OK_Ordinary, SourceLocation(), false);
> + Exp = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), Exp, UO_AddrOf,
> + Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
> InitExprs.push_back(Exp);
> }
> @@ -4527,9 +4534,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
> }
> NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue,
> SourceLocation());
> - NewRep = new (Context) UnaryOperator(
> - NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), VK_RValue,
> - OK_Ordinary, SourceLocation(), false);
> + NewRep = UnaryOperator::Create(
> + const_cast<ASTContext &>(*Context), NewRep, UO_AddrOf,
> + Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary,
> + SourceLocation(), false, FPOptions(Context->getLangOpts()));
> NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
> NewRep);
> BlockDeclRefs.clear();
>
> diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
> index 6b919191d6d5..f8c6379eee91 100644
> --- a/clang/lib/Parse/ParseDeclCXX.cpp
> +++ b/clang/lib/Parse/ParseDeclCXX.cpp
> @@ -3365,6 +3365,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
> // are complete and we can parse the delayed portions of method
> // declarations and the lexed inline method definitions, along with any
> // 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;
> ParseLexedPragmas(getCurrentClass());
> ParseLexedAttributes(getCurrentClass());
>
> diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
> index 34232437528b..3b5b7154d6a6 100644
> --- a/clang/lib/Parse/ParsePragma.cpp
> +++ b/clang/lib/Parse/ParsePragma.cpp
> @@ -184,6 +184,16 @@ struct PragmaDetectMismatchHandler : public PragmaHandler {
> Sema &Actions;
> };
>
> +struct PragmaFloatControlHandler : public PragmaHandler {
> + PragmaFloatControlHandler(Sema &Actions)
> + : PragmaHandler("float_control"), Actions(Actions) {}
> + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
> + Token &FirstToken) override;
> +
> +private:
> + Sema &Actions;
> +};
> +
> struct PragmaMSPointersToMembers : public PragmaHandler {
> explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
> void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
> @@ -334,6 +344,8 @@ void Parser::initializePragmaHandlers() {
> PP.AddPragmaHandler(MSCommentHandler.get());
> }
>
> + FloatControlHandler = std::make_unique<PragmaFloatControlHandler>(Actions);
> + PP.AddPragmaHandler(FloatControlHandler.get());
> if (getLangOpts().MicrosoftExt) {
> MSDetectMismatchHandler =
> std::make_unique<PragmaDetectMismatchHandler>(Actions);
> @@ -438,6 +450,8 @@ void Parser::resetPragmaHandlers() {
> PP.RemovePragmaHandler("clang", PCSectionHandler.get());
> PCSectionHandler.reset();
>
> + PP.RemovePragmaHandler(FloatControlHandler.get());
> + FloatControlHandler.reset();
> if (getLangOpts().MicrosoftExt) {
> PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
> MSDetectMismatchHandler.reset();
> @@ -646,6 +660,22 @@ void Parser::HandlePragmaFPContract() {
> 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() {
> assert(Tok.is(tok::annot_pragma_fenv_access));
> tok::OnOffSwitch OOS =
> @@ -665,8 +695,8 @@ void Parser::HandlePragmaFEnvAccess() {
> break;
> }
>
> - Actions.ActOnPragmaFEnvAccess(FPC);
> - ConsumeAnnotationToken();
> + SourceLocation PragmaLoc = ConsumeAnnotationToken();
> + Actions.ActOnPragmaFEnvAccess(PragmaLoc, FPC);
> }
>
>
> @@ -2489,6 +2519,129 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP,
> 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.
> ///
> /// The syntax is:
> @@ -2749,7 +2902,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
>
> auto *AnnotValue = new (PP.getPreprocessorAllocator())
> TokFPAnnotValue{*FlagKind, *FlagValue};
> - // Generate the loop hint token.
> + // Generate the fp annotation token.
> Token FPTok;
> FPTok.startToken();
> FPTok.setKind(tok::annot_pragma_fp);
>
> diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
> index 770402128395..84166bbbdc7b 100644
> --- a/clang/lib/Parse/ParseStmt.cpp
> +++ b/clang/lib/Parse/ParseStmt.cpp
> @@ -354,13 +354,13 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
>
> case tok::annot_pragma_fp_contract:
> ProhibitAttributes(Attrs);
> - Diag(Tok, diag::err_pragma_fp_contract_scope);
> + Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract";
> ConsumeAnnotationToken();
> return StmtError();
>
> case tok::annot_pragma_fp:
> ProhibitAttributes(Attrs);
> - Diag(Tok, diag::err_pragma_fp_scope);
> + Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp";
> ConsumeAnnotationToken();
> return StmtError();
>
> @@ -369,6 +369,12 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
> HandlePragmaFEnvAccess();
> 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:
> ProhibitAttributes(Attrs);
> HandlePragmaOpenCLExtension();
> @@ -937,6 +943,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
> case tok::annot_pragma_fenv_access:
> HandlePragmaFEnvAccess();
> break;
> + case tok::annot_pragma_float_control:
> + HandlePragmaFloatControl();
> + break;
> case tok::annot_pragma_ms_pointers_to_members:
> HandlePragmaMSPointersToMembers();
> break;
>
> diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
> index 5fa23f2cdc13..de809b9ee849 100644
> --- a/clang/lib/Parse/Parser.cpp
> +++ b/clang/lib/Parse/Parser.cpp
> @@ -752,6 +752,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
> case tok::annot_pragma_fenv_access:
> HandlePragmaFEnvAccess();
> return nullptr;
> + case tok::annot_pragma_float_control:
> + HandlePragmaFloatControl();
> + return nullptr;
> case tok::annot_pragma_fp:
> HandlePragmaFP();
> break;
>
> diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
> index 405b6c33d280..0d2877efe3ee 100644
> --- a/clang/lib/Sema/Sema.cpp
> +++ b/clang/lib/Sema/Sema.cpp
> @@ -159,7 +159,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
> LangOpts.getMSPointerToMemberRepresentationMethod()),
> VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
> DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
> - CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
> + CodeSegStack(nullptr), FpPragmaStack(CurFPFeatures.getAsOpaqueInt()),
> + CurInitSeg(nullptr), VisContext(nullptr),
> PragmaAttributeCurrentTargetDecl(nullptr),
> IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
> LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
>
> diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
> index 8633581b6880..518ac0f070c1 100644
> --- a/clang/lib/Sema/SemaAttr.cpp
> +++ b/clang/lib/Sema/SemaAttr.cpp
> @@ -407,6 +407,65 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
> 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(
> LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
> SourceLocation PragmaLoc) {
> @@ -948,9 +1007,16 @@ void Sema::setExceptionMode(LangOptions::FPExceptionModeKind FPE) {
> CurFPFeatures.setExceptionMode(FPE);
> }
>
> -void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
> +void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc,
> + LangOptions::FEnvAccessModeKind FPC) {
> switch (FPC) {
> 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();
> break;
> case LangOptions::FEA_Off:
> @@ -959,7 +1025,6 @@ void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
> }
> }
>
> -
> void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
> SourceLocation Loc) {
> // Visibility calculations will consider the namespace's visibility.
>
> diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
> index 78d9322bf393..935ac93e9922 100644
> --- a/clang/lib/Sema/SemaDeclCXX.cpp
> +++ b/clang/lib/Sema/SemaDeclCXX.cpp
> @@ -13455,13 +13455,13 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
> // directly construct UnaryOperators here because semantic analysis
> // does not permit us to take the address of an xvalue.
> Expr *From = FromB.build(S, Loc);
> - From = new (S.Context) UnaryOperator(From, UO_AddrOf,
> - S.Context.getPointerType(From->getType()),
> - VK_RValue, OK_Ordinary, Loc, false);
> + From = UnaryOperator::Create(
> + S.Context, From, UO_AddrOf, S.Context.getPointerType(From->getType()),
> + VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatures);
> Expr *To = ToB.build(S, Loc);
> - To = new (S.Context) UnaryOperator(To, UO_AddrOf,
> - S.Context.getPointerType(To->getType()),
> - VK_RValue, OK_Ordinary, Loc, false);
> + To = UnaryOperator::Create(S.Context, To, UO_AddrOf,
> + S.Context.getPointerType(To->getType()), VK_RValue,
> + OK_Ordinary, Loc, false, S.CurFPFeatures);
>
> const Type *E = T->getBaseElementTypeUnsafe();
> bool NeedsCollectableMemCpy =
> @@ -13703,9 +13703,9 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
> // Create the pre-increment of the iteration variable. We can determine
> // whether the increment will overflow based on the value of the array
> // bound.
> - Expr *Increment = new (S.Context)
> - UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType,
> - VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue());
> + Expr *Increment = UnaryOperator::Create(
> + S.Context, IterationVarRef.build(S, Loc), UO_PreInc, SizeType, VK_LValue,
> + OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatures);
>
> // Construct the loop that copies all elements of this array.
> return S.ActOnForStmt(
>
> diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
> index 5b28015dba03..7e8446c6f1ab 100644
> --- a/clang/lib/Sema/SemaExpr.cpp
> +++ b/clang/lib/Sema/SemaExpr.cpp
> @@ -13662,14 +13662,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
> if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
> 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
> // 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
> @@ -14319,8 +14311,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
> if (Opc != UO_AddrOf && Opc != UO_Deref)
> CheckArrayAccess(Input.get());
>
> - auto *UO = new (Context)
> - UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow);
> + auto *UO = UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK,
> + OK, OpLoc, CanOverflow, CurFPFeatures);
>
> if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) &&
> !isa<ArrayType>(UO->getType().getDesugaredType(Context)))
>
> diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
> index 10a7cf3e22d0..11ab4db1e485 100644
> --- a/clang/lib/Sema/SemaExprObjC.cpp
> +++ b/clang/lib/Sema/SemaExprObjC.cpp
> @@ -4427,9 +4427,9 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
> } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
> assert(uo->getOpcode() == UO_Extension);
> Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
> - return new (Context)
> - UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(),
> - sub->getObjectKind(), uo->getOperatorLoc(), false);
> + return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(),
> + sub->getValueKind(), sub->getObjectKind(),
> + uo->getOperatorLoc(), false, CurFPFeatures);
> } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
> assert(!gse->isResultDependent());
>
>
> diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
> index fb5eff006fd3..57b650de3fee 100644
> --- a/clang/lib/Sema/SemaOverload.cpp
> +++ b/clang/lib/Sema/SemaOverload.cpp
> @@ -13001,8 +13001,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
>
> if (Input->isTypeDependent()) {
> if (Fns.empty())
> - return new (Context) UnaryOperator(Input, Opc, Context.DependentTy,
> - VK_RValue, OK_Ordinary, OpLoc, false);
> + return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy,
> + VK_RValue, OK_Ordinary, OpLoc, false,
> + CurFPFeatures);
>
> CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
> UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(
> @@ -14802,9 +14803,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
> if (Context.getTargetInfo().getCXXABI().isMicrosoft())
> (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
>
> - return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType,
> - VK_RValue, OK_Ordinary,
> - UnOp->getOperatorLoc(), false);
> + return UnaryOperator::Create(
> + Context, SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary,
> + UnOp->getOperatorLoc(), false, CurFPFeatures);
> }
> }
> Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
> @@ -14812,10 +14813,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
> if (SubExpr == UnOp->getSubExpr())
> return UnOp;
>
> - return new (Context) UnaryOperator(SubExpr, UO_AddrOf,
> - Context.getPointerType(SubExpr->getType()),
> - VK_RValue, OK_Ordinary,
> - UnOp->getOperatorLoc(), false);
> + return UnaryOperator::Create(
> + Context, SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()),
> + VK_RValue, OK_Ordinary, UnOp->getOperatorLoc(), false, CurFPFeatures);
> }
>
> if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
>
> diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
> index 0ed45221177b..da777201af88 100644
> --- a/clang/lib/Sema/SemaPseudoObject.cpp
> +++ b/clang/lib/Sema/SemaPseudoObject.cpp
> @@ -127,12 +127,10 @@ namespace {
> if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
> assert(uop->getOpcode() == UO_Extension);
> e = rebuild(uop->getSubExpr());
> - return new (S.Context) UnaryOperator(e, uop->getOpcode(),
> - uop->getType(),
> - uop->getValueKind(),
> - uop->getObjectKind(),
> - uop->getOperatorLoc(),
> - uop->canOverflow());
> + return UnaryOperator::Create(
> + S.Context, e, uop->getOpcode(), uop->getType(), uop->getValueKind(),
> + uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(),
> + S.CurFPFeatures);
> }
>
> if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
> @@ -526,12 +524,14 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
> (result.get()->isTypeDependent() || CanCaptureValue(result.get())))
> setResultToLastSemantic();
>
> - UnaryOperator *syntactic = new (S.Context) UnaryOperator(
> - syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc,
> - !resultType->isDependentType()
> - ? S.Context.getTypeSize(resultType) >=
> - S.Context.getTypeSize(S.Context.IntTy)
> - : false);
> + UnaryOperator *syntactic =
> + UnaryOperator::Create(S.Context, syntacticOp, opcode, resultType,
> + VK_LValue, OK_Ordinary, opcLoc,
> + !resultType->isDependentType()
> + ? S.Context.getTypeSize(resultType) >=
> + S.Context.getTypeSize(S.Context.IntTy)
> + : false,
> + S.CurFPFeatures);
> return complete(syntactic);
> }
>
> @@ -1551,8 +1551,9 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
> UnaryOperatorKind opcode, Expr *op) {
> // Do nothing if the operand is dependent.
> if (op->isTypeDependent())
> - return new (Context) UnaryOperator(op, opcode, Context.DependentTy,
> - VK_RValue, OK_Ordinary, opcLoc, false);
> + return UnaryOperator::Create(Context, op, opcode, Context.DependentTy,
> + VK_RValue, OK_Ordinary, opcLoc, false,
> + CurFPFeatures);
>
> assert(UnaryOperator::isIncrementDecrementOp(opcode));
> Expr *opaqueRef = op->IgnoreParens();
> @@ -1636,9 +1637,10 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
> Expr *syntax = E->getSyntacticForm();
> if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
> Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
> - return new (Context) UnaryOperator(
> - op, uop->getOpcode(), uop->getType(), uop->getValueKind(),
> - uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow());
> + return UnaryOperator::Create(Context, op, uop->getOpcode(), uop->getType(),
> + uop->getValueKind(), uop->getObjectKind(),
> + uop->getOperatorLoc(), uop->canOverflow(),
> + CurFPFeatures);
> } else if (CompoundAssignOperator *cop
> = dyn_cast<CompoundAssignOperator>(syntax)) {
> Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
>
> diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
> index aa0d89ac09c3..f76994a6dab3 100644
> --- a/clang/lib/Sema/SemaStmt.cpp
> +++ b/clang/lib/Sema/SemaStmt.cpp
> @@ -394,6 +394,11 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
> ArrayRef<Stmt *> Elts, bool isStmtExpr) {
> 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
> // so, emit an extension diagnostic.
> if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
>
> diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
> index 3ead713b5e06..187665be5255 100644
> --- a/clang/lib/Serialization/ASTReader.cpp
> +++ b/clang/lib/Serialization/ASTReader.cpp
> @@ -3779,6 +3779,29 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
> 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:
> for (unsigned I = 0, N = Record.size(); I != N; ++I)
> DeclsToCheckForDeferredDiags.push_back(getGlobalDeclID(F, Record[I]));
> @@ -7853,6 +7876,34 @@ void ASTReader::UpdateSema() {
> 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) {
>
> diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
> index 2c91af31ee14..e0a6e532cb7b 100644
> --- a/clang/lib/Serialization/ASTReaderStmt.cpp
> +++ b/clang/lib/Serialization/ASTReaderStmt.cpp
> @@ -682,10 +682,14 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
>
> void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
> VisitExpr(E);
> + bool hasFP_Features = Record.readInt();
> + assert(hasFP_Features == E->hasStoredFPFeatures());
> E->setSubExpr(Record.readSubExpr());
> E->setOpcode((UnaryOperator::Opcode)Record.readInt());
> E->setOperatorLoc(readSourceLocation());
> E->setCanOverflow(Record.readInt());
> + if (hasFP_Features)
> + E->setStoredFPFeatures(FPOptions(Record.readInt()));
> }
>
> void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
> @@ -2889,7 +2893,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
> break;
>
> case EXPR_UNARY_OPERATOR:
> - S = new (Context) UnaryOperator(Empty);
> + S = UnaryOperator::CreateEmpty(Context,
> + Record[ASTStmtReader::NumExprFields]);
> break;
>
> case EXPR_OFFSETOF:
>
> diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
> index 462f27578c0f..b2281abe5ba5 100644
> --- a/clang/lib/Serialization/ASTWriter.cpp
> +++ b/clang/lib/Serialization/ASTWriter.cpp
> @@ -4139,6 +4139,26 @@ void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) {
> 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,
> ModuleFileExtensionWriter &Writer) {
> // Enter the extension block.
> @@ -4867,6 +4887,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
> WriteMSPointersToMembersPragmaOptions(SemaRef);
> }
> WritePackPragmaOptions(SemaRef);
> + WriteFloatControlPragmaOptions(SemaRef);
>
> // Some simple statistics
> RecordData::value_type Record[] = {
>
> diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
> index fc96cffcb2ec..ec1b57785f1c 100644
> --- a/clang/lib/Serialization/ASTWriterStmt.cpp
> +++ b/clang/lib/Serialization/ASTWriterStmt.cpp
> @@ -702,10 +702,16 @@ void ASTStmtWriter::VisitParenListExpr(ParenListExpr *E) {
>
> void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *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.push_back(E->getOpcode()); // FIXME: stable encoding
> Record.AddSourceLocation(E->getOperatorLoc());
> Record.push_back(E->canOverflow());
> + if (HasFPFeatures)
> + Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
> Code = serialization::EXPR_UNARY_OPERATOR;
> }
>
>
> diff --git a/clang/test/CodeGen/builtins-nvptx.c b/clang/test/CodeGen/builtins-nvptx.c
> index 31c3ecdb1497..1f7a8c62ac2c 100644
> --- a/clang/test/CodeGen/builtins-nvptx.c
> +++ b/clang/test/CodeGen/builtins-nvptx.c
> @@ -1,11 +1,11 @@
> // 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: | 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: | 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: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s
> // RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_53 \
>
> diff --git a/clang/test/CodeGen/constrained-math-builtins.c b/clang/test/CodeGen/constrained-math-builtins.c
> index b22cfe61d313..fe303eb0d5c2 100644
> --- a/clang/test/CodeGen/constrained-math-builtins.c
> +++ b/clang/test/CodeGen/constrained-math-builtins.c
> @@ -154,9 +154,9 @@ void bar(float f) {
> (double)f * f - f;
> (long double)-f * f + f;
>
> -// CHECK: call float @llvm.experimental.constrained.fmuladd.f32
> -// CHECK: fneg
> -// CHECK: call double @llvm.experimental.constrained.fmuladd.f64
> -// CHECK: fneg
> -// CHECK: call x86_fp80 @llvm.experimental.constrained.fmuladd.f80
> + // CHECK: call contract float @llvm.experimental.constrained.fmuladd.f32
> + // CHECK: fneg
> + // CHECK: call contract double @llvm.experimental.constrained.fmuladd.f64
> + // CHECK: fneg
> + // CHECK: call contract x86_fp80 @llvm.experimental.constrained.fmuladd.f80
> };
>
> diff --git a/clang/test/CodeGen/fast-math.c b/clang/test/CodeGen/fast-math.c
> index 6f98b8432746..6ebd65a22c92 100644
> --- a/clang/test/CodeGen/fast-math.c
> +++ b/clang/test/CodeGen/fast-math.c
> @@ -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;
>
> void foo(void) {
>
> diff --git a/clang/test/CodeGen/fp-contract-on-pragma.cpp b/clang/test/CodeGen/fp-contract-on-pragma.cpp
> index 812a7176b515..5f7463608660 100644
> --- a/clang/test/CodeGen/fp-contract-on-pragma.cpp
> +++ b/clang/test/CodeGen/fp-contract-on-pragma.cpp
> @@ -3,7 +3,7 @@
> // Is FP_CONTRACT honored in a simple case?
> float fp_contract_1(float a, float b, float c) {
> // CHECK: _Z13fp_contract_1fff
> -// CHECK: tail call float @llvm.fmuladd
> +// CHECK: tail call contract float @llvm.fmuladd
> #pragma clang fp contract(on)
> 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) {
> // CHECK: _Z13fp_contract_3fff
> - // CHECK: tail call float @llvm.fmuladd
> + // CHECK: tail call contract float @llvm.fmuladd
> return template_muladd<float>(a, b, c);
> }
>
> @@ -45,13 +45,13 @@ class fp_contract_4 {
>
> template class fp_contract_4<int>;
> // CHECK: _ZN13fp_contract_4IiE6methodEfff
> -// CHECK: tail call float @llvm.fmuladd
> +// CHECK: tail call contract float @llvm.fmuladd
>
> // Check file-scoped FP_CONTRACT
> #pragma clang fp contract(on)
> float fp_contract_5(float a, float b, float c) {
> // CHECK: _Z13fp_contract_5fff
> - // CHECK: tail call float @llvm.fmuladd
> + // CHECK: tail call contract float @llvm.fmuladd
> 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) {
> // CHECK: _Z13fp_contract_7fff
> -// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
> -// CHECK-NEXT: fsub float %[[M]], %c
> +// CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
> +// CHECK-NEXT: fsub contract float %[[M]], %c
> #pragma clang fp contract(on)
> return (a = 2 * b) - c;
> }
>
> diff --git a/clang/test/CodeGen/fp-contract-pragma.cpp b/clang/test/CodeGen/fp-contract-pragma.cpp
> index 805cc5d9c299..3a861ab613cd 100644
> --- a/clang/test/CodeGen/fp-contract-pragma.cpp
> +++ b/clang/test/CodeGen/fp-contract-pragma.cpp
> @@ -2,9 +2,9 @@
>
> // Is FP_CONTRACT honored in a simple case?
> float fp_contract_1(float a, float b, float c) {
> -// CHECK: _Z13fp_contract_1fff
> -// CHECK: tail call float @llvm.fmuladd
> - #pragma STDC FP_CONTRACT ON
> + // CHECK: _Z13fp_contract_1fff
> + // CHECK: tail call contract float @llvm.fmuladd
> +#pragma STDC FP_CONTRACT ON
> 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) {
> -// CHECK: _Z13fp_contract_3fff
> -// CHECK: tail call float @llvm.fmuladd
> + // CHECK: _Z13fp_contract_3fff
> + // CHECK: tail call contract float @llvm.fmuladd
> return template_muladd<float>(a, b, c);
> }
>
> @@ -44,13 +44,13 @@ template<typename T> class fp_contract_4 {
>
> template class fp_contract_4<int>;
> // CHECK: _ZN13fp_contract_4IiE6methodEfff
> -// CHECK: tail call float @llvm.fmuladd
> +// CHECK: tail call contract float @llvm.fmuladd
>
> // Check file-scoped FP_CONTRACT
> #pragma STDC FP_CONTRACT ON
> float fp_contract_5(float a, float b, float c) {
> -// CHECK: _Z13fp_contract_5fff
> -// CHECK: tail call float @llvm.fmuladd
> + // CHECK: _Z13fp_contract_5fff
> + // CHECK: tail call contract float @llvm.fmuladd
> 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
>
> float fp_contract_7(float a, float b, float c) {
> -// CHECK: _Z13fp_contract_7fff
> -// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
> -// CHECK-NEXT: fsub float %[[M]], %c
> - #pragma STDC FP_CONTRACT ON
> + // CHECK: _Z13fp_contract_7fff
> + // CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
> + // CHECK-NEXT: fsub contract float %[[M]], %c
> +#pragma STDC FP_CONTRACT ON
> return (a = 2 * b) - c;
> }
>
> float fp_contract_8(float a, float b, float c) {
> -// CHECK: _Z13fp_contract_8fff
> -// CHECK: fneg float %c
> -// CHECK: tail call float @llvm.fmuladd
> - #pragma STDC FP_CONTRACT ON
> + // CHECK: _Z13fp_contract_8fff
> + // CHECK: fneg contract float %c
> + // CHECK: tail call contract float @llvm.fmuladd
> +#pragma STDC FP_CONTRACT ON
> return a * b - c;
> }
>
> float fp_contract_9(float a, float b, float c) {
> -// CHECK: _Z13fp_contract_9fff
> -// CHECK: fneg float %a
> -// CHECK: tail call float @llvm.fmuladd
> - #pragma STDC FP_CONTRACT ON
> + // CHECK: _Z13fp_contract_9fff
> + // CHECK: fneg contract float %a
> + // CHECK: tail call contract float @llvm.fmuladd
> +#pragma STDC FP_CONTRACT ON
> return c - a * b;
> }
>
> diff --git a/clang/test/CodeGen/fp-floatcontrol-class.cpp b/clang/test/CodeGen/fp-floatcontrol-class.cpp
> new file mode 100644
> index 000000000000..0e981af37a56
> --- /dev/null
> +++ b/clang/test/CodeGen/fp-floatcontrol-class.cpp
> @@ -0,0 +1,19 @@
> +// RUN: %clang -c -ffp-contract=on -Xclang -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;
>
> diff --git a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
> new file mode 100644
> index 000000000000..24bab05028a6
> --- /dev/null
> +++ b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
> @@ -0,0 +1,47 @@
> +// RUN: %clang_cc1 -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;
> +}
>
> diff --git a/clang/test/CodeGen/fp-floatcontrol-stack.cpp b/clang/test/CodeGen/fp-floatcontrol-stack.cpp
> new file mode 100644
> index 000000000000..2e7f43aa7baa
> --- /dev/null
> +++ b/clang/test/CodeGen/fp-floatcontrol-stack.cpp
> @@ -0,0 +1,253 @@
> +// RUN: %clang -c -ffp-contract=on -DDEFAULT=1 -Xclang -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s
> +// RUN: %clang -c -ffp-contract=on -DEBSTRICT=1 -ffp-exception-behavior=strict -Xclang -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s
> +// RUN: %clang -c -DFAST=1 -ffast-math -Xclang -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-FAST %s
> +// RUN: %clang -c -ffp-contract=on -DNOHONOR=1 -fno-honor-nans -fno-honor-infinities -Xclang -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;
>
> diff --git a/clang/test/CodeGen/fpconstrained.c b/clang/test/CodeGen/fpconstrained.c
> index 0a890e2e702e..902d6b5baf49 100644
> --- a/clang/test/CodeGen/fpconstrained.c
> +++ b/clang/test/CodeGen/fpconstrained.c
> @@ -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 -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 -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=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
> @@ -17,6 +17,7 @@ void foo() {
> // STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
> // PRECISE: fadd contract float %{{.*}}, %{{.*}}
> // FAST: fadd fast
> + // FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
> f0 = f1 + f2;
>
> // CHECK: ret
>
> diff --git a/clang/test/CodeGen/fpconstrained.cpp b/clang/test/CodeGen/fpconstrained.cpp
> index 7aa34c98a487..e914abcc6926 100644
> --- a/clang/test/CodeGen/fpconstrained.cpp
> +++ b/clang/test/CodeGen/fpconstrained.cpp
> @@ -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++ -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 -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=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
> @@ -20,16 +20,17 @@ float f0, f1, f2;
> // CHECK-LABEL: define {{.*}}void @_ZN4aaaaIiED2Ev{{.*}}
>
> } catch (...) {
> - // 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")
> - // 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")
> - // STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
> - // PRECISE: fadd contract float %{{.*}}, %{{.*}}
> - // FAST: fadd fast
> - f0 = f1 + f2;
> + // 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")
> + // 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")
> + // STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
> + // PRECISE: fadd contract float %{{.*}}, %{{.*}}
> + // FAST: fadd fast
> + // FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
> + f0 = f1 + f2;
>
> - // CHECK: ret void
> + // CHECK: ret void
> }
> }
>
>
> diff --git a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl
> index 7676ee164ce4..757a2f410dc2 100644
> --- a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl
> +++ b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl
> @@ -8,12 +8,12 @@
> float spscalardiv(float a, float b) {
> // CHECK: @spscalardiv(
>
> - // NORMAL: fdiv float
> + // NORMAL: fdiv contract float
> // FAST: fdiv fast float
> - // FINITE: fdiv nnan ninf float
> - // UNSAFE: fdiv nnan nsz float
> - // MAD: fdiv float
> - // NOSIGNED: fdiv nsz float
> + // FINITE: fdiv nnan ninf contract float
> + // UNSAFE: fdiv nnan nsz contract float
> + // MAD: fdiv contract float
> + // NOSIGNED: fdiv nsz contract float
> return a / b;
> }
> // CHECK: attributes
>
> diff --git a/clang/test/CodeGenOpenCL/single-precision-constant.cl b/clang/test/CodeGenOpenCL/single-precision-constant.cl
> index 6ff7bd1bde2d..061025d7a893 100644
> --- a/clang/test/CodeGenOpenCL/single-precision-constant.cl
> +++ b/clang/test/CodeGenOpenCL/single-precision-constant.cl
> @@ -1,6 +1,6 @@
> // RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s
>
> 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.;
> }
>
> diff --git a/clang/test/Headers/nvptx_device_math_sin.c b/clang/test/Headers/nvptx_device_math_sin.c
> index 75b998d59006..83de8b02444a 100644
> --- a/clang/test/Headers/nvptx_device_math_sin.c
> +++ b/clang/test/Headers/nvptx_device_math_sin.c
> @@ -1,8 +1,8 @@
> // 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 -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 -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 -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 -ffp-contract=fast | FileCheck %s --check-prefix=FAST
> // expected-no-diagnostics
>
> #include <math.h>
>
> diff --git a/clang/test/Headers/nvptx_device_math_sin.cpp b/clang/test/Headers/nvptx_device_math_sin.cpp
> index e4d25b40b1b9..ba5f6fc483d9 100644
> --- a/clang/test/Headers/nvptx_device_math_sin.cpp
> +++ b/clang/test/Headers/nvptx_device_math_sin.cpp
> @@ -1,8 +1,8 @@
> // 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++ -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++ -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++ -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 -ffp-contract=fast | FileCheck %s --check-prefix=FAST
> // expected-no-diagnostics
>
> #include <cmath>
>
> diff --git a/clang/test/PCH/pragma-floatcontrol.c b/clang/test/PCH/pragma-floatcontrol.c
> new file mode 100644
> index 000000000000..a0918dd53597
> --- /dev/null
> +++ b/clang/test/PCH/pragma-floatcontrol.c
> @@ -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
>
> diff --git a/clang/test/Parser/fp-floatcontrol-syntax.cpp b/clang/test/Parser/fp-floatcontrol-syntax.cpp
> new file mode 100644
> index 000000000000..a0e0b020ddb6
> --- /dev/null
> +++ b/clang/test/Parser/fp-floatcontrol-syntax.cpp
> @@ -0,0 +1,63 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify -DCHECK_ERROR %s
> +
> +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 -c -fsyntax-only %s -DDEFAULT -Xclang -verify
> +// RUN: %clang -c -fsyntax-only %s -ffp-model=precise -DPRECISE -Xclang -verify
> +// RUN: %clang -c -fsyntax-only %s -ffp-model=strict -DSTRICT -Xclang -verify
> +// RUN: %clang -c -fsyntax-only %s -ffp-model=fast -DFAST -Xclang -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 at +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
> +//RUN -ffp-model=strict
> +//error: '#pragma float_control(precise, off)' is illegal when except is enabled
> +//with default, fast or precise: no errors
> +
> +#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;
> +}
>
> diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
> index 8a9312614875..6e431bc3ac0f 100644
> --- a/llvm/include/llvm/IR/IRBuilder.h
> +++ b/llvm/include/llvm/IR/IRBuilder.h
> @@ -244,6 +244,8 @@ class IRBuilderBase {
> /// Get the flags to be applied to created floating point ops
> FastMathFlags getFastMathFlags() const { return FMF; }
>
> + FastMathFlags &getFastMathFlags() { return FMF; }
> +
> /// Clear the fast-math flags.
> void clearFastMathFlags() { FMF.clear(); }
>
> @@ -332,10 +334,16 @@ class IRBuilderBase {
> IRBuilderBase &Builder;
> FastMathFlags FMF;
> MDNode *FPMathTag;
> + bool IsFPConstrained;
> + fp::ExceptionBehavior DefaultConstrainedExcept;
> + RoundingMode DefaultConstrainedRounding;
>
> public:
> 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 &operator=(const FastMathFlagGuard &) = delete;
> @@ -343,6 +351,9 @@ class IRBuilderBase {
> ~FastMathFlagGuard() {
> Builder.FMF = FMF;
> Builder.DefaultFPMathTag = FPMathTag;
> + Builder.IsFPConstrained = IsFPConstrained;
> + Builder.DefaultConstrainedExcept = DefaultConstrainedExcept;
> + Builder.DefaultConstrainedRounding = DefaultConstrainedRounding;
> }
> };
>
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list