Skip to content

Commit

Permalink
[IR] Avoid the need to prefix MS C++ symbols with '\01'
Browse files Browse the repository at this point in the history
Now the Windows mangling modes ('w' and 'x') do not do any mangling for
symbols starting with '?'. This means that clang can stop adding the
hideous '\01' leading escape. This means LLVM debug logs are less likely
to contain ASCII escape characters and it will be easier to copy and
paste MS symbol names from IR.

Finally.

For non-Windows platforms, names starting with '?' still get IR
mangling, so once clang stops escaping MS C++ names, we will get extra
'_' prefixing on MachO. That's fine, since it is currently impossible to
construct a triple that uses the MS C++ ABI in clang and emits macho
object files.

Differential Revision: https://reviews.llvm.org/D7775

llvm-svn: 327734
  • Loading branch information
rnk committed Mar 16, 2018
1 parent 2aeb930 commit f8b51c5
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 24 deletions.
15 changes: 10 additions & 5 deletions llvm/docs/LangRef.rst
Expand Up @@ -1940,17 +1940,22 @@ as follows:
``a:<abi>:<pref>``
This specifies the alignment for an object of aggregate type.
``m:<mangling>``
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<size1>:<size2>:<size3>...``
This specifies a set of native integer widths for the target CPU in
bits. For example, it might contain ``n32`` for 32-bit PowerPC,
Expand Down
3 changes: 3 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Expand Up @@ -42,6 +42,9 @@ Non-comprehensive list of changes in this release
* 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
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/IR/DataLayout.h
Expand Up @@ -263,6 +263,12 @@ class DataLayout {
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 {
Expand Down
12 changes: 10 additions & 2 deletions llvm/lib/IR/Mangler.cpp
Expand Up @@ -44,6 +44,9 @@ static void getNameWithPrefixImpl(raw_ostream &OS, const Twine &GVName,
return;
}

if (DL.doNotMangleLeadingQuestionMark() && Name[0] == '?')
Prefix = '\0';

if (PrefixTy == Private)
OS << DL.getPrivateGlobalPrefix();
else if (PrefixTy == LinkerPrivate)
Expand Down Expand Up @@ -135,8 +138,13 @@ void Mangler::getNameWithPrefix(raw_ostream &OS, const GlobalValue *GV,
// Mangle functions with Microsoft calling conventions specially. Only do
// this mangling for x86_64 vectorcall and 32-bit x86.
const Function *MSFunc = dyn_cast<Function>(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() &&
Expand Down
60 changes: 60 additions & 0 deletions llvm/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
}
17 changes: 0 additions & 17 deletions llvm/test/MC/COFF/symbol-mangling.ll

This file was deleted.

1 change: 1 addition & 0 deletions llvm/unittests/IR/CMakeLists.txt
Expand Up @@ -25,6 +25,7 @@ set(IRSources
IntrinsicsTest.cpp
LegacyPassManagerTest.cpp
MDBuilderTest.cpp
ManglerTest.cpp
MetadataTest.cpp
ModuleTest.cpp
PassManagerTest.cpp
Expand Down
140 changes: 140 additions & 0 deletions llvm/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

0 comments on commit f8b51c5

Please sign in to comment.