[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