From: Douglas Gregor Date: Fri, 13 Feb 2009 00:10:09 +0000 (+0000) Subject: Add basic support for C++ name mangling according to the Itanium C++ X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5f2bfd4811996abb783aa6c7254c56baa6930e8c;p=clang Add basic support for C++ name mangling according to the Itanium C++ ABI to the CodeGen library. Since C++ code-generation is so incomplete, we can't exercise much of this mangling code. However, a few smoke tests show that it's doing the same thing as GCC. When C++ codegen matures, we'll extend the ABI tester to verify name-mangling as well, and complete the implementation here. At this point, the major client of name mangling is in the uses of the new "overloadable" attribute in C, which allows overloading. Any "overloadable" function in C (or in an extern "C" block in C++) will be mangled the same way that the corresponding C++ function would be mangled. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64413 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 5c03b332ef..30d994b9df 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -474,6 +474,10 @@ public: return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace; } + bool isTranslationUnit() const { + return DeclKind == Decl::TranslationUnit; + } + bool isRecord() const { return DeclKind == Decl::Record || DeclKind == Decl::CXXRecord; } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index a32b78dedb..3b912ce3d6 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -101,7 +101,7 @@ CodeGenFunction::GenerateStaticBlockVarDecl(const VarDecl &D, std::string ContextName; if (const FunctionDecl *FD = dyn_cast(CurFuncDecl)) - ContextName = FD->getNameAsString(); + ContextName = CGM.getMangledName(FD)->getName(); else if (isa(CurFuncDecl)) ContextName = std::string(CurFn->getNameStart(), CurFn->getNameStart() + CurFn->getNameLen()); @@ -164,7 +164,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // A normal fixed sized variable becomes an alloca in the entry block. const llvm::Type *LTy = ConvertType(Ty); llvm::AllocaInst *Alloc = - CreateTempAlloca(LTy, D.getIdentifier()->getName()); + CreateTempAlloca(LTy, CGM.getMangledName(&D)->getName()); unsigned align = getContext().getTypeAlign(Ty); if (const AlignedAttr* AA = D.getAttr()) align = std::max(align, AA->getAlignment()); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 7ef6fdf2af..83fbd72f90 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -714,7 +714,7 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) { std::string FunctionName; if(const FunctionDecl *FD = dyn_cast(CurFuncDecl)) { - FunctionName = FD->getNameAsString(); + FunctionName = CGM.getMangledName(FD)->getName(); } else { // Just get the mangled name. FunctionName = CurFn->getName(); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index c59853a1b7..1820c0b9f0 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -18,5 +18,6 @@ add_clang_library(clangCodeGen CodeGenFunction.cpp CodeGenModule.cpp CodeGenTypes.cpp + Mangle.cpp ModuleBuilder.cpp ) diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index b46d24a2fc..322f8bf565 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -171,7 +171,7 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy, if (CGDebugInfo *DI = CGM.getDebugInfo()) { DI->setLocation(StartLoc); if (const FunctionDecl *FD = dyn_cast(D)) { - DI->EmitFunctionStart(FD->getIdentifier()->getName(), + DI->EmitFunctionStart(CGM.getMangledName(FD)->getName(), RetTy, CurFn, Builder); } else { // Just use LLVM function name. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a3b79562d1..df4a3d0763 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -16,6 +16,7 @@ #include "CodeGenFunction.h" #include "CGCall.h" #include "CGObjCRuntime.h" +#include "Mangle.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" @@ -148,6 +149,29 @@ static void setGlobalVisibility(llvm::GlobalValue *GV, } } +/// \brief Retrieves the mangled name for the given declaration. +/// +/// If the given declaration requires a mangled name, returns an +/// IdentifierInfo* containing the mangled name. Otherwise, returns +/// the name of the declaration as an identifier. +/// +/// FIXME: Returning an IdentifierInfo* here is a total hack. We +/// really need some kind of string abstraction that either stores a +/// mangled name or stores an IdentifierInfo*. This will require +/// changes to the GlobalDeclMap, too. +/// +/// FIXME: Performance here is going to be terribly until we start +/// caching mangled names. However, we should fix the problem above +/// first. +IdentifierInfo *CodeGenModule::getMangledName(const NamedDecl *ND) const { + std::string Name; + llvm::raw_string_ostream Out(Name); + if (!mangleName(ND, Context, Out)) + return ND->getIdentifier(); + + return &Context.Idents.get(Out.str()); +} + /// AddGlobalCtor - Add a function to the list that will be called before /// main() runs. void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor, int Priority) { @@ -340,9 +364,10 @@ void CodeGenModule::EmitAliases() { llvm::GlobalValue *GA = new llvm::GlobalAlias(aliasee->getType(), llvm::Function::ExternalLinkage, - D->getNameAsString(), aliasee, &getModule()); + getMangledName(D)->getName(), aliasee, + &getModule()); - llvm::GlobalValue *&Entry = GlobalDeclMap[D->getIdentifier()]; + llvm::GlobalValue *&Entry = GlobalDeclMap[getMangledName(D)]; if (Entry) { // If we created a dummy function for this then replace it. GA->takeName(Entry); @@ -377,7 +402,7 @@ void CodeGenModule::EmitStatics() { // global symbol map. // FIXME: This is missing some important cases. For example, we // need to check for uses in an alias and in a constructor. - if (!GlobalDeclMap.count(D->getIdentifier())) { + if (!GlobalDeclMap.count(getMangledName(D))) { i++; continue; } @@ -498,13 +523,13 @@ void CodeGenModule::EmitGlobalDefinition(const ValueDecl *D) { const llvm::Type *PTy = llvm::PointerType::get(Ty, ASTTy.getAddressSpace()); // Lookup the entry, lazily creating it if necessary. - llvm::GlobalValue *&Entry = GlobalDeclMap[D->getIdentifier()]; + llvm::GlobalValue *&Entry = GlobalDeclMap[getMangledName(D)]; if (!Entry) { llvm::GlobalVariable *GV = new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage, - 0, D->getNameAsString(), &getModule(), 0, - ASTTy.getAddressSpace()); + 0, getMangledName(D)->getName(), &getModule(), + 0, ASTTy.getAddressSpace()); Entry = GV; // Handle things which are present even on external declarations. @@ -545,14 +570,14 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { } const llvm::Type* InitType = Init->getType(); - llvm::GlobalValue *&Entry = GlobalDeclMap[D->getIdentifier()]; + llvm::GlobalValue *&Entry = GlobalDeclMap[getMangledName(D)]; llvm::GlobalVariable *GV = cast_or_null(Entry); if (!GV) { GV = new llvm::GlobalVariable(InitType, false, llvm::GlobalValue::ExternalLinkage, - 0, D->getNameAsString(), &getModule(), 0, - ASTTy.getAddressSpace()); + 0, getMangledName(D)->getName(), + &getModule(), 0, ASTTy.getAddressSpace()); } else if (GV->getType() != llvm::PointerType::get(InitType, ASTTy.getAddressSpace())) { // We have a definition after a prototype with the wrong type. @@ -575,8 +600,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // Make a new global with the correct type GV = new llvm::GlobalVariable(InitType, false, llvm::GlobalValue::ExternalLinkage, - 0, D->getNameAsString(), &getModule(), 0, - ASTTy.getAddressSpace()); + 0, getMangledName(D)->getName(), + &getModule(), 0, ASTTy.getAddressSpace()); // Steal the name of the old global GV->takeName(OldGV); @@ -672,7 +697,8 @@ CodeGenModule::EmitForwardFunctionDefinition(const FunctionDecl *D) { const llvm::Type *Ty = getTypes().ConvertType(D->getType()); llvm::Function *F = llvm::Function::Create(cast(Ty), llvm::Function::ExternalLinkage, - D->getNameAsString(),&getModule()); + getMangledName(D)->getName(), + &getModule()); SetFunctionAttributes(D, F); return F; } @@ -683,7 +709,7 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(const FunctionDecl *D) { const llvm::Type *PTy = llvm::PointerType::get(Ty, ASTTy.getAddressSpace()); // Lookup the entry, lazily creating it if necessary. - llvm::GlobalValue *&Entry = GlobalDeclMap[D->getIdentifier()]; + llvm::GlobalValue *&Entry = GlobalDeclMap[getMangledName(D)]; if (!Entry) Entry = EmitForwardFunctionDefinition(D); @@ -691,7 +717,7 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(const FunctionDecl *D) { } void CodeGenModule::EmitGlobalFunctionDefinition(const FunctionDecl *D) { - llvm::GlobalValue *&Entry = GlobalDeclMap[D->getIdentifier()]; + llvm::GlobalValue *&Entry = GlobalDeclMap[getMangledName(D)]; if (!Entry) { Entry = EmitForwardFunctionDefinition(D); } else { diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 0c3964fd5f..d8719efabf 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -88,6 +88,7 @@ class CodeGenModule { /// decl, they should be bitcasted on retrieval. Also note that the /// globals are keyed on their source name, not the global name /// (which may change with attributes such as asm-labels). + /// This key to this map should be generated using getMangledName(). llvm::DenseMap GlobalDeclMap; /// Aliases - List of aliases in module. These cannot be emitted @@ -257,6 +258,9 @@ public: const Decl *TargetDecl, AttributeListType &PAL); + IdentifierInfo *getMangledName(const NamedDecl *ND) const; + + private: /// SetFunctionAttributesForDefinition - Set function attributes /// specific to a function definition. diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp new file mode 100644 index 0000000000..a97ac58dd7 --- /dev/null +++ b/lib/CodeGen/Mangle.cpp @@ -0,0 +1,516 @@ +//===--------------------- Mangle.cpp - Mangle C++ Names ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements C++ name mangling according to the Itanium C++ ABI, +// which is used in GCC 3.2 and newer (and many compilers that are +// ABI-compatible with GCC): +// +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +//===----------------------------------------------------------------------===// +#include "Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN CXXNameMangler { + ASTContext &Context; + llvm::raw_ostream &Out; + + public: + CXXNameMangler(ASTContext &C, llvm::raw_ostream &os) + : Context(C), Out(os) { } + + bool mangle(const NamedDecl *D); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleName(const NamedDecl *ND); + void mangleUnqualifiedName(const NamedDecl *ND); + void mangleSourceName(const IdentifierInfo *II); + void mangleNestedName(const NamedDecl *ND); + void manglePrefix(const DeclContext *DC); + void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); + void mangleCVQualifiers(unsigned Quals); + void mangleType(QualType T); + void mangleType(const BuiltinType *T); + void mangleType(const FunctionType *T); + void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType); + void mangleType(const TagType *T); + void mangleType(const ArrayType *T); + void mangleType(const MemberPointerType *T); + void mangleType(const TemplateTypeParmType *T); + void mangleExpression(Expr *E); + }; +} + + +bool CXXNameMangler::mangle(const NamedDecl *D) { + // ::= _Z + // ::= + // ::= + + // FIXME: Actually use a visitor to decode these? + if (const FunctionDecl *FD = dyn_cast(D)) { + bool RequiresMangling = false; + // Clang's "overloadable" attribute extension to C/C++ + if (FD->getAttr()) + RequiresMangling = true; + else if (Context.getLangOptions().CPlusPlus) { + RequiresMangling = true; + if (isa(FD->getDeclContext()) && + cast(FD->getDeclContext())->getLanguage() + == LinkageSpecDecl::lang_c) { + // Entities with C linkage are not mangled. + RequiresMangling = false; + } + } + + if (RequiresMangling) { + Out << "_Z"; + mangleFunctionEncoding(FD); + return true; + } + } + + return false; +} + +void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // ::= + mangleName(FD); + mangleBareFunctionType(FD->getType()->getAsFunctionType(), false); +} + +static bool isStdNamespace(const DeclContext *DC) { + if (!DC->isNamespace() || !DC->getParent()->isTranslationUnit()) + return false; + + const NamespaceDecl *NS = cast(DC); + const IdentifierInfo *Name = NS->getIdentifier(); + if (Name->getLength() != 3) + return false; + + const char *Str = Name->getName(); + if (Str[0] != 's' || Str[1] != 't' || Str[2] != 'd') + return false; + + return true; +} + +void CXXNameMangler::mangleName(const NamedDecl *ND) { + // ::= + // ::= + // ::= + // ::= # See Scope Encoding below + // + // ::= + // ::= St # ::std:: + if (ND->getDeclContext()->isTranslationUnit()) + mangleUnqualifiedName(ND); + else if (isStdNamespace(ND->getDeclContext())) { + Out << "St"; + mangleUnqualifiedName(ND); + } else { + mangleNestedName(ND); + } +} + +void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { + // ::= + // ::= + // ::= + DeclarationName Name = ND->getDeclName(); + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + mangleSourceName(Name.getAsIdentifierInfo()); + break; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Can't mangle Objective-C selector names here!"); + break; + + case DeclarationName::CXXConstructorName: + // ::= C1 # complete object constructor + // ::= C2 # base object constructor + // ::= C3 # complete object allocating constructor + // + // FIXME: We don't even have all of these constructors + // in the AST yet. + Out << "C1"; + break; + + case DeclarationName::CXXDestructorName: + // ::= D0 # deleting destructor + // ::= D1 # complete object destructor + // ::= D2 # base object destructor + // + // FIXME: We don't even have all of these destructors in the AST + // yet. + Out << "D0"; + break; + + case DeclarationName::CXXConversionFunctionName: + assert(false && "Not sure how to mangle conversion functions yet"); + break; + + case DeclarationName::CXXOperatorName: + mangleOperatorName(Name.getCXXOverloadedOperator(), + cast(ND)->getNumParams()); + break; + + case DeclarationName::CXXUsingDirective: + assert(false && "Can't mangle a using directive name!"); + } +} + +void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { + // ::= + // ::= [n] + // ::= + Out << II->getLength() << II->getName(); +} + +void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { + // ::= N [] E + // ::= N [] E + // FIXME: no template support + Out << 'N'; + if (const CXXMethodDecl *Method = dyn_cast(ND)) + mangleCVQualifiers(Method->getTypeQualifiers()); + manglePrefix(ND->getDeclContext()); + mangleUnqualifiedName(ND); + Out << 'E'; +} + +void CXXNameMangler::manglePrefix(const DeclContext *DC) { + // ::= + // ::= + // ::= + // ::= # empty + // ::= + // FIXME: We only handle mangling of namespaces and classes at the moment. + if (DC->getParent() != DC) + manglePrefix(DC); + + if (const NamespaceDecl *Namespace = dyn_cast(DC)) + mangleSourceName(Namespace->getIdentifier()); + else if (const RecordDecl *Record = dyn_cast(DC)) + mangleSourceName(Record->getIdentifier()); +} + +void +CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { + switch (OO) { + // ::= nw # new + case OO_New: Out << "nw"; break; + // ::= na # new[] + case OO_Array_New: Out << "na"; break; + // ::= dl # delete + case OO_Delete: Out << "dl"; break; + // ::= da # delete[] + case OO_Array_Delete: Out << "da"; break; + // ::= ps # + (unary) + // ::= pl # + + case OO_Plus: Out << (Arity == 1? "ps" : "pl"); break; + // ::= ng # - (unary) + // ::= mi # - + case OO_Minus: Out << (Arity == 1? "ng" : "mi"); break; + // ::= ad # & (unary) + // ::= an # & + case OO_Amp: Out << (Arity == 1? "ad" : "an"); break; + // ::= de # * (unary) + // ::= ml # * + case OO_Star: Out << (Arity == 1? "de" : "ml"); break; + // ::= co # ~ + case OO_Tilde: Out << "co"; break; + // ::= dv # / + case OO_Slash: Out << "dv"; break; + // ::= rm # % + case OO_Percent: Out << "rm"; break; + // ::= or # | + case OO_Pipe: Out << "or"; break; + // ::= eo # ^ + case OO_Caret: Out << "eo"; break; + // ::= aS # = + case OO_Equal: Out << "aS"; break; + // ::= pL # += + case OO_PlusEqual: Out << "pL"; break; + // ::= mI # -= + case OO_MinusEqual: Out << "mI"; break; + // ::= mL # *= + case OO_StarEqual: Out << "mL"; break; + // ::= dV # /= + case OO_SlashEqual: Out << "dV"; break; + // ::= rM # %= + case OO_PercentEqual: Out << "rM"; break; + // ::= aN # &= + case OO_AmpEqual: Out << "aN"; break; + // ::= oR # |= + case OO_PipeEqual: Out << "oR"; break; + // ::= eO # ^= + case OO_CaretEqual: Out << "eO"; break; + // ::= ls # << + case OO_LessLess: Out << "ls"; break; + // ::= rs # >> + case OO_GreaterGreater: Out << "rs"; break; + // ::= lS # <<= + case OO_LessLessEqual: Out << "lS"; break; + // ::= rS # >>= + case OO_GreaterGreaterEqual: Out << "rS"; break; + // ::= eq # == + case OO_EqualEqual: Out << "eq"; break; + // ::= ne # != + case OO_ExclaimEqual: Out << "ne"; break; + // ::= lt # < + case OO_Less: Out << "lt"; break; + // ::= gt # > + case OO_Greater: Out << "gt"; break; + // ::= le # <= + case OO_LessEqual: Out << "le"; break; + // ::= ge # >= + case OO_GreaterEqual: Out << "ge"; break; + // ::= nt # ! + case OO_Exclaim: Out << "nt"; break; + // ::= aa # && + case OO_AmpAmp: Out << "aa"; break; + // ::= oo # || + case OO_PipePipe: Out << "oo"; break; + // ::= pp # ++ + case OO_PlusPlus: Out << "pp"; break; + // ::= mm # -- + case OO_MinusMinus: Out << "mm"; break; + // ::= cm # , + case OO_Comma: Out << "cm"; break; + // ::= pm # ->* + case OO_ArrowStar: Out << "pm"; break; + // ::= pt # -> + case OO_Arrow: Out << "pt"; break; + // ::= cl # () + case OO_Call: Out << "cl"; break; + // ::= ix # [] + case OO_Subscript: Out << "ix"; break; + // UNSUPPORTED: ::= qu # ? + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Not an ovelroaded operator"); + break; + } +} + +void CXXNameMangler::mangleCVQualifiers(unsigned Quals) { + // ::= [r] [V] [K] # restrict (C99), volatile, const + if (Quals & QualType::Restrict) + Out << 'r'; + if (Quals & QualType::Volatile) + Out << 'V'; + if (Quals & QualType::Const) + Out << 'K'; +} + +void CXXNameMangler::mangleType(QualType T) { + // Only operate on the canonical type! + T = Context.getCanonicalType(T); + + // FIXME: Should we have a TypeNodes.def to make this easier? (YES!) + + // ::= + mangleCVQualifiers(T.getCVRQualifiers()); + + // ::= + if (const BuiltinType *BT = dyn_cast(T.getTypePtr())) + mangleType(BT); + // ::= + else if (const FunctionType *FT = dyn_cast(T.getTypePtr())) + mangleType(FT); + // ::= + else if (const TagType *TT = dyn_cast(T.getTypePtr())) + mangleType(TT); + // ::= + else if (const ArrayType *AT = dyn_cast(T.getTypePtr())) + mangleType(AT); + // ::= + else if (const MemberPointerType *MPT + = dyn_cast(T.getTypePtr())) + mangleType(MPT); + // ::= + else if (const TemplateTypeParmType *TypeParm + = dyn_cast(T.getTypePtr())) + mangleType(TypeParm); + // FIXME: ::= + // FIXME: ::= # See Compression below + // ::= P # pointer-to + else if (const PointerType *PT = dyn_cast(T.getTypePtr())) { + Out << 'P'; + mangleType(PT->getPointeeType()); + } + // ::= R # reference-to + // ::= O # rvalue reference-to (C++0x) + else if (const ReferenceType *RT = dyn_cast(T.getTypePtr())) { + // FIXME: rvalue references + Out << 'R'; + mangleType(RT->getPointeeType()); + } + // ::= C # complex pair (C 2000) + else if (const ComplexType *CT = dyn_cast(T.getTypePtr())) { + Out << 'C'; + mangleType(CT->getElementType()); + } else if (const VectorType *VT = dyn_cast(T.getTypePtr())) { + // GNU extension: vector types + Out << "U8__vector"; + mangleType(VT->getElementType()); + } + // FIXME: ::= G # imaginary (C 2000) + // FIXME: ::= U # vendor extended type qualifier + else + assert(false && "Cannot mangle unknown type"); +} + +void CXXNameMangler::mangleType(const BuiltinType *T) { + // ::= v # void + // ::= w # wchar_t + // ::= b # bool + // ::= c # char + // ::= a # signed char + // ::= h # unsigned char + // ::= s # short + // ::= t # unsigned short + // ::= i # int + // ::= j # unsigned int + // ::= l # long + // ::= m # unsigned long + // ::= x # long long, __int64 + // ::= y # unsigned long long, __int64 + // ::= n # __int128 + // UNSUPPORTED: ::= o # unsigned __int128 + // ::= f # float + // ::= d # double + // ::= e # long double, __float80 + // UNSUPPORTED: ::= g # __float128 + // NOT HERE: ::= z # ellipsis + // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) + // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) + // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) + // UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits) + // UNSUPPORTED: ::= Di # char32_t + // UNSUPPORTED: ::= Ds # char16_t + // ::= u # vendor extended type + switch (T->getKind()) { + case BuiltinType::Void: Out << 'v'; break; + case BuiltinType::Bool: Out << 'b'; break; + case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break; + case BuiltinType::UChar: Out << 'h'; break; + case BuiltinType::UShort: Out << 't'; break; + case BuiltinType::UInt: Out << 'j'; break; + case BuiltinType::ULong: Out << 'm'; break; + case BuiltinType::ULongLong: Out << 'y'; break; + case BuiltinType::SChar: Out << 'a'; break; + case BuiltinType::WChar: Out << 'w'; break; + case BuiltinType::Short: Out << 's'; break; + case BuiltinType::Int: Out << 'i'; break; + case BuiltinType::Long: Out << 'l'; break; + case BuiltinType::LongLong: Out << 'x'; break; + case BuiltinType::Float: Out << 'f'; break; + case BuiltinType::Double: Out << 'd'; break; + case BuiltinType::LongDouble: Out << 'e'; break; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + assert(false && + "Overloaded and dependent types shouldn't get to name mangling"); + break; + } +} + +void CXXNameMangler::mangleType(const FunctionType *T) { + // ::= F [Y] E + Out << 'F'; + // FIXME: We don't have enough information in the AST to produce the + // 'Y' encoding for extern "C" function types. + mangleBareFunctionType(T, /*MangleReturnType=*/true); + Out << 'E'; +} + +void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType) { + // ::= + + if (MangleReturnType) + mangleType(T->getResultType()); + + const FunctionTypeProto *Proto = dyn_cast(T); + assert(Proto && "Can't mangle K&R function prototypes"); + + for (FunctionTypeProto::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(*Arg); +} + +void CXXNameMangler::mangleType(const TagType *T) { + // ::= + mangleName(T->getDecl()); +} + +void CXXNameMangler::mangleType(const ArrayType *T) { + // ::= A _ + // ::= A [] _ + Out << 'A'; + if (const ConstantArrayType *CAT = dyn_cast(T)) + Out << CAT->getSize(); + else if (const VariableArrayType *VAT = dyn_cast(T)) + mangleExpression(VAT->getSizeExpr()); + else if (const DependentSizedArrayType *DSAT + = dyn_cast(T)) + mangleExpression(DSAT->getSizeExpr()); + + Out << '_'; + mangleType(T->getElementType()); +} + +void CXXNameMangler::mangleType(const MemberPointerType *T) { + // ::= M + Out << 'M'; + mangleType(QualType(T->getClass(), 0)); + mangleType(T->getPointeeType()); +} + +void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { + // ::= T_ # first template parameter + // ::= T _ + if (T->getIndex() == 0) + Out << "T_"; + else + Out << 'T' << (T->getIndex() - 1) << '_'; +} + +void CXXNameMangler::mangleExpression(Expr *E) { + assert(false && "Cannot mangle expressions yet"); +} + +namespace clang { + /// \brief Mangles the name of the declaration D and emits that name + /// to the given output stream. + /// + /// If the declaration D requires a mangled name, this routine will + /// emit that mangled name to \p os and return true. Otherwise, \p + /// os will be unchanged 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. + bool mangleName(const NamedDecl *D, ASTContext &Context, + llvm::raw_ostream &os) { + CXXNameMangler Mangler(Context, os); + return Mangler.mangle(D); + } +} + diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h new file mode 100644 index 0000000000..404f8bddb7 --- /dev/null +++ b/lib/CodeGen/Mangle.h @@ -0,0 +1,32 @@ +//===---------------------- Mangle.h - Mangle C++ Names -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements C++ name mangling according to the Itanium C++ ABI, +// which is used in GCC 3.2 and newer (and many compilers that are +// ABI-compatible with GCC): +// +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_CODEGEN_MANGLE_H +#define LLVM_CLANG_CODEGEN_MANGLE_H + +namespace llvm { + class raw_ostream; +} + +namespace clang { + class ASTContext; + class NamedDecl; + + bool mangleName(const NamedDecl *D, ASTContext &Context, + llvm::raw_ostream &os); +} + +#endif diff --git a/test/CodeGen/overloadable.c b/test/CodeGen/overloadable.c new file mode 100644 index 0000000000..6b1cb351e6 --- /dev/null +++ b/test/CodeGen/overloadable.c @@ -0,0 +1,24 @@ +// RUN: clang -emit-llvm %s -o - | grep _Z1fPA10_1X +int __attribute__((overloadable)) f(int x) { return x; } +float __attribute__((overloadable)) f(float x) { return x; } +double __attribute__((overloadable)) f(double x) { return x; } +double _Complex __attribute__((overloadable)) f(double _Complex x) { return x; } +typedef short v4hi __attribute__ ((__vector_size__ (8))); +v4hi __attribute__((overloadable)) f(v4hi x) { return x; } + +struct X { }; +void __attribute__((overloadable)) f(struct X (*ptr)[10]) { } + +int main() { + int iv = 17; + float fv = 3.0f; + double dv = 4.0; + double _Complex cdv; + v4hi vv; + + iv = f(iv); + fv = f(fv); + dv = f(dv); + cdv = f(cdv); + vv = f(vv); +} diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp new file mode 100644 index 0000000000..7b92c85046 --- /dev/null +++ b/test/CodeGenCXX/mangle.cpp @@ -0,0 +1,9 @@ +// RUN: clang -emit-llvm %s -o - | grep _ZplRK1YRA100_P1X + +// FIXME: This test is intentionally trivial, because we can't yet +// CodeGen anything real in C++. +struct X { }; +struct Y { }; + +bool operator+(const Y&, X* (&xs)[100]) { return false; } +