Index: test/Driver/mips-float.c
===================================================================
--- test/Driver/mips-float.c	(revision 0)
+++ test/Driver/mips-float.c	(revision 0)
@@ -0,0 +1,59 @@
+// Check handling -mhard-float / -msoft-float / -mfloat-abi options
+// when build for MIPS platforms.
+//
+// Default
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN:     -target mips-linux-gnu \
+// RUN:   | FileCheck --check-prefix=CHECK-DEF %s
+// CHECK-DEF: "-mfloat-abi" "hard"
+//
+// -mhard-float
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN:     -target mips-linux-gnu -mhard-float \
+// RUN:   | FileCheck --check-prefix=CHECK-HARD %s
+// CHECK-HARD: "-mfloat-abi" "hard"
+//
+// -msoft-float
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN:     -target mips-linux-gnu -msoft-float \
+// RUN:   | FileCheck --check-prefix=CHECK-SOFT %s
+// CHECK-SOFT: "-msoft-float"
+// CHECK-SOFT: "-mfloat-abi" "soft"
+// CHECK-SOFT: "-target-feature" "+soft-float"
+//
+// -mfloat-abi=hard
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN:     -target mips-linux-gnu -mfloat-abi=hard \
+// RUN:   | FileCheck --check-prefix=CHECK-ABI-HARD %s
+// CHECK-ABI-HARD: "-mfloat-abi" "hard"
+//
+// -mfloat-abi=soft
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN:     -target mips-linux-gnu -mfloat-abi=soft \
+// RUN:   | FileCheck --check-prefix=CHECK-ABI-SOFT %s
+// CHECK-ABI-SOFT: "-msoft-float"
+// CHECK-ABI-SOFT: "-mfloat-abi" "soft"
+// CHECK-ABI-SOFT: "-target-feature" "+soft-float"
+//
+// -mfloat-abi=single
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN:     -target mips-linux-gnu -mfloat-abi=single \
+// RUN:   | FileCheck --check-prefix=CHECK-ABI-SINGLE %s
+// CHECK-ABI-SINGLE: "-target-feature" "+single-float"
+//
+// Let's check float ABI related macros.
+//
+// -mfloat-abi=hard
+// RUN: %clang -c %s -dM -E 2>&1 \
+// RUN:     -target mips-linux-gnu -mfloat-abi=hard \
+// RUN:   | grep "#define __mips_hard_float 1"
+//
+// -mfloat-abi=soft
+// RUN: %clang -c %s -dM -E 2>&1 \
+// RUN:     -target mips-linux-gnu -mfloat-abi=soft \
+// RUN:   | grep "#define __mips_soft_float 1"
+//
+// -mfloat-abi=single
+// RUN: %clang -c %s -dM -E 2>&1 \
+// RUN:     -target mips-linux-gnu -mfloat-abi=single \
+// RUN:   | grep "#define __mips_single_float 1"
Index: lib/Basic/Targets.cpp
===================================================================
--- lib/Basic/Targets.cpp	(revision 152780)
+++ lib/Basic/Targets.cpp	(working copy)
@@ -3440,11 +3440,19 @@
 namespace {
 class MipsTargetInfoBase : public TargetInfo {
   std::string CPU;
+  bool SoftFloat;
+  bool SingleFloat;
+
 protected:
   std::string ABI;
+
 public:
   MipsTargetInfoBase(const std::string& triple, const std::string& ABIStr)
-    : TargetInfo(triple), ABI(ABIStr) {}
+    : TargetInfo(triple),
+      SoftFloat(false), SingleFloat(false),
+      ABI(ABIStr)
+  {}
+
   virtual const char *getABI() const { return ABI.c_str(); }
   virtual bool setABI(const std::string &Name) = 0;
   virtual bool setCPU(const std::string &Name) {
@@ -3455,8 +3463,23 @@
     Features[ABI] = true;
     Features[CPU] = true;
   }
+
   virtual void getArchDefines(const LangOptions &Opts,
-                              MacroBuilder &Builder) const = 0;
+                              MacroBuilder &Builder) const {
+    if (SoftFloat) {
+      Builder.defineMacro("__mips_soft_float", Twine(1));
+    }
+    else if (SingleFloat) {
+      Builder.defineMacro("__mips_single_float", Twine(1));
+    }
+    else if (!SoftFloat && !SingleFloat) {
+      Builder.defineMacro("__mips_hard_float", Twine(1));
+    }
+    else {
+      llvm_unreachable("Invalid float ABI for Mips.");
+    }
+  }
+
   virtual void getTargetDefines(const LangOptions &Opts,
                                 MacroBuilder &Builder) const = 0;
   virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -3507,6 +3530,35 @@
     // FIXME: Implement!
     return "";
   }
+
+  virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+                                 StringRef Name,
+                                 bool Enabled) const {
+    if (Name == "soft-float" || Name == "single-float") {
+      Features[Name] = Enabled;
+      return true;
+    }
+    return false;
+  }
+
+  virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+    SoftFloat = false;
+    SingleFloat = false;
+
+    for (unsigned i = 0, e = Features.size(); i != e; ++i) {
+      if (Features[i] == "+soft-float")
+        SoftFloat = true;
+      else if (Features[i] == "+single-float")
+        SingleFloat = true;
+    }
+
+    // This option is front-end specific.
+    // Do not need to pass it to the backend.
+    std::vector<std::string>::iterator it;
+    it = std::find(Features.begin(), Features.end(), "+soft-float");
+    if (it != Features.end())
+      Features.erase(it);
+  }
 };
 
 class Mips32TargetInfoBase : public MipsTargetInfoBase {
@@ -3525,6 +3577,8 @@
   }
   virtual void getArchDefines(const LangOptions &Opts,
                               MacroBuilder &Builder) const {
+    MipsTargetInfoBase::getArchDefines(Opts, Builder);
+
     Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
     Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
     Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
@@ -3642,6 +3696,8 @@
   }
   virtual void getArchDefines(const LangOptions &Opts,
                               MacroBuilder &Builder) const {
+    MipsTargetInfoBase::getArchDefines(Opts, Builder);
+
     if (ABI == "n32") {
       Builder.defineMacro("__mips_n32");
       Builder.defineMacro("_ABIN32", "2");
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp	(revision 152780)
+++ lib/Driver/Tools.cpp	(working copy)
@@ -785,31 +785,57 @@
   CmdArgs.push_back("-target-abi");
   CmdArgs.push_back(ABIName);
 
-  // Select the float ABI as determined by -msoft-float, -mhard-float, and
+  // Select the float ABI as determined by -msoft-float, -mhard-float,
+  // and -mfloat-abi=.
   StringRef FloatABI;
   if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
-                               options::OPT_mhard_float)) {
+                               options::OPT_mhard_float,
+                               options::OPT_mfloat_abi_EQ)) {
     if (A->getOption().matches(options::OPT_msoft_float))
       FloatABI = "soft";
     else if (A->getOption().matches(options::OPT_mhard_float))
       FloatABI = "hard";
+    else {
+      FloatABI = A->getValue(Args);
+      if (FloatABI != "soft" && FloatABI != "single" && FloatABI != "hard") {
+        D.Diag(diag::err_drv_invalid_mfloat_abi)
+          << A->getAsString(Args);
+        FloatABI = "hard";
+      }
+    }
   }
 
   // If unspecified, choose the default based on the platform.
   if (FloatABI.empty()) {
-    // Assume "soft", but warn the user we are guessing.
-    FloatABI = "soft";
-    D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+    // Assume "hard", because it's a default value used by gcc.
+    // When we start to recognize specific target MIPS processors,
+    // we will be able to select the default more correctly.
+    FloatABI = "hard";
   }
 
   if (FloatABI == "soft") {
     // Floating point operations and argument passing are soft.
-    //
-    // FIXME: This changes CPP defines, we need -target-soft-float.
     CmdArgs.push_back("-msoft-float");
-  } else {
+    CmdArgs.push_back("-mfloat-abi");
+    CmdArgs.push_back("soft");
+
+    // FIXME: Note, this is a hack. We need to pass the selected float
+    // mode to the MipsTargetInfoBase to define appropriate macros there.
+    // Now it is the only method.
+    CmdArgs.push_back("-target-feature");
+    CmdArgs.push_back("+soft-float");
+  }
+  else if (FloatABI == "single") {
+    // Restrict the use of hardware floating-point
+    // instructions to 32-bit operations.
+    CmdArgs.push_back("-target-feature");
+    CmdArgs.push_back("+single-float");
+  }
+  else {
+    // Floating point operations and argument passing are hard.
     assert(FloatABI == "hard" && "Invalid float abi!");
-    CmdArgs.push_back("-mhard-float");
+    CmdArgs.push_back("-mfloat-abi");
+    CmdArgs.push_back("hard");
   }
 }
 
