Merge remote-tracking branch 'origin/swift-4.0-branch' into stable
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 885ad57..8ec370c 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -2312,3 +2312,36 @@
 proven safe to vectorize. To identify and diagnose optimization issues use
 `-Rpass`, `-Rpass-missed`, and `-Rpass-analysis` command line options. See the
 user guide for details.
+
+Extensions to specify floating-point flags
+====================================================
+
+The ``#pragma clang fp`` pragma allows floating-point options 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.
+
+Currently, only FP contraction can be controlled with the pragma. ``#pragma
+clang fp contract`` specifies whether the compiler should contract a multiply
+and an addition (or subtraction) into a fused FMA operation when supported by
+the target.
+
+The pragma can take three values: ``on``, ``fast`` and ``off``.  The ``on``
+option is identical to using ``#pragma STDC FP_CONTRACT(ON)`` and it allows
+fusion as specified the language standard.  The ``fast`` option allows fusiong
+in cases when the language standard does not make this possible (e.g. across
+statements in C)
+
+.. code-block:: c++
+
+  for(...) {
+    #pragma clang fp contract(fast)
+    a = b[i] * c[i];
+    d[i] += a;
+  }
+
+
+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.
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 56b99cc..1ef6b42 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -2917,11 +2917,9 @@
 private:
   unsigned Opc : 6;
 
-  // Records the FP_CONTRACT pragma status at the point that this binary
-  // operator was parsed. This bit is only meaningful for operations on
-  // floating point types. For all other types it should default to
-  // false.
-  unsigned FPContractable : 1;
+  // This is only meaningful for operations on floating point types and 0
+  // otherwise.
+  unsigned FPFeatures : 2;
   SourceLocation OpLoc;
 
   enum { LHS, RHS, END_EXPR };
@@ -2930,7 +2928,7 @@
 
   BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
                  ExprValueKind VK, ExprObjectKind OK,
-                 SourceLocation opLoc, bool fpContractable)
+                 SourceLocation opLoc, FPOptions FPFeatures)
     : Expr(BinaryOperatorClass, ResTy, VK, OK,
            lhs->isTypeDependent() || rhs->isTypeDependent(),
            lhs->isValueDependent() || rhs->isValueDependent(),
@@ -2938,7 +2936,7 @@
             rhs->isInstantiationDependent()),
            (lhs->containsUnexpandedParameterPack() ||
             rhs->containsUnexpandedParameterPack())),
-      Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
+      Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
     assert(!isCompoundAssignmentOp() &&
@@ -3073,16 +3071,20 @@
 
   // Set the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
-  void setFPContractable(bool FPC) { FPContractable = FPC; }
+  void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); }
+
+  FPOptions getFPFeatures() const { return FPOptions(FPFeatures); }
 
   // Get the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
-  bool isFPContractable() const { return FPContractable; }
+  bool isFPContractableWithinStatement() const {
+    return FPOptions(FPFeatures).allowFPContractWithinStatement();
+  }
 
 protected:
   BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
                  ExprValueKind VK, ExprObjectKind OK,
-                 SourceLocation opLoc, bool fpContractable, bool dead2)
+                 SourceLocation opLoc, FPOptions FPFeatures, bool dead2)
     : Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
            lhs->isTypeDependent() || rhs->isTypeDependent(),
            lhs->isValueDependent() || rhs->isValueDependent(),
@@ -3090,7 +3092,7 @@
             rhs->isInstantiationDependent()),
            (lhs->containsUnexpandedParameterPack() ||
             rhs->containsUnexpandedParameterPack())),
-      Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
+      Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
   }
@@ -3112,8 +3114,8 @@
   CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
                          ExprValueKind VK, ExprObjectKind OK,
                          QualType CompLHSType, QualType CompResultType,
-                         SourceLocation OpLoc, bool fpContractable)
-    : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
+                         SourceLocation OpLoc, FPOptions FPFeatures)
+    : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures,
                      true),
       ComputationLHSType(CompLHSType),
       ComputationResultType(CompResultType) {
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 37e5977..f0cc1e4 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -54,18 +54,16 @@
   OverloadedOperatorKind Operator;
   SourceRange Range;
 
-  // Record the FP_CONTRACT state that applies to this operator call. Only
-  // meaningful for floating point types. For other types this value can be
-  // set to false.
-  unsigned FPContractable : 1;
+  // Only meaningful for floating point types.
+  FPOptions FPFeatures;
 
   SourceRange getSourceRangeImpl() const LLVM_READONLY;
 public:
   CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
                       ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
-                      SourceLocation operatorloc, bool fpContractable)
+                      SourceLocation operatorloc, FPOptions FPFeatures)
     : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
-      Operator(Op), FPContractable(fpContractable) {
+      Operator(Op), FPFeatures(FPFeatures) {
     Range = getSourceRangeImpl();
   }
   explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
@@ -113,11 +111,15 @@
 
   // Set the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
-  void setFPContractable(bool FPC) { FPContractable = FPC; }
+  void setFPFeatures(FPOptions F) { FPFeatures = F; }
+
+  FPOptions getFPFeatures() const { return FPFeatures; }
 
   // Get the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
-  bool isFPContractable() const { return FPContractable; }
+  bool isFPContractableWithinStatement() const {
+    return FPFeatures.allowFPContractWithinStatement();
+  }
 
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3f7de6f..d6ebdb1 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -1040,6 +1040,16 @@
 def err_pragma_loop_invalid_option : Error<
   "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
   "vectorize_width, interleave, interleave_count, unroll, unroll_count, or distribute">;
+
+def err_pragma_fp_invalid_option : Error<
+  "%select{invalid|missing}0 option%select{ %1|}0; expected contract">;
+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/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 19a081c..cf6725d 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -215,7 +215,8 @@
 BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
 LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
 LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math")
-LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT")
+/// \brief FP_CONTRACT mode (on/off/fast).
+ENUM_LANGOPT(DefaultFPContractMode, FPContractModeKind, 2, FPC_Off, "FP contraction type")
 LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
 LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
 LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 10635b1..e156068 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -88,6 +88,12 @@
     MSVC2015 = 19
   };
 
+  enum FPContractModeKind {
+    FPC_Off,        // Form fused FP ops only where result will not be affected.
+    FPC_On,         // Form fused FP ops according to FP_CONTRACT rules.
+    FPC_Fast        // Aggressively fuse FP ops (E.g. FMA).
+  };
+
 public:
   /// \brief Set of enabled sanitizers.
   SanitizerSet Sanitize;
@@ -175,12 +181,35 @@
 /// \brief Floating point control options
 class FPOptions {
 public:
-  unsigned fp_contract : 1;
+  FPOptions() : fp_contract(LangOptions::FPC_Off) {}
 
-  FPOptions() : fp_contract(0) {}
+  // Used for serializing.
+  explicit FPOptions(unsigned I)
+      : fp_contract(static_cast<LangOptions::FPContractModeKind>(I)) {}
 
-  FPOptions(const LangOptions &LangOpts) :
-    fp_contract(LangOpts.DefaultFPContract) {}
+  explicit FPOptions(const LangOptions &LangOpts)
+      : fp_contract(LangOpts.getDefaultFPContractMode()) {}
+
+  bool allowFPContractWithinStatement() const {
+    return fp_contract == LangOptions::FPC_On;
+  }
+  bool allowFPContractAcrossStatement() const {
+    return fp_contract == LangOptions::FPC_Fast;
+  }
+  void setAllowFPContractWithinStatement() {
+    fp_contract = LangOptions::FPC_On;
+  }
+  void setAllowFPContractAcrossStatement() {
+    fp_contract = LangOptions::FPC_Fast;
+  }
+  void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; }
+
+  /// Used to serialize this.
+  unsigned getInt() const { return fp_contract; }
+
+private:
+  /// Adjust BinaryOperator::FPFeatures to match the bit-field size of this.
+  unsigned fp_contract : 2;
 };
 
 /// \brief Describes the kind of translation unit being processed.
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 104b053..0439933 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -787,6 +787,8 @@
 // handles #pragma loop ... directives.
 ANNOTATION(pragma_loop_hint)
 
+ANNOTATION(pragma_fp)
+
 // Annotations for module import translated from #include etc.
 ANNOTATION(module_include)
 ANNOTATION(module_begin)
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 964a6cc..4863f1c 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -65,8 +65,6 @@
 CODEGENOPT(EmitGcovNotes     , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
 CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
 CODEGENOPT(EmulatedTLS       , 1, 0) ///< Set when -femulated-tls is enabled.
-/// \brief FP_CONTRACT mode (on/off/fast).
-ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On)
 /// \brief Embed Bitcode mode (off/all/bitcode/marker).
 ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
 CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 52bd1c5..47f7147 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -69,12 +69,6 @@
     LocalExecTLSModel
   };
 
-  enum FPContractModeKind {
-    FPC_Off,        // Form fused FP ops only where result will not be affected.
-    FPC_On,         // Form fused FP ops according to FP_CONTRACT rules.
-    FPC_Fast        // Aggressively fuse FP ops (E.g. FMA).
-  };
-
   enum StructReturnConventionKind {
     SRCK_Default,  // No special option was passed.
     SRCK_OnStack,  // Small structs on the stack (-fpcc-struct-return).
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 2e93bec..a3c7b7b 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -183,6 +183,7 @@
   std::unique_ptr<PragmaHandler> LoopHintHandler;
   std::unique_ptr<PragmaHandler> UnrollHintHandler;
   std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
+  std::unique_ptr<PragmaHandler> FPHandler;
 
   std::unique_ptr<CommentHandler> CommentSemaHandler;
 
@@ -549,6 +550,10 @@
   void HandlePragmaFPContract();
 
   /// \brief Handle the annotation token produced for
+  /// #pragma clang fp ...
+  void HandlePragmaFP();
+
+  /// \brief Handle the annotation token produced for
   /// #pragma OPENCL EXTENSION...
   void HandlePragmaOpenCLExtension();
 
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 51aa988..15367b2 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1061,14 +1061,12 @@
   /// statements.
   class FPContractStateRAII {
   public:
-    FPContractStateRAII(Sema& S)
-      : S(S), OldFPContractState(S.FPFeatures.fp_contract) {}
-    ~FPContractStateRAII() {
-      S.FPFeatures.fp_contract = OldFPContractState;
-    }
+    FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {}
+    ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; }
+
   private:
     Sema& S;
-    bool OldFPContractState : 1;
+    FPOptions OldFPFeaturesState;
   };
 
   void addImplicitTypedef(StringRef Name, QualType T);
@@ -8093,8 +8091,9 @@
                             SourceLocation AliasNameLoc);
 
   /// ActOnPragmaFPContract - Called on well formed
-  /// \#pragma {STDC,OPENCL} FP_CONTRACT
-  void ActOnPragmaFPContract(tok::OnOffSwitch OOS);
+  /// \#pragma {STDC,OPENCL} FP_CONTRACT and
+  /// \#pragma clang fp contract
+  void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC);
 
   /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
   /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'.
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 017cc8c..4ae6be9 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -5862,7 +5862,7 @@
                                                       T, E->getValueKind(),
                                                       E->getObjectKind(),
                                            Importer.Import(E->getOperatorLoc()),
-                                                      E->isFPContractable());
+                                                      E->getFPFeatures());
 }
 
 Expr *ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
@@ -6012,7 +6012,7 @@
                                                E->getObjectKind(),
                                                CompLHSType, CompResultType,
                                            Importer.Import(E->getOperatorLoc()),
-                                               E->isFPContractable());
+                                               E->getFPFeatures());
 }
 
 bool ASTNodeImporter::ImportCastPath(CastExpr *CE, CXXCastPath &Path) {
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 56c812c..5912724 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -87,7 +87,7 @@
                                          QualType Ty) {
  return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
                                BO_Assign, Ty, VK_RValue,
-                               OK_Ordinary, SourceLocation(), false);
+                               OK_Ordinary, SourceLocation(), FPOptions());
 }
 
 BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
@@ -99,7 +99,7 @@
                                 Op,
                                 C.getLogicalOperationType(),
                                 VK_RValue,
-                                OK_Ordinary, SourceLocation(), false);
+                                OK_Ordinary, SourceLocation(), FPOptions());
 }
 
 CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 328ac5b..e883f15 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -557,14 +557,14 @@
           .Default(llvm::FloatABI::Default);
 
   // Set FP fusion mode.
-  switch (CodeGenOpts.getFPContractMode()) {
-  case CodeGenOptions::FPC_Off:
+  switch (LangOpts.getDefaultFPContractMode()) {
+  case LangOptions::FPC_Off:
     Options.AllowFPOpFusion = llvm::FPOpFusion::Strict;
     break;
-  case CodeGenOptions::FPC_On:
+  case LangOptions::FPC_On:
     Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
     break;
-  case CodeGenOptions::FPC_Fast:
+  case LangOptions::FPC_Fast:
     Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
     break;
   }
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 322ee87..ebd7c95 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -48,7 +48,7 @@
   Value *RHS;
   QualType Ty;  // Computation Type.
   BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
-  bool FPContractable;
+  FPOptions FPFeatures;
   const Expr *E;      // Entire expr, for error unsupported.  May not be binop.
 };
 
@@ -112,6 +112,22 @@
          (2 * Ctx.getTypeSize(RHSTy)) < PromotedSize;
 }
 
+/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
+static void updateFastMathFlags(llvm::FastMathFlags &FMF,
+                                FPOptions FPFeatures) {
+  FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement());
+}
+
+/// Propagate fast-math flags from \p Op to the instruction in \p V.
+static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) {
+  if (auto *I = dyn_cast<llvm::Instruction>(V)) {
+    llvm::FastMathFlags FMF = I->getFastMathFlags();
+    updateFastMathFlags(FMF, Op.FPFeatures);
+    I->setFastMathFlags(FMF);
+  }
+  return V;
+}
+
 class ScalarExprEmitter
   : public StmtVisitor<ScalarExprEmitter, Value*> {
   CodeGenFunction &CGF;
@@ -547,8 +563,10 @@
         !CanElideOverflowCheck(CGF.getContext(), Ops))
       return EmitOverflowCheckedBinOp(Ops);
 
-    if (Ops.LHS->getType()->isFPOrFPVectorTy())
-      return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
+    if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
+      Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
+      return propagateFMFlags(V, Ops);
+    }
     return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
   }
   /// Create a binary op that checks for overflow.
@@ -1702,7 +1720,7 @@
   BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false);
   BinOp.Ty = E->getType();
   BinOp.Opcode = IsInc ? BO_Add : BO_Sub;
-  BinOp.FPContractable = false;
+  // FIXME: once UnaryOperator carries FPFeatures, copy it here.
   BinOp.E = E;
   return BinOp;
 }
@@ -1968,7 +1986,7 @@
     BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
   BinOp.Ty = E->getType();
   BinOp.Opcode = BO_Sub;
-  BinOp.FPContractable = false;
+  // FIXME: once UnaryOperator carries FPFeatures, copy it here.
   BinOp.E = E;
   return EmitSub(BinOp);
 }
@@ -2189,7 +2207,7 @@
   Result.RHS = Visit(E->getRHS());
   Result.Ty  = E->getType();
   Result.Opcode = E->getOpcode();
-  Result.FPContractable = E->isFPContractable();
+  Result.FPFeatures = E->getFPFeatures();
   Result.E = E;
   return Result;
 }
@@ -2209,7 +2227,7 @@
   OpInfo.RHS = Visit(E->getRHS());
   OpInfo.Ty = E->getComputationResultType();
   OpInfo.Opcode = E->getOpcode();
-  OpInfo.FPContractable = E->isFPContractable();
+  OpInfo.FPFeatures = E->getFPFeatures();
   OpInfo.E = E;
   // Load/convert the LHS.
   LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
@@ -2656,12 +2674,7 @@
          "Only fadd/fsub can be the root of an fmuladd.");
 
   // Check whether this op is marked as fusable.
-  if (!op.FPContractable)
-    return nullptr;
-
-  // Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is
-  // either disabled, or handled entirely by the LLVM backend).
-  if (CGF.CGM.getCodeGenOpts().getFPContractMode() != CodeGenOptions::FPC_On)
+  if (!op.FPFeatures.allowFPContractWithinStatement())
     return nullptr;
 
   // We have a potentially fusable op. Look for a mul on one of the operands.
@@ -2711,7 +2724,8 @@
     if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
       return FMulAdd;
 
-    return Builder.CreateFAdd(op.LHS, op.RHS, "add");
+    Value *V = Builder.CreateFAdd(op.LHS, op.RHS, "add");
+    return propagateFMFlags(V, op);
   }
 
   return Builder.CreateAdd(op.LHS, op.RHS, "add");
@@ -2744,7 +2758,8 @@
       // Try to form an fmuladd.
       if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
         return FMulAdd;
-      return Builder.CreateFSub(op.LHS, op.RHS, "sub");
+      Value *V = Builder.CreateFSub(op.LHS, op.RHS, "sub");
+      return propagateFMFlags(V, op);
     }
 
     return Builder.CreateSub(op.LHS, op.RHS, "sub");
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 03d3fb3..144ef32 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -1316,7 +1316,7 @@
 
   BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
                         ivarRef.getType(), VK_RValue, OK_Ordinary,
-                        SourceLocation(), false);
+                        SourceLocation(), FPOptions());
   EmitStmt(&assign);
 }
 
@@ -3239,7 +3239,7 @@
   CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
   CXXOperatorCallExpr TheCall(C, OO_Equal, CalleeExp->getCallee(),
                               Args, DestTy->getPointeeType(),
-                              VK_LValue, SourceLocation(), false);
+                              VK_LValue, SourceLocation(), FPOptions());
   
   EmitStmt(&TheCall);
 
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 39e1cdf..6da9e7a 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -2320,8 +2320,7 @@
     CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
     // Generate condition for loop.
     BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
-                        OK_Ordinary, S.getLocStart(),
-                        /*fpContractable=*/false);
+                        OK_Ordinary, S.getLocStart(), FPOptions());
     // Increment for loop counter.
     UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
                       S.getLocStart());
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index cb092ea..f4d26aa 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -801,18 +801,6 @@
     }
   }
 
-  if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
-    StringRef Val = A->getValue();
-    if (Val == "fast")
-      Opts.setFPContractMode(CodeGenOptions::FPC_Fast);
-    else if (Val == "on")
-      Opts.setFPContractMode(CodeGenOptions::FPC_On);
-    else if (Val == "off")
-      Opts.setFPContractMode(CodeGenOptions::FPC_Off);
-    else
-      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
-  }
-
   if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) {
     StringRef Val = A->getValue();
     if (Val == "ieee")
@@ -1647,7 +1635,7 @@
     Opts.ZVector = 0;
     Opts.CXXOperatorNames = 1;
     Opts.LaxVectorConversions = 0;
-    Opts.DefaultFPContract = 1;
+    Opts.setDefaultFPContractMode(LangOptions::FPC_On);
     Opts.NativeHalfType = 1;
     Opts.NativeHalfArgsAndReturns = 1;
     // Include default header file for OpenCL.
@@ -1658,6 +1646,9 @@
 
   Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda ||
               LangStd == LangStandard::lang_cuda;
+  if (Opts.CUDA)
+    // Set default FP_CONTRACT to FAST.
+    Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
 
   Opts.RenderScript = IK == IK_RenderScript;
   if (Opts.RenderScript) {
@@ -2245,6 +2236,18 @@
                       Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
                       Args.hasArg(OPT_cl_fast_relaxed_math);
 
+  if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
+    StringRef Val = A->getValue();
+    if (Val == "fast")
+      Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
+    else if (Val == "on")
+      Opts.setDefaultFPContractMode(LangOptions::FPC_On);
+    else if (Val == "off")
+      Opts.setDefaultFPContractMode(LangOptions::FPC_Off);
+    else
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+  }
+
   Opts.RetainCommentsFromSystemHeaders =
       Args.hasArg(OPT_fretain_comments_from_system_headers);
 
@@ -2508,10 +2511,6 @@
     // triple used for host compilation.
     if (LangOpts.CUDAIsDevice)
       Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
-
-    // Set default FP_CONTRACT to FAST.
-    if (!Args.hasArg(OPT_ffp_contract))
-      Res.getCodeGenOpts().setFPContractMode(CodeGenOptions::FPC_Fast);
   }
 
   // FIXME: Override value name discarding when asan or msan is used because the
diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index e7bfced..cd22e82 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -7500,7 +7500,7 @@
       BinaryOperator *addExpr = 
         new (Context) BinaryOperator(castExpr, DRE, BO_Add, 
                                      Context->getPointerType(Context->CharTy),
-                                     VK_RValue, OK_Ordinary, SourceLocation(), false);
+                                     VK_RValue, OK_Ordinary, SourceLocation(), FPOptions());
       // Don't forget the parens to enforce the proper binding.
       ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
                                               SourceLocation(),
diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index e842e59..055f3ce 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -2992,7 +2992,7 @@
     BinaryOperator *lessThanExpr = 
       new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
                                    VK_RValue, OK_Ordinary, SourceLocation(),
-                                   false);
+                                   FPOptions());
     // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
     ConditionalOperator *CondExpr =
       new (Context) ConditionalOperator(lessThanExpr,
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 8973323..879d68b 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -86,6 +86,12 @@
                     Token &FirstToken) override;
 };
 
+struct PragmaFPHandler : public PragmaHandler {
+  PragmaFPHandler() : PragmaHandler("fp") {}
+  void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+                    Token &FirstToken) override;
+};
+
 struct PragmaNoOpenMPHandler : public PragmaHandler {
   PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
   void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
@@ -266,6 +272,9 @@
 
   NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
   PP.AddPragmaHandler(NoUnrollHintHandler.get());
+
+  FPHandler.reset(new PragmaFPHandler());
+  PP.AddPragmaHandler("clang", FPHandler.get());
 }
 
 void Parser::resetPragmaHandlers() {
@@ -344,6 +353,9 @@
 
   PP.RemovePragmaHandler(NoUnrollHintHandler.get());
   NoUnrollHintHandler.reset();
+
+  PP.RemovePragmaHandler("clang", FPHandler.get());
+  FPHandler.reset();
 }
 
 /// \brief Handle the annotation token produced for #pragma unused(...)
@@ -454,7 +466,21 @@
   tok::OnOffSwitch OOS =
     static_cast<tok::OnOffSwitch>(
     reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
-  Actions.ActOnPragmaFPContract(OOS);
+
+  LangOptions::FPContractModeKind FPC;
+  switch (OOS) {
+  case tok::OOS_ON:
+    FPC = LangOptions::FPC_On;
+    break;
+  case tok::OOS_OFF:
+    FPC = LangOptions::FPC_Off;
+    break;
+  case tok::OOS_DEFAULT:
+    FPC = getLangOpts().getDefaultFPContractMode();
+    break;
+  }
+
+  Actions.ActOnPragmaFPContract(FPC);
   ConsumeToken(); // The annotation token.
 }
 
@@ -1947,6 +1973,129 @@
   Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
 }
 
+namespace {
+/// Used as the annotation value for tok::annot_pragma_fp.
+struct TokFPAnnotValue {
+  enum FlagKinds { Contract };
+  enum FlagValues { On, Off, Fast };
+
+  FlagKinds FlagKind;
+  FlagValues FlagValue;
+};
+} // end anonymous namespace
+
+void PragmaFPHandler::HandlePragma(Preprocessor &PP,
+                                   PragmaIntroducerKind Introducer,
+                                   Token &Tok) {
+  // fp
+  Token PragmaName = Tok;
+  SmallVector<Token, 1> TokenList;
+
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::identifier)) {
+    PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+        << /*MissingOption=*/true << "";
+    return;
+  }
+
+  while (Tok.is(tok::identifier)) {
+    IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
+
+    auto FlagKind =
+        llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>(
+            OptionInfo->getName())
+            .Case("contract", TokFPAnnotValue::Contract)
+            .Default(None);
+    if (!FlagKind) {
+      PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+          << /*MissingOption=*/false << OptionInfo;
+      return;
+    }
+    PP.Lex(Tok);
+
+    // Read '('
+    if (Tok.isNot(tok::l_paren)) {
+      PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+      return;
+    }
+    PP.Lex(Tok);
+
+    if (Tok.isNot(tok::identifier)) {
+      PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+          << PP.getSpelling(Tok) << OptionInfo->getName();
+      return;
+    }
+    const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+    auto FlagValue =
+        llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>(
+            II->getName())
+            .Case("on", TokFPAnnotValue::On)
+            .Case("off", TokFPAnnotValue::Off)
+            .Case("fast", TokFPAnnotValue::Fast)
+            .Default(llvm::None);
+
+    if (!FlagValue) {
+      PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+          << PP.getSpelling(Tok) << OptionInfo->getName();
+      return;
+    }
+    PP.Lex(Tok);
+
+    // Read ')'
+    if (Tok.isNot(tok::r_paren)) {
+      PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+      return;
+    }
+    PP.Lex(Tok);
+
+    auto *AnnotValue = new (PP.getPreprocessorAllocator())
+        TokFPAnnotValue{*FlagKind, *FlagValue};
+    // Generate the loop hint token.
+    Token FPTok;
+    FPTok.startToken();
+    FPTok.setKind(tok::annot_pragma_fp);
+    FPTok.setLocation(PragmaName.getLocation());
+    FPTok.setAnnotationEndLoc(PragmaName.getLocation());
+    FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
+    TokenList.push_back(FPTok);
+  }
+
+  if (Tok.isNot(tok::eod)) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+        << "clang fp";
+    return;
+  }
+
+  auto TokenArray = llvm::make_unique<Token[]>(TokenList.size());
+  std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
+
+  PP.EnterTokenStream(std::move(TokenArray), TokenList.size(),
+                      /*DisableMacroExpansion=*/false);
+}
+
+void Parser::HandlePragmaFP() {
+  assert(Tok.is(tok::annot_pragma_fp));
+  auto *AnnotValue =
+      reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
+
+  LangOptions::FPContractModeKind FPC;
+  switch (AnnotValue->FlagValue) {
+  case TokFPAnnotValue::On:
+    FPC = LangOptions::FPC_On;
+    break;
+  case TokFPAnnotValue::Fast:
+    FPC = LangOptions::FPC_Fast;
+    break;
+  case TokFPAnnotValue::Off:
+    FPC = LangOptions::FPC_Off;
+    break;
+  }
+
+  Actions.ActOnPragmaFPContract(FPC);
+  ConsumeToken(); // The annotation token.
+}
+
 /// \brief Parses loop or unroll pragma hint value and fills in Info.
 static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
                                Token Option, bool ValueInParens,
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 30e392f..2f19b08 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -341,6 +341,12 @@
     ConsumeToken();
     return StmtError();
 
+  case tok::annot_pragma_fp:
+    ProhibitAttributes(Attrs);
+    Diag(Tok, diag::err_pragma_fp_scope);
+    ConsumeToken();
+    return StmtError();
+
   case tok::annot_pragma_opencl_extension:
     ProhibitAttributes(Attrs);
     HandlePragmaOpenCLExtension();
@@ -900,6 +906,9 @@
     case tok::annot_pragma_fp_contract:
       HandlePragmaFPContract();
       break;
+    case tok::annot_pragma_fp:
+      HandlePragmaFP();
+      break;
     case tok::annot_pragma_ms_pointers_to_members:
       HandlePragmaMSPointersToMembers();
       break;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index d9c383a..bb45366 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -698,6 +698,9 @@
   case tok::annot_pragma_fp_contract:
     HandlePragmaFPContract();
     return nullptr;
+  case tok::annot_pragma_fp:
+    HandlePragmaFP();
+    break;
   case tok::annot_pragma_opencl_extension:
     HandlePragmaOpenCLExtension();
     return nullptr;
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index a3eddcf..c6e3cc8 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -448,16 +448,16 @@
   }
 }
 
-void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) {
-  switch (OOS) {
-  case tok::OOS_ON:
-    FPFeatures.fp_contract = 1;
+void Sema::ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC) {
+  switch (FPC) {
+  case LangOptions::FPC_On:
+    FPFeatures.setAllowFPContractWithinStatement();
     break;
-  case tok::OOS_OFF:
-    FPFeatures.fp_contract = 0; 
+  case LangOptions::FPC_Fast:
+    FPFeatures.setAllowFPContractAcrossStatement();
     break;
-  case tok::OOS_DEFAULT:
-    FPFeatures.fp_contract = getLangOpts().DefaultFPContract;
+  case LangOptions::FPC_Off:
+    FPFeatures.setDisallowFPContract();
     break;
   }
 }
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b1bec1c..a9a8453 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -10855,7 +10855,7 @@
     = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc),
                      IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
                                      BO_NE, S.Context.BoolTy,
-                                     VK_RValue, OK_Ordinary, Loc, false);
+                                     VK_RValue, OK_Ordinary, Loc, FPOptions());
 
   // Create the pre-increment of the iteration variable.
   Expr *Increment
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 8594be1..5d31ad4 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -11181,7 +11181,7 @@
   
   if (CompResultTy.isNull())
     return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK,
-                                        OK, OpLoc, FPFeatures.fp_contract);
+                                        OK, OpLoc, FPFeatures);
   if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
       OK_ObjCProperty) {
     VK = VK_LValue;
@@ -11189,7 +11189,7 @@
   }
   return new (Context) CompoundAssignOperator(
       LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy,
-      OpLoc, FPFeatures.fp_contract);
+      OpLoc, FPFeatures);
 }
 
 /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 9b5fe9a..71894b8 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -6136,7 +6136,7 @@
         return E;
       return new (Context) BinaryOperator(
           BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(),
-          BO->getObjectKind(), BO->getOperatorLoc(), BO->isFPContractable());
+          BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures());
     }
   }
 
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index f976b76..a1fd632 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -11957,7 +11957,7 @@
                                      Fns.begin(), Fns.end());
     return new (Context)
         CXXOperatorCallExpr(Context, Op, Fn, ArgsArray, Context.DependentTy,
-                            VK_RValue, OpLoc, false);
+                            VK_RValue, OpLoc, FPOptions());
   }
 
   // Build an empty overload set.
@@ -12027,7 +12027,7 @@
       Args[0] = Input;
       CallExpr *TheCall =
         new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(), ArgsArray,
-                                          ResultTy, VK, OpLoc, false);
+                                          ResultTy, VK, OpLoc, FPOptions());
 
       if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
         return ExprError();
@@ -12125,12 +12125,12 @@
       if (Opc <= BO_Assign || Opc > BO_OrAssign)
         return new (Context) BinaryOperator(
             Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary,
-            OpLoc, FPFeatures.fp_contract);
+            OpLoc, FPFeatures);
 
       return new (Context) CompoundAssignOperator(
           Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary,
           Context.DependentTy, Context.DependentTy, OpLoc,
-          FPFeatures.fp_contract);
+          FPFeatures);
     }
 
     // FIXME: save results of ADL from here?
@@ -12144,7 +12144,7 @@
                                      Fns.begin(), Fns.end());
     return new (Context)
         CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy,
-                            VK_RValue, OpLoc, FPFeatures.fp_contract);
+                            VK_RValue, OpLoc, FPFeatures);
   }
 
   // Always do placeholder-like conversions on the RHS.
@@ -12259,7 +12259,7 @@
         CXXOperatorCallExpr *TheCall =
           new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(),
                                             Args, ResultTy, VK, OpLoc,
-                                            FPFeatures.fp_contract);
+                                            FPFeatures);
 
         if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
                                 FnDecl))
@@ -12407,7 +12407,7 @@
 
     return new (Context)
         CXXOperatorCallExpr(Context, OO_Subscript, Fn, Args,
-                            Context.DependentTy, VK_RValue, RLoc, false);
+                            Context.DependentTy, VK_RValue, RLoc, FPOptions());
   }
 
   // Handle placeholders on both operands.
@@ -12483,7 +12483,7 @@
           new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
                                             FnExpr.get(), Args,
                                             ResultTy, VK, RLoc,
-                                            false);
+                                            FPOptions());
 
         if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
           return ExprError();
@@ -13046,7 +13046,7 @@
 
   CXXOperatorCallExpr *TheCall = new (Context)
       CXXOperatorCallExpr(Context, OO_Call, NewFn.get(), MethodArgs, ResultTy,
-                          VK, RParenLoc, false);
+                          VK, RParenLoc, FPOptions());
 
   if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
     return true;
@@ -13226,7 +13226,7 @@
   ResultTy = ResultTy.getNonLValueExprType(Context);
   CXXOperatorCallExpr *TheCall =
     new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.get(),
-                                      Base, ResultTy, VK, OpLoc, false);
+                                      Base, ResultTy, VK, OpLoc, FPOptions());
 
   if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
     return ExprError();
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 8e53fda..b740540 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -447,7 +447,8 @@
     syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
                                                opcode, capturedRHS->getType(),
                                                capturedRHS->getValueKind(),
-                                               OK_Ordinary, opcLoc, false);
+                                               OK_Ordinary, opcLoc,
+                                               FPOptions());
   } else {
     ExprResult opLHS = buildGet();
     if (opLHS.isInvalid()) return ExprError();
@@ -465,7 +466,7 @@
                                              OK_Ordinary,
                                              opLHS.get()->getType(),
                                              result.get()->getType(),
-                                             opcLoc, false);
+                                             opcLoc, FPOptions());
   }
 
   // The result of the assignment, if not void, is the value set into
@@ -1587,7 +1588,8 @@
   // Do nothing if either argument is dependent.
   if (LHS->isTypeDependent() || RHS->isTypeDependent())
     return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
-                                        VK_RValue, OK_Ordinary, opcLoc, false);
+                                        VK_RValue, OK_Ordinary, opcLoc,
+                                        FPOptions());
 
   // Filter out non-overload placeholder types in the RHS.
   if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1652,14 +1654,15 @@
                                                 cop->getObjectKind(),
                                                 cop->getComputationLHSType(),
                                                 cop->getComputationResultType(),
-                                                cop->getOperatorLoc(), false);
+                                                cop->getOperatorLoc(),
+                                                FPOptions());
   } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
     Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
     Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
     return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
                                         bop->getType(), bop->getValueKind(),
                                         bop->getObjectKind(),
-                                        bop->getOperatorLoc(), false);
+                                        bop->getOperatorLoc(), FPOptions());
   } else {
     assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
     return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f8e65a1..39ec495 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -8855,7 +8855,7 @@
     return E;
 
   Sema::FPContractStateRAII FPContractState(getSema());
-  getSema().FPFeatures.fp_contract = E->isFPContractable();
+  getSema().FPFeatures = E->getFPFeatures();
 
   return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
                                             LHS.get(), RHS.get());
@@ -9335,7 +9335,7 @@
     return SemaRef.MaybeBindToTemporary(E);
 
   Sema::FPContractStateRAII FPContractState(getSema());
-  getSema().FPFeatures.fp_contract = E->isFPContractable();
+  getSema().FPFeatures = E->getFPFeatures();
 
   return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
                                                  E->getOperatorLoc(),
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index a22f7f4..94548f4 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -7346,7 +7346,7 @@
   // FIXME: What happens if these are changed by a module import?
   if (!FPPragmaOptions.empty()) {
     assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS");
-    SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0];
+    SemaObj->FPFeatures = FPOptions(FPPragmaOptions[0]);
   }
 
   SemaObj->OpenCLFeatures.copy(OpenCLExtensions);
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 686a69b..062fe86 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -665,7 +665,7 @@
   E->setRHS(Record.readSubExpr());
   E->setOpcode((BinaryOperator::Opcode)Record.readInt());
   E->setOperatorLoc(ReadSourceLocation());
-  E->setFPContractable((bool)Record.readInt());
+  E->setFPFeatures(FPOptions(Record.readInt()));
 }
 
 void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -1220,7 +1220,7 @@
   VisitCallExpr(E);
   E->Operator = (OverloadedOperatorKind)Record.readInt();
   E->Range = Record.readSourceRange();
-  E->setFPContractable((bool)Record.readInt());
+  E->setFPFeatures(FPOptions(Record.readInt()));
 }
 
 void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index df4e58f..c16be87 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -3970,7 +3970,7 @@
 
 /// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions.
 void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) {
-  RecordData::value_type Record[] = {Opts.fp_contract};
+  RecordData::value_type Record[] = {Opts.getInt()};
   Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record);
 }
 
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 01fd98c..e55da00 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -645,7 +645,7 @@
   Record.AddStmt(E->getRHS());
   Record.push_back(E->getOpcode()); // FIXME: stable encoding
   Record.AddSourceLocation(E->getOperatorLoc());
-  Record.push_back(E->isFPContractable());
+  Record.push_back(E->getFPFeatures().getInt());
   Code = serialization::EXPR_BINARY_OPERATOR;
 }
 
@@ -1213,7 +1213,7 @@
   VisitCallExpr(E);
   Record.push_back(E->getOperator());
   Record.AddSourceRange(E->Range);
-  Record.push_back(E->isFPContractable());
+  Record.push_back(E->getFPFeatures().getInt());
   Code = serialization::EXPR_CXX_OPERATOR_CALL;
 }
 
diff --git a/test/CodeGen/aarch64-neon-intrinsics.c b/test/CodeGen/aarch64-neon-intrinsics.c
index 2ffbcdc..54877e9 100644
--- a/test/CodeGen/aarch64-neon-intrinsics.c
+++ b/test/CodeGen/aarch64-neon-intrinsics.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN:     -fallow-half-arguments-and-returns -ffp-contract=fast -S -emit-llvm -o - %s \
+// RUN:     -fallow-half-arguments-and-returns -S -emit-llvm -o - %s \
 // RUN: | opt -S -mem2reg \
 // RUN: | FileCheck %s
 
diff --git a/test/CodeGen/ffp-contract-fast-option.cpp b/test/CodeGen/ffp-contract-fast-option.cpp
new file mode 100644
index 0000000..3db93de
--- /dev/null
+++ b/test/CodeGen/ffp-contract-fast-option.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+float fp_contract_1(float a, float b, float c) {
+  // CHECK-LABEL: fp_contract_1fff(
+  // CHECK: fmul contract float
+  // CHECK: fadd contract float
+  return a * b + c;
+}
+
+float fp_contract_2(float a, float b, float c) {
+  // CHECK-LABEL: fp_contract_2fff(
+  // CHECK: fmul contract float
+  // CHECK: fsub contract float
+  return a * b - c;
+}
+
+void fp_contract_3(float *a, float b, float c) {
+  // CHECK-LABEL: fp_contract_3Pfff(
+  // CHECK: fmul contract float
+  // CHECK: fadd contract float
+  a[0] += b * c;
+}
+
+void fp_contract_4(float *a, float b, float c) {
+  // CHECK-LABEL: fp_contract_4Pfff(
+  // CHECK: fmul contract float
+  // CHECK: fsub contract float
+  a[0] -= b * c;
+}
diff --git a/test/CodeGen/ffp-contract-option.c b/test/CodeGen/ffp-contract-option.c
index 61913b0..52b7507 100644
--- a/test/CodeGen/ffp-contract-option.c
+++ b/test/CodeGen/ffp-contract-option.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=powerpc-apple-darwin10 -S -o - %s | FileCheck %s
-// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=aarch64-apple-darwin -S -o - %s | FileCheck %s
+// REQUIRES: aarch64-registered-target
 
 float fma_test1(float a, float b, float c) {
-// CHECK: fmadds
+// CHECK: fmadd
   float x = a * b;
   float y = x + c;
   return y;
diff --git a/test/CodeGen/fp-contract-fast-pragma.cpp b/test/CodeGen/fp-contract-fast-pragma.cpp
new file mode 100644
index 0000000..c2e52f0
--- /dev/null
+++ b/test/CodeGen/fp-contract-fast-pragma.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+// Is FP_CONTRACT honored in a simple case?
+float fp_contract_1(float a, float b, float c) {
+// CHECK: _Z13fp_contract_1fff
+// CHECK: %[[M:.+]] = fmul contract float %a, %b
+// CHECK-NEXT: fadd contract float %[[M]], %c
+#pragma clang fp contract(fast)
+  return a * b + c;
+}
+
+// Is FP_CONTRACT state cleared on exiting compound statements?
+float fp_contract_2(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_2fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  {
+#pragma clang fp contract(fast)
+  }
+  return a * b + c;
+}
+
+// Does FP_CONTRACT survive template instantiation?
+class Foo {};
+Foo operator+(Foo, Foo);
+
+template <typename T>
+T template_muladd(T a, T b, T c) {
+#pragma clang fp contract(fast)
+  return a * b + c;
+}
+
+float fp_contract_3(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_3fff
+  // CHECK: %[[M:.+]] = fmul contract float %a, %b
+  // CHECK-NEXT: fadd contract float %[[M]], %c
+  return template_muladd<float>(a, b, c);
+}
+
+template <typename T>
+class fp_contract_4 {
+  float method(float a, float b, float c) {
+#pragma clang fp contract(fast)
+    return a * b + c;
+  }
+};
+
+template class fp_contract_4<int>;
+// CHECK: _ZN13fp_contract_4IiE6methodEfff
+// CHECK: %[[M:.+]] = fmul contract float %a, %b
+// CHECK-NEXT: fadd contract float %[[M]], %c
+
+// Check file-scoped FP_CONTRACT
+#pragma clang fp contract(fast)
+float fp_contract_5(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_5fff
+  // CHECK: %[[M:.+]] = fmul contract float %a, %b
+  // CHECK-NEXT: fadd contract float %[[M]], %c
+  return a * b + c;
+}
+
+// Verify that we can handle multiple flags on the same pragma
+#pragma clang fp contract(fast) contract(off)
+float fp_contract_6(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_6fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  return a * b + c;
+}
diff --git a/test/CodeGen/fp-contract-on-pragma.cpp b/test/CodeGen/fp-contract-on-pragma.cpp
new file mode 100644
index 0000000..812a717
--- /dev/null
+++ b/test/CodeGen/fp-contract-on-pragma.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+// 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 clang fp contract(on)
+  return a * b + c;
+}
+
+// Is FP_CONTRACT state cleared on exiting compound statements?
+float fp_contract_2(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_2fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  {
+#pragma clang fp contract(on)
+  }
+  return a * b + c;
+}
+
+// Does FP_CONTRACT survive template instantiation?
+class Foo {};
+Foo operator+(Foo, Foo);
+
+template <typename T>
+T template_muladd(T a, T b, T c) {
+#pragma clang fp contract(on)
+  return a * b + c;
+}
+
+float fp_contract_3(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_3fff
+  // CHECK: tail call float @llvm.fmuladd
+  return template_muladd<float>(a, b, c);
+}
+
+template <typename T>
+class fp_contract_4 {
+  float method(float a, float b, float c) {
+#pragma clang fp contract(on)
+    return a * b + c;
+  }
+};
+
+template class fp_contract_4<int>;
+// CHECK: _ZN13fp_contract_4IiE6methodEfff
+// CHECK: tail call 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
+  return a * b + c;
+}
+
+#pragma clang fp contract(off)
+float fp_contract_6(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_6fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  return a * b + c;
+}
+
+// If the multiply has multiple uses, don't produce fmuladd.
+// This used to assert (PR25719):
+// 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 clang fp contract(on)
+  return (a = 2 * b) - c;
+}
diff --git a/test/CodeGenCUDA/fp-contract.cu b/test/CodeGenCUDA/fp-contract.cu
index 070ebae..96de5c4 100644
--- a/test/CodeGenCUDA/fp-contract.cu
+++ b/test/CodeGenCUDA/fp-contract.cu
@@ -10,10 +10,10 @@
 // RUN:   -ffp-contract=fast -disable-llvm-passes -o - %s \
 // RUN:   | FileCheck -check-prefix ENABLED %s
 
-// Explicit -ffp-contract=on -- fusing by front-end (disabled).
+// Explicit -ffp-contract=on -- fusing by front-end.
 // RUN: %clang_cc1 -fcuda-is-device -triple nvptx-nvidia-cuda -S \
 // RUN:   -ffp-contract=on -disable-llvm-passes -o - %s \
-// RUN:   | FileCheck -check-prefix DISABLED %s
+// RUN:   | FileCheck -check-prefix ENABLED %s
 
 // Explicit -ffp-contract=off should disable instruction fusing.
 // RUN: %clang_cc1 -fcuda-is-device -triple nvptx-nvidia-cuda -S \
diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp
index 9374b58..75fb37e 100644
--- a/test/Parser/cxx11-stmt-attributes.cpp
+++ b/test/Parser/cxx11-stmt-attributes.cpp
@@ -80,5 +80,6 @@
   {
     [[ ]] // expected-error {{an attribute list cannot appear here}}
 #pragma STDC FP_CONTRACT ON // expected-error {{can only appear at file scope or at the start of a compound statement}}
+#pragma clang fp contract(fast) // expected-error {{can only appear at file scope or at the start of a compound statement}}
   }
 }
diff --git a/test/Parser/pragma-fp.cpp b/test/Parser/pragma-fp.cpp
new file mode 100644
index 0000000..00547bf
--- /dev/null
+++ b/test/Parser/pragma-fp.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+void test_0(int *List, int Length) {
+/* expected-error@+1 {{missing option; expected contract}} */
+#pragma clang fp
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+void test_1(int *List, int Length) {
+/* expected-error@+1 {{invalid option 'blah'; expected contract}} */
+#pragma clang fp blah
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_3(int *List, int Length) {
+/* expected-error@+1 {{expected '('}} */
+#pragma clang fp contract on
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_4(int *List, int Length) {
+/* expected-error@+1 {{unexpected argument 'while' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+#pragma clang fp contract(while)
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_5(int *List, int Length) {
+/* expected-error@+1 {{unexpected argument 'maybe' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+#pragma clang fp contract(maybe)
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_6(int *List, int Length) {
+/* expected-error@+1 {{expected ')'}} */
+#pragma clang fp contract(fast
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_7(int *List, int Length) {
+/* expected-warning@+1 {{extra tokens at end of '#pragma clang fp' - ignored}} */
+#pragma clang fp contract(fast) *
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_8(int *List, int Length) {
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+/* expected-error@+1 {{'#pragma clang fp' can only appear at file scope or at the start of a compound statement}} */
+#pragma clang fp contract(fast)
+  }
+}