Index: include/clang/Basic/LangOptions.h
===================================================================
--- include/clang/Basic/LangOptions.h
+++ include/clang/Basic/LangOptions.h
@@ -21,6 +21,7 @@
 #include "clang/Basic/Visibility.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/IR/FPState.h"
 #include <string>
 #include <vector>
 
@@ -178,6 +179,29 @@
     FEA_On
   };
 
+  llvm::FPState::FPModelKind DefaultFPModel = llvm::FPState::FPM_Off;
+  llvm::FPState::FPModelKind getDefaultFPModel() const {
+    return DefaultFPModel;
+  }
+  void setDefaultFPModel(llvm::FPState::FPModelKind Value) {
+     DefaultFPModel = Value;
+  }
+  llvm::FPState::FPModelExceptKind DefaultFPModelExcept =
+                                     llvm::FPState::FPME_Off;
+  llvm::FPState::FPModelExceptKind getDefaultFPModelExcept() const {
+    return DefaultFPModelExcept;
+  }
+  void setDefaultFPModelExcept(llvm::FPState::FPModelExceptKind Value) {
+     DefaultFPModelExcept = Value;
+  }
+  llvm::FPState::FPSpeculationKind DefaultFPSpeculation =
+                                     llvm::FPState::FPS_Off;
+  llvm::FPState::FPSpeculationKind getDefaultFPSpeculation() const {
+    return DefaultFPSpeculation;
+  }
+  void setDefaultFPSpeculation(llvm::FPState::FPSpeculationKind Value) {
+     DefaultFPSpeculation = Value;
+  }
 
 public:
   /// Set of enabled sanitizers.
Index: include/clang/Driver/CC1Options.td
===================================================================
--- include/clang/Driver/CC1Options.td
+++ include/clang/Driver/CC1Options.td
@@ -775,6 +775,10 @@
   HelpText<"Use the native __fp16 type for arguments and returns (and skip ABI-specific lowering)">;
 def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">,
   HelpText<"Allow function arguments and returns of type half">;
+def fp_model_except : Flag<["-"], "fp-model-except">,
+  HelpText<"Controls the constrained exception setting of floating-point calculations.">;
+def no_fp_model_except : Flag<["-"], "no-fp-model-except">,
+  HelpText<"Exceptions in floating-point calculations are ignored.">;
 def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">,
   HelpText<"Set default calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall,regcall">;
 def finclude_default_header : Flag<["-"], "finclude-default-header">,
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -904,6 +904,10 @@
 def : Flag<["-"], "fno-extended-identifiers">, Group<f_Group>, Flags<[Unsupported]>;
 def fhosted : Flag<["-"], "fhosted">, Group<f_Group>;
 def fdenormal_fp_math_EQ : Joined<["-"], "fdenormal-fp-math=">, Group<f_Group>, Flags<[CC1Option]>;
+def fp_model_EQ : Joined<["-"], "fp-model=">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Controls the semantics of floating-point calculations.">;
+def fp_speculation_EQ : Joined<["-"], "fp-speculation=">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Specifies the mode in which to speculate on floating-point operations.">;
 def ffast_math : Flag<["-"], "ffast-math">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Allow aggressive, lossy floating-point optimizations">;
 def fno_fast_math : Flag<["-"], "fno-fast-math">, Group<f_Group>;
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -90,6 +90,11 @@
     FMF.setAllowReassoc();
   }
   Builder.setFastMathFlags(FMF);
+  llvm::FPState fpState(Builder);
+  auto fpModel = getLangOpts().getDefaultFPModel();
+  auto fpModelExcept = getLangOpts().getDefaultFPModelExcept();
+  auto fpSpeculation = getLangOpts().getDefaultFPSpeculation();
+  fpState.updateBuilder(fpModel, fpModelExcept, fpSpeculation);
 }
 
 CodeGenFunction::~CodeGenFunction() {
Index: lib/Driver/ToolChains/Clang.cpp
===================================================================
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -32,6 +32,7 @@
 #include "clang/Driver/XRayArgs.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/llvm-config.h"
+#include "llvm/IR/FPState.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/Compression.h"
@@ -2268,6 +2269,9 @@
   bool TrappingMath = true;
   StringRef DenormalFPMath = "";
   StringRef FPContract = "";
+  llvm::FPState::FPModelKind FPModel = llvm::FPState::FPM_Off;
+  llvm::FPState::FPModelExceptKind FPModelExcept = llvm::FPState::FPME_Off;
+  llvm::FPState::FPSpeculationKind FPSpeculation = llvm::FPState::FPS_Off;
 
   if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
     CmdArgs.push_back("-mlimit-float-precision");
@@ -2278,6 +2282,39 @@
     switch (A->getOption().getID()) {
     // If this isn't an FP option skip the claim below
     default: continue;
+    // Options controlling floating point model and speculation
+    case options::OPT_fp_model_EQ: {
+      StringRef Val = A->getValue();
+      if (Val == "precise")
+        FPModel = llvm::FPState::FPM_Precise;
+      else if (Val == "strict")
+        FPModel = llvm::FPState::FPM_Strict;
+      else if (Val == "except")
+        FPModelExcept = llvm::FPState::FPME_Except;
+      else if (Val == "except-")
+        FPModelExcept= llvm::FPState::FPME_NoExcept;
+      else if (Val == "fast")
+        FPModel = llvm::FPState::FPM_Fast;
+      else {
+        D.Diag(diag::err_drv_invalid_value) << "-fp-model" << Val;
+        continue;
+      }
+      break;
+    }
+    case options::OPT_fp_speculation_EQ: {
+      StringRef Val = A->getValue();
+      if (Val == "fast")
+        FPSpeculation = llvm::FPState::FPS_Fast;
+      else if (Val == "strict")
+        FPSpeculation = llvm::FPState::FPS_Strict;
+      else if (Val == "safe")
+        FPSpeculation = llvm::FPState::FPS_Safe;
+      else {
+        D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+        continue;
+      }
+      break;
+    }
 
     // Options controlling individual features
     case options::OPT_fhonor_infinities:    HonorINFs = true;         break;
@@ -2371,6 +2408,42 @@
     A->claim();
   }
 
+  if ((FPModelExcept == llvm::FPState::FPME_Except) &&
+      (FPModel == llvm::FPState::FPM_Fast))
+    D.Diag(diag::err_drv_argument_not_allowed_with)
+        << "fp-model=fast" << "fp-model=except";
+
+  switch (FPModel) {
+  case llvm::FPState::FPM_Precise:
+    CmdArgs.push_back("-fp-model=precise"); break;
+  case llvm::FPState::FPM_Strict:
+    CmdArgs.push_back("-fp-model=strict"); break;
+  case llvm::FPState::FPM_Fast:
+    CmdArgs.push_back("-fp-model=fast"); break;
+  case llvm::FPState::FPM_Off: break;
+  default: llvm_unreachable("Unrecognized FPModel");
+  }
+
+  switch (FPModelExcept) {
+  case llvm::FPState::FPME_Except:
+    CmdArgs.push_back("-fp-model-except"); break;
+  case llvm::FPState::FPME_NoExcept:
+    CmdArgs.push_back("-no-fpmodel-except-"); break;
+  case llvm::FPState::FPME_Off: break;
+  default: llvm_unreachable("Unrecognized FPModel");
+  }
+
+  switch (FPSpeculation) {
+  case llvm::FPState::FPS_Fast:
+    CmdArgs.push_back("-fp-speculation=fast"); break;
+  case llvm::FPState::FPS_Strict:
+    CmdArgs.push_back("-fp-speculation=strict"); break;
+  case llvm::FPState::FPS_Safe:
+    CmdArgs.push_back("-fp-speculation=safe"); break;
+  case llvm::FPState::FPS_Off: break;
+  default: llvm_unreachable("Unrecognized FPSpeculation");
+  }
+
   if (!HonorINFs)
     CmdArgs.push_back("-menable-no-infs");
 
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -2978,6 +2978,58 @@
       Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
   }
 
+  llvm::FPState::FPModelKind FPM = llvm::FPState::FPM_Off;
+  if (Arg *A = Args.getLastArg(OPT_fp_model_EQ)) {
+    StringRef Val = A->getValue();
+    if (Val == "precise")
+      FPM = llvm::FPState::FPM_Precise;
+    else if (Val == "strict")
+      FPM = llvm::FPState::FPM_Strict;
+    else if (Val == "fast")
+      FPM = llvm::FPState::FPM_Fast;
+    else
+      llvm_unreachable("invalid -fp-model setting");
+  }
+  Opts.setDefaultFPModel(FPM);
+
+  llvm::FPState::FPModelExceptKind FPME = llvm::FPState::FPME_Off;
+  if (const Arg *A =
+          Args.getLastArg(OPT_fp_model_except, OPT_no_fp_model_except))
+    switch (A->getOption().getID()) {
+    case OPT_fp_model_except:
+      FPME = llvm::FPState::FPME_Except;
+      break;
+    case OPT_no_fp_model_except:
+      FPME = llvm::FPState::FPME_NoExcept;
+      break;
+    default : llvm_unreachable("invalid -fp-model-except setting");
+    }
+  Opts.setDefaultFPModelExcept(FPME);
+
+  llvm::FPState::FPSpeculationKind FPS = llvm::FPState::FPS_Off;
+  if (Arg *A = Args.getLastArg(OPT_fp_speculation_EQ)) {
+    StringRef Val = A->getValue();
+    if (Val == "fast")
+      FPS = llvm::FPState::FPS_Fast;
+    else if (Val == "strict")
+      FPS = llvm::FPState::FPS_Strict;
+    else if (Val == "safe")
+      FPS = llvm::FPState::FPS_Safe;
+    else
+      llvm_unreachable("invalid -fp-speculation setting");
+    Opts.setDefaultFPSpeculation(FPS);
+  }
+
+  if (FPM == llvm::FPState::FPM_Precise)
+    // This doesn't correspond to constrained fp, equivalent to -fp-contract=on
+    Opts.setDefaultFPContractMode(LangOptions::FPC_On);
+  else if (FPM == llvm::FPState::FPM_Fast) {
+    // This doesn't correspond to constrained fp, equivalent to -ffast-math
+    Opts.FastMath = true;
+    Opts.FiniteMathOnly = true;
+    Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
+  }
+
   Opts.RetainCommentsFromSystemHeaders =
       Args.hasArg(OPT_fretain_comments_from_system_headers);
 
@@ -3340,6 +3392,15 @@
     // FIXME: Should we really be calling this for an InputKind::Asm input?
     ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
                   Res.getPreprocessorOpts(), Diags);
+    auto fpm = LangOpts.getDefaultFPModel();
+    if (fpm == llvm::FPState::FPM_Fast) {
+      auto CGOpts = Res.getCodeGenOpts();
+      CGOpts.NoInfsFPMath = true;
+      CGOpts.UnsafeFPMath = true;
+      CGOpts.ReciprocalMath = true;
+      CGOpts.NoTrappingMath = true;
+      CGOpts.NoSignedZeros = true;
+    }
     if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
       LangOpts.ObjCExceptions = 1;
     if (T.isOSDarwin() && DashX.isPreprocessed()) {
Index: test/CodeGen/fpconstrained.c
===================================================================
--- /dev/null
+++ test/CodeGen/fpconstrained.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fp-model=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=STRICT
+// RUN: %clang_cc1 -fp-model=strict -fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=STRICTEXCEPT
+// RUN: %clang_cc1 -fp-model=strict -no-fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=STRICTNOEXCEPT
+// RUN: %clang_cc1 -fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
+// RUN: %clang_cc1 -no-fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=NOEXCEPT
+// RUN: %clang_cc1 -fp-model=precise -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
+// RUN: %clang_cc1 -fp-model=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
+// RUN: %clang_cc1 -fp-model=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
+// RUN: %clang_cc1 -fp-model=fast -fp-speculation=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=NOEXCEPT
+// RUN: %clang_cc1 -fp-model=fast -fp-speculation=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
+// RUN: %clang_cc1 -fp-model=fast -fp-speculation=safe -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
+float f0, f1, f2;
+
+void foo(void) {
+  // CHECK-LABEL: define {{.*}}void @foo()
+
+  // MAYTRAP: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
+  // EXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  // NOEXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  // STRICT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  // STRICTEXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  // STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  // PRECISE: fadd float
+  // FAST: fadd fast
+  f0 = f1 + f2;
+
+  // CHECK: ret
+}
Index: test/Driver/clang_f_opts.c
===================================================================
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -217,6 +217,11 @@
 // RUN: %clang -### -S -fexec-charset=iso-8859-1 -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-INPUT-CHARSET %s
 // CHECK-INVALID-INPUT-CHARSET: error: invalid value 'iso-8859-1' in '-fexec-charset=iso-8859-1'
 
+// RUN: %clang -### -S -fp-model=fast -fp-model=except -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-FAST-EXCEPT %s
+// RUN: %clang -### -S -fp-model=fast -fp-model=except -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-FAST-EXCEPT %s
+// CHECK-INVALID-FAST-EXCEPT: error: invalid argument 'fp-model=fast' not allowed with 'fp-model=except'
+//
+
 // Test that we don't error on these.
 // RUN: %clang -### -S -Werror                                                \
 // RUN:     -falign-functions -falign-functions=2 -fno-align-functions        \