summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/LangRef.rst15
-rw-r--r--llvm/docs/ReleaseNotes.rst3
-rw-r--r--llvm/include/llvm/IR/DataLayout.h6
-rw-r--r--llvm/lib/IR/Mangler.cpp12
-rw-r--r--llvm/test/CodeGen/X86/mangle-question-mark.ll60
-rw-r--r--llvm/test/MC/COFF/symbol-mangling.ll17
-rw-r--r--llvm/unittests/IR/CMakeLists.txt1
-rw-r--r--llvm/unittests/IR/ManglerTest.cpp140
8 files changed, 230 insertions, 24 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 9d8242f29d7..5bbbf32710d 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -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,
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 53d3abec956..1deeb650e7d 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -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
diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h
index 00eb9523152..c48e140f3a6 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -263,6 +263,12 @@ public:
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 {
diff --git a/llvm/lib/IR/Mangler.cpp b/llvm/lib/IR/Mangler.cpp
index 7adcc59f571..be3086cfcf0 100644
--- a/llvm/lib/IR/Mangler.cpp
+++ b/llvm/lib/IR/Mangler.cpp
@@ -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)
@@ -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() &&
diff --git a/llvm/test/CodeGen/X86/mangle-question-mark.ll b/llvm/test/CodeGen/X86/mangle-question-mark.ll
new file mode 100644
index 00000000000..582f65d3987
--- /dev/null
+++ b/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
+}
diff --git a/llvm/test/MC/COFF/symbol-mangling.ll b/llvm/test/MC/COFF/symbol-mangling.ll
deleted file mode 100644
index f1b4b4becd0..00000000000
--- a/llvm/test/MC/COFF/symbol-mangling.ll
+++ /dev/null
@@ -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*)
diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
index 15f869c6bd4..b2782a930f8 100644
--- a/llvm/unittests/IR/CMakeLists.txt
+++ b/llvm/unittests/IR/CMakeLists.txt
@@ -25,6 +25,7 @@ set(IRSources
IntrinsicsTest.cpp
LegacyPassManagerTest.cpp
MDBuilderTest.cpp
+ ManglerTest.cpp
MetadataTest.cpp
ModuleTest.cpp
PassManagerTest.cpp
diff --git a/llvm/unittests/IR/ManglerTest.cpp b/llvm/unittests/IR/ManglerTest.cpp
new file mode 100644
index 00000000000..04f1ca6cf97
--- /dev/null
+++ b/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
OpenPOWER on IntegriCloud