diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -9,6 +9,8 @@
 #ifndef LLVM_DEMANGLE_DEMANGLE_H
 #define LLVM_DEMANGLE_DEMANGLE_H
 
+#include "llvm/ADT/Optional.h"
+
 #include <cstddef>
 #include <string>
 
@@ -28,6 +30,16 @@
   demangle_success = 0,
 };
 
+/// The different Demangle formats
+enum DemangleFormatTy {
+  demangle_format_itanium = 0,
+  demangle_format_dlang,
+  demangle_format_rust,
+  demangle_format_non_microsoft, // this is all of the above formats
+  demangle_format_microsoft,
+  demangle_format_autodetect,
+};
+
 char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
                       int *status);
 
@@ -70,6 +82,15 @@
 /// demangling occurred.
 std::string demangle(const std::string &MangledName);
 
+/// Demangle with specified DemangleFormat. This replaces the demangle()
+/// function. \param MangledName - reference to string to demangle. \param
+/// Format - Specifier for what formats to try to demangle. Pass
+/// demangle_format_autodetect to try all the demangler \return - a
+/// llvm::Optional that is populated if the demangling succeeded.
+llvm::Optional<std::string> demangle(const std::string &MangledName,
+                                     DemangleFormatTy Format);
+
+/// Alias for demangle(name, demangle_format_non_microsoft)
 bool nonMicrosoftDemangle(const char *MangledName, std::string &Result);
 
 /// "Partial" demangler. This supports demangling a string into an AST
diff --git a/llvm/lib/Demangle/Demangle.cpp b/llvm/lib/Demangle/Demangle.cpp
--- a/llvm/lib/Demangle/Demangle.cpp
+++ b/llvm/lib/Demangle/Demangle.cpp
@@ -26,39 +26,71 @@
          MangledName[1] == 'D';
 }
 
-std::string llvm::demangle(const std::string &MangledName) {
-  std::string Result;
+llvm::Optional<std::string> llvm::demangle(const std::string &MangledName,
+                                           DemangleFormatTy Format) {
   const char *S = MangledName.c_str();
+  llvm::Optional<std::string> Result;
+  char *Demangled = nullptr;
+  int Status = demangle_unknown_error;
 
-  if (nonMicrosoftDemangle(S, Result))
-    return Result;
-
-  if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result))
+  switch (Format) {
+  case demangle_format_itanium:
+    if (isItaniumEncoding(S)) {
+      Demangled = itaniumDemangle(S, nullptr, nullptr, nullptr);
+      Status = demangle_success;
+    }
+    break;
+  case demangle_format_dlang:
+    if (isDLangEncoding(S)) {
+      Demangled = dlangDemangle(S);
+      Status = demangle_success;
+    }
+    break;
+  case demangle_format_rust:
+    if (isRustEncoding(S)) {
+      Demangled = rustDemangle(S);
+      Status = demangle_success;
+    }
+    break;
+  case demangle_format_microsoft:
+    Demangled = microsoftDemangle(S, nullptr, nullptr, nullptr, &Status);
+    break;
+  case demangle_format_autodetect:
+  case demangle_format_non_microsoft:
+    if (auto D = demangle(MangledName, demangle_format_itanium))
+      return D;
+    if (auto D = demangle(MangledName, demangle_format_rust))
+      return D;
+    if (auto D = demangle(MangledName, demangle_format_dlang))
+      return D;
+    // If the flag is non_microsoft we don't want to run the code below
+    if (Format == demangle_format_autodetect)
+      if (auto D = demangle(MangledName, demangle_format_microsoft))
+        return D;
     return Result;
+  }
 
-  if (char *Demangled =
-          microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) {
+  if (Status == demangle_success && Demangled) {
     Result = Demangled;
     std::free(Demangled);
-    return Result;
   }
 
+  return Result;
+}
+
+std::string llvm::demangle(const std::string &MangledName) {
+  auto D = demangle(MangledName, demangle_format_autodetect);
+  if (D)
+    return D.value();
   return MangledName;
 }
 
 bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) {
-  char *Demangled = nullptr;
-  if (isItaniumEncoding(MangledName))
-    Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr);
-  else if (isRustEncoding(MangledName))
-    Demangled = rustDemangle(MangledName);
-  else if (isDLangEncoding(MangledName))
-    Demangled = dlangDemangle(MangledName);
-
-  if (!Demangled)
-    return false;
-
-  Result = Demangled;
-  std::free(Demangled);
-  return true;
+  auto D = demangle(MangledName, demangle_format_non_microsoft);
+  if (D) {
+    Result = D.value();
+    return true;
+  }
+  Result = MangledName;
+  return false;
 }
diff --git a/llvm/test/tools/llvm-cxxfilt/microsoft-format.test b/llvm/test/tools/llvm-cxxfilt/microsoft-format.test
new file mode 100644
--- /dev/null
+++ b/llvm/test/tools/llvm-cxxfilt/microsoft-format.test
@@ -0,0 +1,13 @@
+## Test microsoft demangle format
+## This should only demangle microsofts format if format=microsoft or format=auto
+## And fail if we set format=gnu
+
+RUN: llvm-cxxfilt --format=microsoft ?a@@YAHD@Z ?c@b@@AAGXM@Z | FileCheck %s
+RUN: llvm-cxxfilt --format=auto ?a@@YAHD@Z ?c@b@@AAGXM@Z | FileCheck %s
+RUN: llvm-cxxfilt --format=gnu ?a@@YAHD@Z ?c@b@@AAGXM@Z | FileCheck %s --check-prefix=GNU
+
+CHECK: int __cdecl a(char)
+CHECK-NEXT: private: void __stdcall b::c(float)
+
+GNU: ?a@@YAHD@Z
+GNU-NEXT: ?c@b@@AAGXM@Z
diff --git a/llvm/tools/llvm-cxxfilt/Opts.td b/llvm/tools/llvm-cxxfilt/Opts.td
--- a/llvm/tools/llvm-cxxfilt/Opts.td
+++ b/llvm/tools/llvm-cxxfilt/Opts.td
@@ -19,7 +19,7 @@
 def types : FF<"types", "Attempt to demangle types as well as function names">;
 def version : FF<"version", "Display the version">;
 
-defm : Eq<"format", "Specify mangling format. Currently ignored because only 'gnu' is supported">;
+defm format : Eq<"format", "Specify mangling format: gnu (default), itanium, dlang, rust, microsoft or auto">, MetaVarName<"<format>">;
 def : F<"s", "Alias for --format">;
 
 def : F<"_", "Alias for --strip-underscore">, Alias<strip_underscore>;
diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
--- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -48,6 +48,8 @@
 #undef OPTION
 };
 
+static DemangleFormatTy DemangleFormat;
+
 class CxxfiltOptTable : public opt::OptTable {
 public:
   CxxfiltOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
@@ -70,11 +72,12 @@
     if (DecoratedStr[0] == '_')
       ++DecoratedStr;
 
-  std::string Result;
-  if (nonMicrosoftDemangle(DecoratedStr, Result))
-    return Result;
+  if (auto Result = demangle(DecoratedStr, DemangleFormat)) {
+    return Result.value();
+  }
 
   std::string Prefix;
+  std::string Result = DecoratedStr;
   char *Undecorated = nullptr;
 
   if (Types)
@@ -162,6 +165,23 @@
     return 0;
   }
 
+  StringRef V = Args.getLastArgValue(OPT_format_EQ, "gnu");
+  if (V == "gnu")
+    DemangleFormat = llvm::demangle_format_non_microsoft;
+  else if (V == "microsoft")
+    DemangleFormat = llvm::demangle_format_microsoft;
+  else if (V == "auto")
+    DemangleFormat = llvm::demangle_format_autodetect;
+  else if (V == "dlang")
+    DemangleFormat = llvm::demangle_format_dlang;
+  else if (V == "rust")
+    DemangleFormat = llvm::demangle_format_rust;
+  else if (V == "itanium")
+    DemangleFormat = llvm::demangle_format_itanium;
+  else
+    error("--format value should be one of: gnu (default), itanium, dlang, "
+          "rust, microsoft or auto");
+
   // The default value depends on the default triple. Mach-O has symbols
   // prefixed with "_", so strip by default.
   if (opt::Arg *A =