Index: test/CodeGenOpenCL/single-precision-constant.cl
===================================================================
--- test/CodeGenOpenCL/single-precision-constant.cl	(revision 164735)
+++ test/CodeGenOpenCL/single-precision-constant.cl	(working copy)
@@ -1,7 +1,6 @@
 // RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s
 
 float fn(float f) {
-  // CHECK: fmul float
-  // CHECK: fadd float
+  // CHECK: %0 = tail call float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00)
   return f*2. + 1.;
 }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h	(revision 164735)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -735,6 +735,20 @@
   /// should not be used elsewhere.
   void EmitCurrentDiagnostic(unsigned DiagID);
 
+  /// Records and restores the FP_CONTRACT state on entry/exit of compound
+  /// statements.
+  class FPContractStateRAII {
+  public:
+    FPContractStateRAII(Sema& S)
+      : S(S), OldFPContractState(S.FPFeatures.fp_contract) {}
+    ~FPContractStateRAII() {
+      S.FPFeatures.fp_contract = OldFPContractState;
+    }
+  private:
+    Sema& S;
+    bool OldFPContractState : 1;
+  };
+
 public:
   Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
        TranslationUnitKind TUKind = TU_Complete,
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h	(revision 164735)
+++ include/clang/AST/Expr.h	(working copy)
@@ -2782,6 +2782,7 @@
 
 private:
   unsigned Opc : 6;
+  bool FPContractable : 1;
   SourceLocation OpLoc;
 
   enum { LHS, RHS, END_EXPR };
@@ -2790,7 +2791,7 @@
 
   BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
                  ExprValueKind VK, ExprObjectKind OK,
-                 SourceLocation opLoc)
+                 SourceLocation opLoc, bool fpContractable = false)
     : Expr(BinaryOperatorClass, ResTy, VK, OK,
            lhs->isTypeDependent() || rhs->isTypeDependent(),
            lhs->isValueDependent() || rhs->isValueDependent(),
@@ -2798,7 +2799,7 @@
             rhs->isInstantiationDependent()),
            (lhs->containsUnexpandedParameterPack() ||
             rhs->containsUnexpandedParameterPack())),
-      Opc(opc), OpLoc(opLoc) {
+      Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
     assert(!isCompoundAssignmentOp() &&
@@ -2899,10 +2900,14 @@
     return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
   }
 
+  void setFPContractable(bool FPC) { FPContractable = FPC; }
+
+  bool isFPContractable() const { return FPContractable; }
+
 protected:
   BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
                  ExprValueKind VK, ExprObjectKind OK,
-                 SourceLocation opLoc, bool dead)
+                 SourceLocation opLoc, bool fpContractable, bool dead2)
     : Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
            lhs->isTypeDependent() || rhs->isTypeDependent(),
            lhs->isValueDependent() || rhs->isValueDependent(),
@@ -2910,7 +2915,7 @@
             rhs->isInstantiationDependent()),
            (lhs->containsUnexpandedParameterPack() ||
             rhs->containsUnexpandedParameterPack())),
-      Opc(opc), OpLoc(opLoc) {
+      Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
   }
@@ -2932,8 +2937,9 @@
   CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
                          ExprValueKind VK, ExprObjectKind OK,
                          QualType CompLHSType, QualType CompResultType,
-                         SourceLocation OpLoc)
-    : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, true),
+                         SourceLocation OpLoc, bool fpContractable = false)
+    : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
+                     true),
       ComputationLHSType(CompLHSType),
       ComputationResultType(CompResultType) {
     assert(isCompoundAssignmentOp() &&
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h	(revision 164735)
+++ include/clang/AST/ExprCXX.h	(working copy)
@@ -53,14 +53,17 @@
   OverloadedOperatorKind Operator;
   SourceRange Range;
 
+  /// \brief Record the FP_CONTRACT state that applies to this operator call.
+  bool FPContractable : 1;
+
   SourceRange getSourceRangeImpl() const LLVM_READONLY;
 public:
   CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
                       ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
-                      SourceLocation operatorloc)
+                      SourceLocation operatorloc, bool fpContractable = false)
     : CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, t, VK,
                operatorloc),
-      Operator(Op) {
+      Operator(Op), FPContractable(fpContractable) {
     Range = getSourceRangeImpl();
   }
   explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
@@ -85,6 +88,10 @@
   }
   static bool classof(const CXXOperatorCallExpr *) { return true; }
 
+  void setFPContractable(bool FPC) { FPContractable = FPC; }
+
+  bool isFPContractable() const { return FPContractable; }
+
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
 };
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h	(revision 164735)
+++ lib/Sema/TreeTransform.h	(working copy)
@@ -6852,6 +6852,9 @@
       (E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
     return SemaRef.MaybeBindToTemporary(E);
 
+  Sema::FPContractStateRAII FPContractState(getSema());
+  getSema().FPFeatures.fp_contract = E->isFPContractable();
+
   return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
                                                  E->getOperatorLoc(),
                                                  Callee.get(),
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp	(revision 164735)
+++ lib/Sema/SemaOverload.cpp	(working copy)
@@ -10179,11 +10179,9 @@
                                      NestedNameSpecifierLoc(), OpNameInfo, 
                                      /*ADL*/ true, IsOverloaded(Fns),
                                      Fns.begin(), Fns.end());
-    return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
-                                                   Args,
-                                                   Context.DependentTy,
-                                                   VK_RValue,
-                                                   OpLoc));
+    return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args,
+                                                Context.DependentTy, VK_RValue,
+                                                OpLoc, FPFeatures.fp_contract));
   }
 
   // Always do placeholder-like conversions on the RHS.
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 164735)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -8381,7 +8381,8 @@
 
   if (CompResultTy.isNull())
     return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
-                                              ResultTy, VK, OK, OpLoc));
+                                              ResultTy, VK, OK, OpLoc,
+                                              FPFeatures.fp_contract));
   if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
       OK_ObjCProperty) {
     VK = VK_LValue;
@@ -8389,7 +8390,8 @@
   }
   return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc,
                                                     ResultTy, VK, OK, CompLHSTy,
-                                                    CompResultTy, OpLoc));
+                                                    CompResultTy, OpLoc,
+                                                    FPFeatures.fp_contract));
 }
 
 /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp	(revision 164735)
+++ lib/AST/ASTImporter.cpp	(working copy)
@@ -4082,7 +4082,8 @@
   return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(),
                                                       T, E->getValueKind(),
                                                       E->getObjectKind(),
-                                          Importer.Import(E->getOperatorLoc()));
+                                           Importer.Import(E->getOperatorLoc()),
+                                                      E->isFPContractable());
 }
 
 Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -4111,7 +4112,8 @@
                                                T, E->getValueKind(),
                                                E->getObjectKind(),
                                                CompLHSType, CompResultType,
-                                          Importer.Import(E->getOperatorLoc()));
+                                           Importer.Import(E->getOperatorLoc()),
+                                               E->isFPContractable());
 }
 
 static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp	(revision 164735)
+++ lib/CodeGen/CGExprScalar.cpp	(working copy)
@@ -45,6 +45,7 @@
   Value *RHS;
   QualType Ty;  // Computation Type.
   BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
+  bool FPContractable;
   const Expr *E;      // Entire expr, for error unsupported.  May not be binop.
 };
 
@@ -1654,6 +1655,7 @@
   Result.RHS = Visit(E->getRHS());
   Result.Ty  = E->getType();
   Result.Opcode = E->getOpcode();
+  Result.FPContractable = E->isFPContractable();
   Result.E = E;
   return Result;
 }
@@ -2000,8 +2002,37 @@
     }
   }
     
-  if (op.LHS->getType()->isFPOrFPVectorTy())
-    return Builder.CreateFAdd(op.LHS, op.RHS, "add");
+ if (op.LHS->getType()->isFPOrFPVectorTy()) {
+   if (op.FPContractable &&
+         CGF.getContext().getLangOpts().getFPContractMode() ==
+         LangOptions::FPC_On) {
+     if (llvm::BinaryOperator* LHSBinOp =
+           dyn_cast<llvm::BinaryOperator>(op.LHS)) {
+       if (LHSBinOp->getOpcode() == llvm::Instruction::FMul) {
+         Value *MLA =
+           Builder.CreateCall3(
+             CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, op.RHS->getType()),
+             LHSBinOp->getOperand(0), LHSBinOp->getOperand(1),
+             op.RHS);
+         LHSBinOp->eraseFromParent();
+         return MLA;
+       }
+     }
+     if (llvm::BinaryOperator* RHSBinOp =
+           dyn_cast<llvm::BinaryOperator>(op.RHS)) {
+       if (RHSBinOp->getOpcode() == llvm::Instruction::FMul) {
+         Value *MLA =
+           Builder.CreateCall3(
+             CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, op.LHS->getType()),
+             RHSBinOp->getOperand(0), RHSBinOp->getOperand(1),
+             op.LHS);
+         RHSBinOp->eraseFromParent();
+         return MLA;
+       }
+     }
+   }
+   return Builder.CreateFAdd(op.LHS, op.RHS, "add");
+ }
 
   return Builder.CreateAdd(op.LHS, op.RHS, "add");
 }
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp	(revision 164735)
+++ lib/Parse/ParseStmt.cpp	(working copy)
@@ -679,6 +679,11 @@
   PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
                                 Tok.getLocation(),
                                 "in compound statement ('{}')");
+
+  // Record the state of the FP_CONTRACT pragma, restore on leaving the
+  // compound statement.
+  Sema::FPContractStateRAII SaveFPContractState(Actions);
+
   InMessageExpressionRAIIObject InMessage(*this, false);
   BalancedDelimiterTracker T(*this, tok::l_brace);
   if (T.consumeOpen())
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp	(revision 164735)
+++ lib/Serialization/ASTReaderStmt.cpp	(working copy)
@@ -565,6 +565,7 @@
   E->setRHS(Reader.ReadSubExpr());
   E->setOpcode((BinaryOperator::Opcode)Record[Idx++]);
   E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+  E->setFPContractable((bool)Record[Idx++]);
 }
 
 void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -1086,6 +1087,7 @@
   VisitCallExpr(E);
   E->Operator = (OverloadedOperatorKind)Record[Idx++];
   E->Range = Reader.ReadSourceRange(F, Record, Idx);
+  E->setFPContractable((bool)Record[Idx++]);
 }
 
 void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp	(revision 164735)
+++ lib/Serialization/ASTWriterStmt.cpp	(working copy)
@@ -536,6 +536,7 @@
   Writer.AddStmt(E->getRHS());
   Record.push_back(E->getOpcode()); // FIXME: stable encoding
   Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+  Record.push_back(E->isFPContractable());
   Code = serialization::EXPR_BINARY_OPERATOR;
 }
 
@@ -1055,6 +1056,7 @@
   VisitCallExpr(E);
   Record.push_back(E->getOperator());
   Writer.AddSourceRange(E->Range, Record);
+  Record.push_back(E->isFPContractable());
   Code = serialization::EXPR_CXX_OPERATOR_CALL;
 }
 
