diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index 76d099f938a7..d2e532544743 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -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; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index fe8575d5d34b..0d26c9e163ed 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -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()) - return true; - +bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { const FunctionDecl *FD = dyn_cast(D); if (FD) { LanguageLinkage L = FD->getLanguageLinkage(); @@ -440,26 +431,6 @@ bool ItaniumMangleContextImpl::shouldMangleDeclName(const NamedDecl *D) { } 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()) { - // 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; - } - // ::= _Z // ::= // ::= @@ -3632,8 +3603,8 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) { /// 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(D) || isa(D)) && "Invalid mangleName() call, argument is not a variable or function!"); assert(!isa(D) && !isa(D) && diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 07c84b2eb4c7..231ef036d829 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/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 @@ static void mangleFunctionBlock(MangleContext &Context, void MangleContext::anchor() { } +enum StdOrFastCC { + SOF_OTHER, + SOF_FAST, + SOF_STD +}; + +static bool isExternC(const NamedDecl *ND) { + if (const FunctionDecl *FD = dyn_cast(ND)) + return FD->isExternC(); + return cast(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(ND); + if (!FD) + return SOF_OTHER; + QualType T = FD->getType(); + + const FunctionType *FT = T->castAs(); + + 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()) + 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()) { + // 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(D); + const FunctionType *FT = FD->getType()->castAs(); + const FunctionProtoType *Proto = dyn_cast(FT); + Out << '@'; + if (!Proto) { + Out << '0'; + return; + } + assert(!Proto->isVariadic()); + unsigned ArgWords = 0; + if (const CXXMethodDecl *MD = dyn_cast(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/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 2c37709bcf17..7194536c5266 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -179,8 +179,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { 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()) - return true; - +bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { if (const FunctionDecl *FD = dyn_cast(D)) { LanguageLinkage L = FD->getLanguageLinkage(); // Overloadable functions need mangling. @@ -281,14 +272,6 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, // 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()) { - // If we have an asm name, then we use it as the mangling. - Out << '\01' << ALA->getLabel(); - return; - } - // ::= ? Out << Prefix; mangleName(D); @@ -1845,8 +1828,8 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, << Range; } -void MicrosoftMangleContextImpl::mangleName(const NamedDecl *D, - raw_ostream &Out) { +void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D, + raw_ostream &Out) { assert((isa(D) || isa(D)) && "Invalid mangleName() call, argument is not a variable or function!"); assert(!isa(D) && !isa(D) && diff --git a/clang/test/CodeGen/mangle-windows-rtd.c b/clang/test/CodeGen/mangle-windows-rtd.c new file mode 100644 index 000000000000..fc6f309eaf58 --- /dev/null +++ b/clang/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/clang/test/CodeGen/mangle-windows.c b/clang/test/CodeGen/mangle-windows.c new file mode 100644 index 000000000000..670649216ddf --- /dev/null +++ b/clang/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/clang/test/CodeGenCXX/mangle-windows.cpp b/clang/test/CodeGenCXX/mangle-windows.cpp new file mode 100644 index 000000000000..c087616875c7 --- /dev/null +++ b/clang/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"