forked from OSchip/llvm-project
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. llvm-svn: 192762
This commit is contained in:
parent
d2b497b522
commit
002667c32b
|
@ -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;
|
||||
|
|
|
@ -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::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<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(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<FunctionDecl>(D) || isa<VarDecl>(D)) &&
|
||||
"Invalid mangleName() call, argument is not a variable or function!");
|
||||
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
|
||||
|
|
|
@ -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<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) {
|
||||
|
|
|
@ -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<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(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<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(const AtomicType *T,
|
|||
<< 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) &&
|
||||
|
|
|
@ -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"
|
|
@ -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(
|
|
@ -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"
|
Loading…
Reference in New Issue