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

Rafael Espindola rafael.espindola at gmail.com
Tue Oct 15 18:40:35 PDT 2013


Author: rafael
Date: Tue Oct 15 20:40:34 2013
New Revision: 192762

URL: http://llvm.org/viewvc/llvm-project?rev=192762&view=rev
Log:
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.

Added:
    cfe/trunk/test/CodeGen/mangle-windows-rtd.c
    cfe/trunk/test/CodeGen/mangle-windows.c
    cfe/trunk/test/CodeGenCXX/mangle-windows.cpp
Modified:
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/Mangle.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=192762&r1=192761&r2=192762&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Tue Oct 15 20:40:34 2013
@@ -108,10 +108,12 @@ public:
   /// @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;

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=192762&r1=192761&r2=192762&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Oct 15 20:40:34 2013
@@ -125,8 +125,8 @@ public:
   /// @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 @@ private:
 
 }
 
-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 @@ bool ItaniumMangleContextImpl::shouldMan
 }
 
 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 @@ void CXXNameMangler::addSubstitution(uin
 /// 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) &&

Modified: cfe/trunk/lib/AST/Mangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Mangle.cpp?rev=192762&r1=192761&r2=192762&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Mangle.cpp (original)
+++ cfe/trunk/lib/AST/Mangle.cpp Tue Oct 15 20:40:34 2013
@@ -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 @@ static void mangleFunctionBlock(MangleCo
 
 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) {

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=192762&r1=192761&r2=192762&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Tue Oct 15 20:40:34 2013
@@ -179,8 +179,8 @@ class MicrosoftMangleContextImpl : publi
 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 @@ private:
 
 }
 
-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 @@ void MicrosoftCXXNameMangler::mangle(con
   // 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 @@ void MicrosoftCXXNameMangler::mangleType
     << 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) &&

Added: cfe/trunk/test/CodeGen/mangle-windows-rtd.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/mangle-windows-rtd.c?rev=192762&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/mangle-windows-rtd.c (added)
+++ cfe/trunk/test/CodeGen/mangle-windows-rtd.c Tue Oct 15 20:40:34 2013
@@ -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 at 0"
+
+void __stdcall f2(void) {}
+// CHECK: define x86_stdcallcc void @"\01_f2 at 0"
+
+void __fastcall f3(void) {}
+// CHECK: define x86_fastcallcc void @"\01 at f3@0"

Added: cfe/trunk/test/CodeGen/mangle-windows.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/mangle-windows.c?rev=192762&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/mangle-windows.c (added)
+++ cfe/trunk/test/CodeGen/mangle-windows.c Tue Oct 15 20:40:34 2013
@@ -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 at 0"
+
+void __fastcall f2(void) {}
+// CHECK: define x86_fastcallcc void @"\01 at f2@0"
+
+void __stdcall f3() {}
+// CHECK: define x86_stdcallcc void @"\01_f3 at 0"
+
+void __fastcall f4(char a) {}
+// CHECK: define x86_fastcallcc void @"\01 at f4@4"
+
+void __fastcall f5(short a) {}
+// CHECK: define x86_fastcallcc void @"\01 at f5@4"
+
+void __fastcall f6(int a) {}
+// CHECK: define x86_fastcallcc void @"\01 at f6@4"
+
+void __fastcall f7(long a) {}
+// CHECK: define x86_fastcallcc void @"\01 at f7@4"
+
+void __fastcall f8(long long a) {}
+// CHECK: define x86_fastcallcc void @"\01 at f8@8"
+
+void __fastcall f9(long long a, char b, char c, short d) {}
+// CHECK: define x86_fastcallcc void @"\01 at f9@20"(i64 %a, i8 signext %b, i8
+// signext %c, i16 signext %d)
+
+void f12(void) {}
+// CHECK: define void @f12(

Added: cfe/trunk/test/CodeGenCXX/mangle-windows.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-windows.cpp?rev=192762&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-windows.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/mangle-windows.cpp Tue Oct 15 20:40:34 2013
@@ -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 at 0"
+
+void __fastcall f2(void) {}
+// WIN: define x86_fastcallcc void @"\01?f2@@YIXXZ"
+// ITANIUM: define x86_fastcallcc void @"\01 at _Z2f2v@0"
+
+extern "C" void __stdcall f3(void) {}
+// WIN: define x86_stdcallcc void @"\01_f3 at 0"
+// ITANIUM: define x86_stdcallcc void @"\01_f3 at 0"
+
+extern "C" void __fastcall f4(void) {}
+// WIN: define x86_fastcallcc void @"\01 at f4@0"
+// ITANIUM: define x86_fastcallcc void @"\01 at f4@0"
+
+struct Foo {
+  void __stdcall foo();
+  static void __stdcall bar();
+};
+
+void Foo::foo() {}
+// WIN: define x86_stdcallcc void @"\01?foo at Foo@@QAGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3fooEv at 4"
+
+void Foo::bar() {}
+// WIN: define x86_stdcallcc void @"\01?bar at Foo@@SGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3barEv at 0"
+
+// Mostly a test that we don't crash and that the names start with a \01.
+// gcc on mingw produces __Zpp at 4
+// cl produces _++ at 4
+extern "C" void __stdcall operator++(Foo &x) {
+}
+// WIN: define x86_stdcallcc void @"\01??E at YGXAAUFoo@@@Z"
+// ITANIUM: define x86_stdcallcc void @"\01__ZppR3Foo at 4"





More information about the cfe-commits mailing list