On 32 bit windows, mangle stdcall and fastcall decls in clang.

This removes the dependency on the llvm mangler doing it for us. In isolation,
the benefit is that the testing of what mangling is applied is all in one place:
(C, C++) X (Itanium, Microsoft) are all handled by clang.

This also gives me hope that in the future the llvm mangler (and llvm-ar) will
not depend on TargetMachine.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192762 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index 76d099f..d2e5325 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -108,10 +108,12 @@
   /// @name Mangler Entry Points
   /// @{
 
-  virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
+  bool shouldMangleDeclName(const NamedDecl *D);
+  virtual bool shouldMangleCXXName(const NamedDecl *D) = 0;
 
   // FIXME: consider replacing raw_ostream & with something like SmallString &.
-  virtual void mangleName(const NamedDecl *D, raw_ostream &) = 0;
+  void mangleName(const NamedDecl *D, raw_ostream &);
+  virtual void mangleCXXName(const NamedDecl *D, raw_ostream &) = 0;
   virtual void mangleThunk(const CXXMethodDecl *MD,
                           const ThunkInfo &Thunk,
                           raw_ostream &) = 0;
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index fe8575d..0d26c9e 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -125,8 +125,8 @@
   /// @name Mangler Entry Points
   /// @{
 
-  bool shouldMangleDeclName(const NamedDecl *D);
-  void mangleName(const NamedDecl *D, raw_ostream &);
+  bool shouldMangleCXXName(const NamedDecl *D);
+  void mangleCXXName(const NamedDecl *D, raw_ostream &);
   void mangleThunk(const CXXMethodDecl *MD,
                    const ThunkInfo &Thunk,
                    raw_ostream &);
@@ -384,16 +384,7 @@
 
 }
 
-bool ItaniumMangleContextImpl::shouldMangleDeclName(const NamedDecl *D) {
-  // In C, functions with no attributes never need to be mangled. Fastpath them.
-  if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
-    return false;
-
-  // Any decl can be declared with __asm("foo") on it, and this takes precedence
-  // over all other naming in the .o file.
-  if (D->hasAttr<AsmLabelAttr>())
-    return true;
-
+bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
   const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
   if (FD) {
     LanguageLinkage L = FD->getLanguageLinkage();
@@ -440,26 +431,6 @@
 }
 
 void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
-  // Any decl can be declared with __asm("foo") on it, and this takes precedence
-  // over all other naming in the .o file.
-  if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
-    // If we have an asm name, then we use it as the mangling.
-
-    // Adding the prefix can cause problems when one file has a "foo" and
-    // another has a "\01foo". That is known to happen on ELF with the
-    // tricks normally used for producing aliases (PR9177). Fortunately the
-    // llvm mangler on ELF is a nop, so we can just avoid adding the \01
-    // marker.  We also avoid adding the marker if this is an alias for an
-    // LLVM intrinsic.
-    StringRef UserLabelPrefix =
-      getASTContext().getTargetInfo().getUserLabelPrefix();
-    if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
-      Out << '\01';  // LLVM IR Marker for __asm("foo")
-
-    Out << ALA->getLabel();
-    return;
-  }
-
   // <mangled-name> ::= _Z <encoding>
   //            ::= <data name>
   //            ::= <special-name>
@@ -3632,8 +3603,8 @@
 /// and this routine will return false. In this case, the caller should just
 /// emit the identifier of the declaration (\c D->getIdentifier()) as its
 /// name.
-void ItaniumMangleContextImpl::mangleName(const NamedDecl *D,
-                                          raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXName(const NamedDecl *D,
+                                             raw_ostream &Out) {
   assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
           "Invalid mangleName() call, argument is not a variable or function!");
   assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 07c84b2..231ef03 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -10,6 +10,7 @@
 // Implements generic name mangling support for blocks and Objective-C.
 //
 //===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
 #include "clang/AST/Mangle.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
@@ -19,6 +20,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/Basic/ABI.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
@@ -47,6 +49,130 @@
 
 void MangleContext::anchor() { }
 
+enum StdOrFastCC {
+  SOF_OTHER,
+  SOF_FAST,
+  SOF_STD
+};
+
+static bool isExternC(const NamedDecl *ND) {
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+    return FD->isExternC();
+  return cast<VarDecl>(ND)->isExternC();
+}
+
+static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context,
+                                            const NamedDecl *ND) {
+  const TargetInfo &TI = Context.getTargetInfo();
+  llvm::Triple Triple = TI.getTriple();
+  if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86)
+    return SOF_OTHER;
+
+  if (Context.getLangOpts().CPlusPlus && !isExternC(ND) &&
+      TI.getCXXABI() == TargetCXXABI::Microsoft)
+    return SOF_OTHER;
+
+  const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+  if (!FD)
+    return SOF_OTHER;
+  QualType T = FD->getType();
+
+  const FunctionType *FT = T->castAs<FunctionType>();
+
+  CallingConv CC = FT->getCallConv();
+  switch (CC) {
+  default:
+    return SOF_OTHER;
+  case CC_X86FastCall:
+    return SOF_FAST;
+  case CC_X86StdCall:
+    return SOF_STD;
+  }
+}
+
+bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
+  const ASTContext &ASTContext = getASTContext();
+
+  StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
+  if (CC != SOF_OTHER)
+    return true;
+
+  // In C, functions with no attributes never need to be mangled. Fastpath them.
+  if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
+    return false;
+
+  // Any decl can be declared with __asm("foo") on it, and this takes precedence
+  // over all other naming in the .o file.
+  if (D->hasAttr<AsmLabelAttr>())
+    return true;
+
+  return shouldMangleCXXName(D);
+}
+
+void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
+  // Any decl can be declared with __asm("foo") on it, and this takes precedence
+  // over all other naming in the .o file.
+  if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
+    // If we have an asm name, then we use it as the mangling.
+
+    // Adding the prefix can cause problems when one file has a "foo" and
+    // another has a "\01foo". That is known to happen on ELF with the
+    // tricks normally used for producing aliases (PR9177). Fortunately the
+    // llvm mangler on ELF is a nop, so we can just avoid adding the \01
+    // marker.  We also avoid adding the marker if this is an alias for an
+    // LLVM intrinsic.
+    StringRef UserLabelPrefix =
+        getASTContext().getTargetInfo().getUserLabelPrefix();
+    if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
+      Out << '\01'; // LLVM IR Marker for __asm("foo")
+
+    Out << ALA->getLabel();
+    return;
+  }
+
+  const ASTContext &ASTContext = getASTContext();
+  StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
+  bool MCXX = shouldMangleCXXName(D);
+  const TargetInfo &TI = Context.getTargetInfo();
+  if (CC == SOF_OTHER || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
+    mangleCXXName(D, Out);
+    return;
+  }
+
+  Out << '\01';
+  if (CC == SOF_STD)
+    Out << '_';
+  else
+    Out << '@';
+
+  if (!MCXX)
+    Out << D->getIdentifier()->getName();
+  else
+    mangleCXXName(D, Out);
+
+  const FunctionDecl *FD = cast<FunctionDecl>(D);
+  const FunctionType *FT = FD->getType()->castAs<FunctionType>();
+  const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT);
+  Out << '@';
+  if (!Proto) {
+    Out << '0';
+    return;
+  }
+  assert(!Proto->isVariadic());
+  unsigned ArgWords = 0;
+  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+    if (!MD->isStatic())
+      ++ArgWords;
+  for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+         ArgEnd = Proto->arg_type_end();
+       Arg != ArgEnd; ++Arg) {
+    QualType AT = *Arg;
+    // Size should be aligned to DWORD boundary
+    ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32;
+  }
+  Out << 4 * ArgWords;
+}
+
 void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
                                       const NamedDecl *ID,
                                       raw_ostream &Out) {
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 2c37709..7194536 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -179,8 +179,8 @@
 public:
   MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
       : MicrosoftMangleContext(Context, Diags) {}
-  virtual bool shouldMangleDeclName(const NamedDecl *D);
-  virtual void mangleName(const NamedDecl *D, raw_ostream &Out);
+  virtual bool shouldMangleCXXName(const NamedDecl *D);
+  virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out);
   virtual void mangleThunk(const CXXMethodDecl *MD,
                            const ThunkInfo &Thunk,
                            raw_ostream &);
@@ -211,16 +211,7 @@
 
 }
 
-bool MicrosoftMangleContextImpl::shouldMangleDeclName(const NamedDecl *D) {
-  // In C, functions with no attributes never need to be mangled. Fastpath them.
-  if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
-    return false;
-
-  // Any decl can be declared with __asm("foo") on it, and this takes precedence
-  // over all other naming in the .o file.
-  if (D->hasAttr<AsmLabelAttr>())
-    return true;
-
+bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     LanguageLinkage L = FD->getLanguageLinkage();
     // Overloadable functions need mangling.
@@ -281,14 +272,6 @@
   // default, we emit an asm marker at the start so we get the name right.
   // Callers can override this with a custom prefix.
 
-  // Any decl can be declared with __asm("foo") on it, and this takes precedence
-  // over all other naming in the .o file.
-  if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
-    // If we have an asm name, then we use it as the mangling.
-    Out << '\01' << ALA->getLabel();
-    return;
-  }
-
   // <mangled-name> ::= ? <name> <type-encoding>
   Out << Prefix;
   mangleName(D);
@@ -1845,8 +1828,8 @@
     << Range;
 }
 
-void MicrosoftMangleContextImpl::mangleName(const NamedDecl *D,
-                                            raw_ostream &Out) {
+void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D,
+                                               raw_ostream &Out) {
   assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
          "Invalid mangleName() call, argument is not a variable or function!");
   assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
diff --git a/test/CodeGen/mangle-windows-rtd.c b/test/CodeGen/mangle-windows-rtd.c
new file mode 100644
index 0000000..fc6f309
--- /dev/null
+++ b/test/CodeGen/mangle-windows-rtd.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -mrtd %s -o - -triple=i386-mingw32 | FileCheck %s
+
+void f1(void) {}
+// CHECK: define x86_stdcallcc void @"\01_f1@0"
+
+void __stdcall f2(void) {}
+// CHECK: define x86_stdcallcc void @"\01_f2@0"
+
+void __fastcall f3(void) {}
+// CHECK: define x86_fastcallcc void @"\01@f3@0"
diff --git a/test/CodeGen/mangle-windows.c b/test/CodeGen/mangle-windows.c
new file mode 100644
index 0000000..6706492
--- /dev/null
+++ b/test/CodeGen/mangle-windows.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft \
+// RUN:     -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | FileCheck %s
+
+void __stdcall f1(void) {}
+// CHECK: define x86_stdcallcc void @"\01_f1@0"
+
+void __fastcall f2(void) {}
+// CHECK: define x86_fastcallcc void @"\01@f2@0"
+
+void __stdcall f3() {}
+// CHECK: define x86_stdcallcc void @"\01_f3@0"
+
+void __fastcall f4(char a) {}
+// CHECK: define x86_fastcallcc void @"\01@f4@4"
+
+void __fastcall f5(short a) {}
+// CHECK: define x86_fastcallcc void @"\01@f5@4"
+
+void __fastcall f6(int a) {}
+// CHECK: define x86_fastcallcc void @"\01@f6@4"
+
+void __fastcall f7(long a) {}
+// CHECK: define x86_fastcallcc void @"\01@f7@4"
+
+void __fastcall f8(long long a) {}
+// CHECK: define x86_fastcallcc void @"\01@f8@8"
+
+void __fastcall f9(long long a, char b, char c, short d) {}
+// CHECK: define x86_fastcallcc void @"\01@f9@20"(i64 %a, i8 signext %b, i8
+// signext %c, i16 signext %d)
+
+void f12(void) {}
+// CHECK: define void @f12(
diff --git a/test/CodeGenCXX/mangle-windows.cpp b/test/CodeGenCXX/mangle-windows.cpp
new file mode 100644
index 0000000..c087616
--- /dev/null
+++ b/test/CodeGenCXX/mangle-windows.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft \
+// RUN:     -triple=i386-pc-win32 | FileCheck --check-prefix=WIN %s
+//
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | \
+// RUN:     FileCheck --check-prefix=ITANIUM %s
+
+void __stdcall f1(void) {}
+// WIN: define x86_stdcallcc void @"\01?f1@@YGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__Z2f1v@0"
+
+void __fastcall f2(void) {}
+// WIN: define x86_fastcallcc void @"\01?f2@@YIXXZ"
+// ITANIUM: define x86_fastcallcc void @"\01@_Z2f2v@0"
+
+extern "C" void __stdcall f3(void) {}
+// WIN: define x86_stdcallcc void @"\01_f3@0"
+// ITANIUM: define x86_stdcallcc void @"\01_f3@0"
+
+extern "C" void __fastcall f4(void) {}
+// WIN: define x86_fastcallcc void @"\01@f4@0"
+// ITANIUM: define x86_fastcallcc void @"\01@f4@0"
+
+struct Foo {
+  void __stdcall foo();
+  static void __stdcall bar();
+};
+
+void Foo::foo() {}
+// WIN: define x86_stdcallcc void @"\01?foo@Foo@@QAGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3fooEv@4"
+
+void Foo::bar() {}
+// WIN: define x86_stdcallcc void @"\01?bar@Foo@@SGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3barEv@0"
+
+// Mostly a test that we don't crash and that the names start with a \01.
+// gcc on mingw produces __Zpp@4
+// cl produces _++@4
+extern "C" void __stdcall operator++(Foo &x) {
+}
+// WIN: define x86_stdcallcc void @"\01??E@YGXAAUFoo@@@Z"
+// ITANIUM: define x86_stdcallcc void @"\01__ZppR3Foo@4"