Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -1940,17 +1940,22 @@ ``a::`` This specifies the alignment for an object of aggregate type. ``m:`` - If present, specifies that llvm names are mangled in the output. The + If present, specifies that llvm names are mangled in the output. Symbols + prefixed with the mangling escape character ``\01`` are passed through + directly to the assembler without the escape character. The mangling style options are * ``e``: ELF mangling: Private symbols get a ``.L`` prefix. * ``m``: Mips mangling: Private symbols get a ``$`` prefix. * ``o``: Mach-O mangling: Private symbols get ``L`` prefix. Other symbols get a ``_`` prefix. - * ``w``: Windows COFF prefix: Similar to Mach-O, but stdcall and fastcall - functions also get a suffix based on the frame size. - * ``x``: Windows x86 COFF prefix: Similar to Windows COFF, but use a ``_`` - prefix for ``__cdecl`` functions. + * ``x``: Windows x86 COFF mangling: Private symbols get the usual prefix. + Regular C symbols get a ``_`` prefix. Functions with ``__stdcall``, + ``__fastcall``, and ``__vectorcall`` have custom mangling that appends + ``@N`` where N is the number of bytes used to pass parameters. C++ symbols + starting with ``?`` are not mangled in any way. + * ``w``: Windows COFF mangling: Similar to ``x``, except that normal C + symbols do not receive a ``_`` prefix. ``n::...`` This specifies a set of native integer widths for the target CPU in bits. For example, it might contain ``n32`` for 32-bit PowerPC, Index: llvm/trunk/docs/ReleaseNotes.rst =================================================================== --- llvm/trunk/docs/ReleaseNotes.rst +++ llvm/trunk/docs/ReleaseNotes.rst @@ -42,6 +42,9 @@ * The LoopInstSimplify pass (-loop-instsimplify) has been removed. +* Symbols starting with ``?`` are no longer mangled by LLVM when using the + Windows ``x`` or ``w`` IR mangling schemes. + * Note.. .. NOTE Index: llvm/trunk/include/llvm/IR/DataLayout.h =================================================================== --- llvm/trunk/include/llvm/IR/DataLayout.h +++ llvm/trunk/include/llvm/IR/DataLayout.h @@ -263,6 +263,12 @@ return ManglingMode == MM_WinCOFFX86; } + /// Returns true if symbols with leading question marks should not receive IR + /// mangling. True for Windows mangling modes. + bool doNotMangleLeadingQuestionMark() const { + return ManglingMode == MM_WinCOFF || ManglingMode == MM_WinCOFFX86; + } + bool hasLinkerPrivateGlobalPrefix() const { return ManglingMode == MM_MachO; } StringRef getLinkerPrivateGlobalPrefix() const { Index: llvm/trunk/lib/IR/Mangler.cpp =================================================================== --- llvm/trunk/lib/IR/Mangler.cpp +++ llvm/trunk/lib/IR/Mangler.cpp @@ -44,6 +44,9 @@ return; } + if (DL.doNotMangleLeadingQuestionMark() && Name[0] == '?') + Prefix = '\0'; + if (PrefixTy == Private) OS << DL.getPrivateGlobalPrefix(); else if (PrefixTy == LinkerPrivate) @@ -135,8 +138,13 @@ // Mangle functions with Microsoft calling conventions specially. Only do // this mangling for x86_64 vectorcall and 32-bit x86. const Function *MSFunc = dyn_cast(GV); - if (Name.startswith("\01")) - MSFunc = nullptr; // Don't mangle when \01 is present. + + // Don't add byte count suffixes when '\01' or '?' are in the first + // character. + if (Name.startswith("\01") || + (DL.doNotMangleLeadingQuestionMark() && Name.startswith("?"))) + MSFunc = nullptr; + CallingConv::ID CC = MSFunc ? MSFunc->getCallingConv() : (unsigned)CallingConv::C; if (!DL.hasMicrosoftFastStdCallMangling() && Index: llvm/trunk/test/CodeGen/X86/mangle-question-mark.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/mangle-question-mark.ll +++ llvm/trunk/test/CodeGen/X86/mangle-question-mark.ll @@ -0,0 +1,60 @@ +; Test that symbols starting with '?' are not affected by IR mangling. + +; RUN: llc -mtriple i686-pc-win32 < %s | FileCheck %s --check-prefix=COFF +; RUN: llc -mtriple x86_64-pc-win32 < %s | FileCheck %s --check-prefix=COFF64 +; RUN: llc -mtriple i686-linux-gnu < %s | FileCheck %s --check-prefix=ELF +; RUN: llc -mtriple i686-apple-darwin < %s | FileCheck %s --check-prefix=MACHO + +; Currently all object files allow escaping private symbols, but eventually we +; might want to reject that. + +; COFF: calll "?withescape@A@@QBEXXZ" +; COFF: calll "?withquestion@A@@QBEXXZ" +; COFF: calll "L?privatequestion@A@@QBEXXZ" +; COFF: calll "L?privatequestionfast@A@@QBEXXZ" +; COFF: calll "?escapedprivate@A@@QBEXXZ" + +; COFF64: callq "?withescape@A@@QBEXXZ" +; COFF64: callq "?withquestion@A@@QBEXXZ" +; COFF64: callq ".L?privatequestion@A@@QBEXXZ" +; COFF64: callq ".L?privatequestionfast@A@@QBEXXZ" +; COFF64: callq "?escapedprivate@A@@QBEXXZ" + +; ELF: calll "?withescape@A@@QBEXXZ" +; ELF: calll "?withquestion@A@@QBEXXZ" +; ELF: calll ".L?privatequestion@A@@QBEXXZ" +; ELF: calll ".L?privatequestionfast@A@@QBEXXZ" +; ELF: calll "?escapedprivate@A@@QBEXXZ" + +; MACHO: calll "?withescape@A@@QBEXXZ" +; MACHO: calll "_?withquestion@A@@QBEXXZ" +; MACHO: calll "l_?privatequestion@A@@QBEXXZ" +; MACHO: calll "l_?privatequestionfast@A@@QBEXXZ" +; MACHO: calll "?escapedprivate@A@@QBEXXZ" + +%struct.A = type {} + +define i32 @main() { +entry: + tail call void @"\01?withescape@A@@QBEXXZ"(%struct.A* null) + tail call void @"?withquestion@A@@QBEXXZ"(%struct.A* null) + tail call void @"?privatequestion@A@@QBEXXZ"(%struct.A* null) + tail call x86_fastcallcc void @"?privatequestionfast@A@@QBEXXZ"(%struct.A* null) + tail call void @"\01?escapedprivate@A@@QBEXXZ"(%struct.A* null) + ret i32 0 +} + +declare void @"\01?withescape@A@@QBEXXZ"(%struct.A*) +declare void @"?withquestion@A@@QBEXXZ"(%struct.A*) + +define private void @"?privatequestion@A@@QBEXXZ"(%struct.A*) { + ret void +} + +define private x86_fastcallcc void @"?privatequestionfast@A@@QBEXXZ"(%struct.A*) { + ret void +} + +define private void @"\01?escapedprivate@A@@QBEXXZ"(%struct.A*) { + ret void +} Index: llvm/trunk/test/MC/COFF/symbol-mangling.ll =================================================================== --- llvm/trunk/test/MC/COFF/symbol-mangling.ll +++ llvm/trunk/test/MC/COFF/symbol-mangling.ll @@ -1,17 +0,0 @@ -; The purpose of this test is to see if the MC layer properly handles symbol -; names needing quoting on MS/Windows. This code is generated by clang when -; using -cxx-abi microsoft. - -; RUN: llc -filetype=asm -mtriple i686-pc-win32 %s -o - | FileCheck %s - -; CHECK: ?sayhi@A@@QBEXXZ - -%struct.A = type {} - -define i32 @main() { -entry: - tail call void @"\01?sayhi@A@@QBEXXZ"(%struct.A* null) - ret i32 0 -} - -declare void @"\01?sayhi@A@@QBEXXZ"(%struct.A*) Index: llvm/trunk/unittests/IR/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/IR/CMakeLists.txt +++ llvm/trunk/unittests/IR/CMakeLists.txt @@ -25,6 +25,7 @@ IntrinsicsTest.cpp LegacyPassManagerTest.cpp MDBuilderTest.cpp + ManglerTest.cpp MetadataTest.cpp ModuleTest.cpp PassManagerTest.cpp Index: llvm/trunk/unittests/IR/ManglerTest.cpp =================================================================== --- llvm/trunk/unittests/IR/ManglerTest.cpp +++ llvm/trunk/unittests/IR/ManglerTest.cpp @@ -0,0 +1,140 @@ +//===- llvm/unittest/IR/ManglerTest.cpp - Mangler unit tests --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Mangler.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Module.h" +#include "gtest/gtest.h" + +using namespace llvm; + +static std::string mangleStr(StringRef IRName, Mangler &Mang, + const DataLayout &DL) { + std::string Mangled; + raw_string_ostream SS(Mangled); + Mang.getNameWithPrefix(SS, IRName, DL); + SS.flush(); + return Mangled; +} + +static std::string mangleFunc(StringRef IRName, + GlobalValue::LinkageTypes Linkage, + llvm::CallingConv::ID CC, Module &Mod, + Mangler &Mang) { + Type *VoidTy = Type::getVoidTy(Mod.getContext()); + Type *I32Ty = Type::getInt32Ty(Mod.getContext()); + FunctionType *FTy = + FunctionType::get(VoidTy, {I32Ty, I32Ty, I32Ty}, /*isVarArg=*/false); + Function *F = Function::Create(FTy, Linkage, IRName, &Mod); + F->setCallingConv(CC); + std::string Mangled; + raw_string_ostream SS(Mangled); + Mang.getNameWithPrefix(SS, F, false); + SS.flush(); + F->eraseFromParent(); + return Mangled; +} + +namespace { + +TEST(ManglerTest, MachO) { + LLVMContext Ctx; + DataLayout DL("m:o"); // macho + Module Mod("test", Ctx); + Mod.setDataLayout(DL); + Mangler Mang; + EXPECT_EQ(mangleStr("foo", Mang, DL), "_foo"); + EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo"); + EXPECT_EQ(mangleStr("?foo", Mang, DL), "_?foo"); + EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::C, Mod, Mang), + "_foo"); + EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::C, Mod, Mang), + "_?foo"); + EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage, + llvm::CallingConv::C, Mod, Mang), + "L_foo"); +} + +TEST(ManglerTest, WindowsX86) { + LLVMContext Ctx; + DataLayout DL("m:x-p:32:32"); // 32-bit windows + Module Mod("test", Ctx); + Mod.setDataLayout(DL); + Mangler Mang; + EXPECT_EQ(mangleStr("foo", Mang, DL), "_foo"); + EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo"); + EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo"); + EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::C, Mod, Mang), + "_foo"); + EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::C, Mod, Mang), + "?foo"); + EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage, + llvm::CallingConv::C, Mod, Mang), + "L_foo"); + + // Test calling conv mangling. + EXPECT_EQ(mangleFunc("stdcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_StdCall, Mod, Mang), + "_stdcall@12"); + EXPECT_EQ(mangleFunc("fastcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_FastCall, Mod, Mang), + "@fastcall@12"); + EXPECT_EQ(mangleFunc("vectorcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_VectorCall, Mod, Mang), + "vectorcall@@12"); + + // Adding a '?' prefix blocks calling convention mangling. + EXPECT_EQ(mangleFunc("?fastcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_FastCall, Mod, Mang), + "?fastcall"); +} + +TEST(ManglerTest, WindowsX64) { + LLVMContext Ctx; + DataLayout DL("m:w-p:64:64"); // windows + Module Mod("test", Ctx); + Mod.setDataLayout(DL); + Mangler Mang; + EXPECT_EQ(mangleStr("foo", Mang, DL), "foo"); + EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo"); + EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo"); + EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::C, Mod, Mang), + "foo"); + EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::C, Mod, Mang), + "?foo"); + EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage, + llvm::CallingConv::C, Mod, Mang), + ".Lfoo"); + + // Test calling conv mangling. + EXPECT_EQ(mangleFunc("stdcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_StdCall, Mod, Mang), + "stdcall"); + EXPECT_EQ(mangleFunc("fastcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_FastCall, Mod, Mang), + "fastcall"); + EXPECT_EQ(mangleFunc("vectorcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_VectorCall, Mod, Mang), + "vectorcall@@24"); + + // Adding a '?' prefix blocks calling convention mangling. + EXPECT_EQ(mangleFunc("?vectorcall", llvm::GlobalValue::ExternalLinkage, + llvm::CallingConv::X86_VectorCall, Mod, Mang), + "?vectorcall"); +} + +} // end anonymous namespace