xref: /llvm-project/llvm/unittests/IR/ManglerTest.cpp (revision fa0cf3d39e03c3c63478f30a4c8c17d119b54b7f)
1 //===- llvm/unittest/IR/ManglerTest.cpp - Mangler unit tests --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/IR/Mangler.h"
10 #include "llvm/IR/CallingConv.h"
11 #include "llvm/IR/DataLayout.h"
12 #include "llvm/IR/GlobalValue.h"
13 #include "llvm/IR/Module.h"
14 #include "gtest/gtest.h"
15 
16 using namespace llvm;
17 
18 static std::string mangleStr(StringRef IRName, Mangler &Mang,
19                              const DataLayout &DL) {
20   std::string Mangled;
21   raw_string_ostream SS(Mangled);
22   Mang.getNameWithPrefix(SS, IRName, DL);
23   return Mangled;
24 }
25 
26 static std::string mangleFunc(StringRef IRName,
27                               GlobalValue::LinkageTypes Linkage,
28                               llvm::CallingConv::ID CC, Module &Mod,
29                               Mangler &Mang) {
30   Type *VoidTy = Type::getVoidTy(Mod.getContext());
31   Type *I32Ty = Type::getInt32Ty(Mod.getContext());
32   FunctionType *FTy =
33       FunctionType::get(VoidTy, {I32Ty, I32Ty, I32Ty}, /*isVarArg=*/false);
34   Function *F = Function::Create(FTy, Linkage, IRName, &Mod);
35   F->setCallingConv(CC);
36   std::string Mangled;
37   raw_string_ostream SS(Mangled);
38   Mang.getNameWithPrefix(SS, F, false);
39   F->eraseFromParent();
40   return Mangled;
41 }
42 
43 namespace {
44 
45 TEST(ManglerTest, MachO) {
46   LLVMContext Ctx;
47   DataLayout DL("m:o"); // macho
48   Module Mod("test", Ctx);
49   Mod.setDataLayout(DL);
50   Mangler Mang;
51   EXPECT_EQ(mangleStr("foo", Mang, DL), "_foo");
52   EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
53   EXPECT_EQ(mangleStr("?foo", Mang, DL), "_?foo");
54   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
55                        llvm::CallingConv::C, Mod, Mang),
56             "_foo");
57   EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
58                        llvm::CallingConv::C, Mod, Mang),
59             "_?foo");
60   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
61                        llvm::CallingConv::C, Mod, Mang),
62             "L_foo");
63 }
64 
65 TEST(ManglerTest, WindowsX86) {
66   LLVMContext Ctx;
67   DataLayout DL("m:x-p:32:32"); // 32-bit windows
68   Module Mod("test", Ctx);
69   Mod.setDataLayout(DL);
70   Mangler Mang;
71   EXPECT_EQ(mangleStr("foo", Mang, DL), "_foo");
72   EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
73   EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
74   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
75                        llvm::CallingConv::C, Mod, Mang),
76             "_foo");
77   EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
78                        llvm::CallingConv::C, Mod, Mang),
79             "?foo");
80   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
81                        llvm::CallingConv::C, Mod, Mang),
82             "L_foo");
83 
84   // Test calling conv mangling.
85   EXPECT_EQ(mangleFunc("stdcall", llvm::GlobalValue::ExternalLinkage,
86                        llvm::CallingConv::X86_StdCall, Mod, Mang),
87             "_stdcall@12");
88   EXPECT_EQ(mangleFunc("fastcall", llvm::GlobalValue::ExternalLinkage,
89                        llvm::CallingConv::X86_FastCall, Mod, Mang),
90             "@fastcall@12");
91   EXPECT_EQ(mangleFunc("vectorcall", llvm::GlobalValue::ExternalLinkage,
92                        llvm::CallingConv::X86_VectorCall, Mod, Mang),
93             "vectorcall@@12");
94 
95   // Adding a '?' prefix blocks calling convention mangling.
96   EXPECT_EQ(mangleFunc("?fastcall", llvm::GlobalValue::ExternalLinkage,
97                        llvm::CallingConv::X86_FastCall, Mod, Mang),
98             "?fastcall");
99 }
100 
101 TEST(ManglerTest, WindowsX64) {
102   LLVMContext Ctx;
103   DataLayout DL("m:w-p:64:64"); // windows
104   Module Mod("test", Ctx);
105   Mod.setDataLayout(DL);
106   Mangler Mang;
107   EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");
108   EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
109   EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
110   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
111                        llvm::CallingConv::C, Mod, Mang),
112             "foo");
113   EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
114                        llvm::CallingConv::C, Mod, Mang),
115             "?foo");
116   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
117                        llvm::CallingConv::C, Mod, Mang),
118             ".Lfoo");
119 
120   // Test calling conv mangling.
121   EXPECT_EQ(mangleFunc("stdcall", llvm::GlobalValue::ExternalLinkage,
122                        llvm::CallingConv::X86_StdCall, Mod, Mang),
123             "stdcall");
124   EXPECT_EQ(mangleFunc("fastcall", llvm::GlobalValue::ExternalLinkage,
125                        llvm::CallingConv::X86_FastCall, Mod, Mang),
126             "fastcall");
127   EXPECT_EQ(mangleFunc("vectorcall", llvm::GlobalValue::ExternalLinkage,
128                        llvm::CallingConv::X86_VectorCall, Mod, Mang),
129             "vectorcall@@24");
130 
131   // Adding a '?' prefix blocks calling convention mangling.
132   EXPECT_EQ(mangleFunc("?vectorcall", llvm::GlobalValue::ExternalLinkage,
133                        llvm::CallingConv::X86_VectorCall, Mod, Mang),
134             "?vectorcall");
135 }
136 
137 TEST(ManglerTest, XCOFF) {
138   LLVMContext Ctx;
139   DataLayout DL("m:a"); // XCOFF/AIX
140   Module Mod("test", Ctx);
141   Mod.setDataLayout(DL);
142   Mangler Mang;
143   EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");
144   EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
145   EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
146   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
147                        llvm::CallingConv::C, Mod, Mang),
148             "foo");
149   EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
150                        llvm::CallingConv::C, Mod, Mang),
151             "?foo");
152   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
153                        llvm::CallingConv::C, Mod, Mang),
154             "L..foo");
155 }
156 
157 TEST(ManglerTest, GOFF) {
158   LLVMContext Ctx;
159   DataLayout DL("m:l"); // GOFF
160   Module Mod("test", Ctx);
161   Mod.setDataLayout(DL);
162   Mangler Mang;
163 
164   EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");
165   EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
166   EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
167   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
168                        llvm::CallingConv::C, Mod, Mang),
169             "foo");
170   EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
171                        llvm::CallingConv::C, Mod, Mang),
172             "L#foo");
173 }
174 
175 TEST(ManglerTest, Arm64EC) {
176   constexpr std::string_view Arm64ECNames[] = {
177       // Basic C name.
178       "#Foo",
179 
180       // Basic C++ name.
181       "?foo@@$$hYAHXZ",
182 
183       // Regression test: https://github.com/llvm/llvm-project/issues/115231
184       "?GetValue@?$Wrapper@UA@@@@$$hQEBAHXZ",
185 
186       // Symbols from:
187       // ```
188       // namespace A::B::C::D {
189       // struct Base {
190       //   virtual int f() { return 0; }
191       // };
192       // }
193       // struct Derived : public A::B::C::D::Base {
194       //   virtual int f() override { return 1; }
195       // };
196       // A::B::C::D::Base* MakeObj() { return new Derived(); }
197       // ```
198       // void * __cdecl operator new(unsigned __int64)
199       "??2@$$hYAPEAX_K@Z",
200       // public: virtual int __cdecl A::B::C::D::Base::f(void)
201       "?f@Base@D@C@B@A@@$$hUEAAHXZ",
202       // public: __cdecl A::B::C::D::Base::Base(void)
203       "??0Base@D@C@B@A@@$$hQEAA@XZ",
204       // public: virtual int __cdecl Derived::f(void)
205       "?f@Derived@@$$hUEAAHXZ",
206       // public: __cdecl Derived::Derived(void)
207       "??0Derived@@$$hQEAA@XZ",
208       // struct A::B::C::D::Base * __cdecl MakeObj(void)
209       "?MakeObj@@$$hYAPEAUBase@D@C@B@A@@XZ",
210 
211       // Symbols from:
212       // ```
213       // template <typename T> struct WW { struct Z{}; };
214       // template <typename X> struct Wrapper {
215       //   int GetValue(typename WW<X>::Z) const;
216       // };
217       // struct A { };
218       // template <typename X> int Wrapper<X>::GetValue(typename WW<X>::Z) const
219       // { return 3; }
220       // template class Wrapper<A>;
221       // ```
222       // public: int __cdecl Wrapper<struct A>::GetValue(struct WW<struct
223       // A>::Z)const
224       "?GetValue@?$Wrapper@UA@@@@$$hQEBAHUZ@?$WW@UA@@@@@Z",
225   };
226 
227   for (const auto &Arm64ECName : Arm64ECNames) {
228     // Check that this is a mangled name.
229     EXPECT_TRUE(isArm64ECMangledFunctionName(Arm64ECName))
230         << "Test case: " << Arm64ECName;
231     // Refuse to mangle it again.
232     EXPECT_FALSE(getArm64ECMangledFunctionName(Arm64ECName).has_value())
233         << "Test case: " << Arm64ECName;
234 
235     // Demangle.
236     auto Arm64Name = getArm64ECDemangledFunctionName(Arm64ECName);
237     EXPECT_TRUE(Arm64Name.has_value()) << "Test case: " << Arm64ECName;
238     // Check that it is not mangled.
239     EXPECT_FALSE(isArm64ECMangledFunctionName(Arm64Name.value()))
240         << "Test case: " << Arm64ECName;
241     // Refuse to demangle it again.
242     EXPECT_FALSE(getArm64ECDemangledFunctionName(Arm64Name.value()).has_value())
243         << "Test case: " << Arm64ECName;
244 
245     // Round-trip.
246     auto RoundTripArm64ECName =
247         getArm64ECMangledFunctionName(Arm64Name.value());
248     EXPECT_EQ(RoundTripArm64ECName, Arm64ECName);
249   }
250 }
251 
252 } // end anonymous namespace
253