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 (" \01 foo" , 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 (" \01 foo" , 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 (" \01 foo" , 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, UEFIX64) {
138
+ LLVMContext Ctx;
139
+ DataLayout DL (" e-m:w-p270:32:32-p271:32:32-p272:64:64-"
140
+ " i64:64-i128:128-f80:128-n8:16:32:64-S128" ); // uefi X86_64
141
+ Module Mod (" test" , Ctx);
142
+ Mod.setDataLayout (DL);
143
+ Mangler Mang;
144
+ EXPECT_EQ (mangleStr (" foo" , Mang, DL), " foo" );
145
+ EXPECT_EQ (mangleStr (" \01 foo" , Mang, DL), " foo" );
146
+ EXPECT_EQ (mangleStr (" ?foo" , Mang, DL), " ?foo" );
147
+ EXPECT_EQ (mangleFunc (" foo" , llvm::GlobalValue::ExternalLinkage,
148
+ llvm::CallingConv::C, Mod, Mang),
149
+ " foo" );
150
+ EXPECT_EQ (mangleFunc (" ?foo" , llvm::GlobalValue::ExternalLinkage,
151
+ llvm::CallingConv::C, Mod, Mang),
152
+ " ?foo" );
153
+ EXPECT_EQ (mangleFunc (" foo" , llvm::GlobalValue::PrivateLinkage,
154
+ llvm::CallingConv::C, Mod, Mang),
155
+ " .Lfoo" );
156
+ }
157
+
158
+ TEST (ManglerTest, XCOFF) {
159
+ LLVMContext Ctx;
160
+ DataLayout DL (" m:a" ); // XCOFF/AIX
161
+ Module Mod (" test" , Ctx);
162
+ Mod.setDataLayout (DL);
163
+ Mangler Mang;
164
+ EXPECT_EQ (mangleStr (" foo" , Mang, DL), " foo" );
165
+ EXPECT_EQ (mangleStr (" \01 foo" , 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::ExternalLinkage,
171
+ llvm::CallingConv::C, Mod, Mang),
172
+ " ?foo" );
173
+ EXPECT_EQ (mangleFunc (" foo" , llvm::GlobalValue::PrivateLinkage,
174
+ llvm::CallingConv::C, Mod, Mang),
175
+ " L..foo" );
176
+ }
177
+
178
+ TEST (ManglerTest, GOFF) {
179
+ LLVMContext Ctx;
180
+ DataLayout DL (" m:l" ); // GOFF
181
+ Module Mod (" test" , Ctx);
182
+ Mod.setDataLayout (DL);
183
+ Mangler Mang;
184
+
185
+ EXPECT_EQ (mangleStr (" foo" , Mang, DL), " foo" );
186
+ EXPECT_EQ (mangleStr (" \01 foo" , Mang, DL), " foo" );
187
+ EXPECT_EQ (mangleStr (" ?foo" , Mang, DL), " ?foo" );
188
+ EXPECT_EQ (mangleFunc (" foo" , llvm::GlobalValue::ExternalLinkage,
189
+ llvm::CallingConv::C, Mod, Mang),
190
+ " foo" );
191
+ EXPECT_EQ (mangleFunc (" foo" , llvm::GlobalValue::PrivateLinkage,
192
+ llvm::CallingConv::C, Mod, Mang),
193
+ " L#foo" );
194
+ }
195
+
196
+ TEST (ManglerTest, Arm64EC) {
197
+ constexpr std::string_view Arm64ECNames[] = {
198
+ // Basic C name.
199
+ " #Foo" ,
200
+
201
+ // Basic C++ name.
202
+ " ?foo@@$$hYAHXZ" ,
203
+
204
+ // Regression test: https://github.com/llvm/llvm-project/issues/115231
205
+ " ?GetValue@?$Wrapper@UA@@@@$$hQEBAHXZ" ,
206
+
207
+ // Symbols from:
208
+ // ```
209
+ // namespace A::B::C::D {
210
+ // struct Base {
211
+ // virtual int f() { return 0; }
212
+ // };
213
+ // }
214
+ // struct Derived : public A::B::C::D::Base {
215
+ // virtual int f() override { return 1; }
216
+ // };
217
+ // A::B::C::D::Base* MakeObj() { return new Derived(); }
218
+ // ```
219
+ // void * __cdecl operator new(unsigned __int64)
220
+ " ??2@$$hYAPEAX_K@Z" ,
221
+ // public: virtual int __cdecl A::B::C::D::Base::f(void)
222
+ " ?f@Base@D@C@B@A@@$$hUEAAHXZ" ,
223
+ // public: __cdecl A::B::C::D::Base::Base(void)
224
+ " ??0Base@D@C@B@A@@$$hQEAA@XZ" ,
225
+ // public: virtual int __cdecl Derived::f(void)
226
+ " ?f@Derived@@$$hUEAAHXZ" ,
227
+ // public: __cdecl Derived::Derived(void)
228
+ " ??0Derived@@$$hQEAA@XZ" ,
229
+ // struct A::B::C::D::Base * __cdecl MakeObj(void)
230
+ " ?MakeObj@@$$hYAPEAUBase@D@C@B@A@@XZ" ,
231
+
232
+ // Symbols from:
233
+ // ```
234
+ // template <typename T> struct WW { struct Z{}; };
235
+ // template <typename X> struct Wrapper {
236
+ // int GetValue(typename WW<X>::Z) const;
237
+ // };
238
+ // struct A { };
239
+ // template <typename X> int Wrapper<X>::GetValue(typename WW<X>::Z) const
240
+ // { return 3; }
241
+ // template class Wrapper<A>;
242
+ // ```
243
+ // public: int __cdecl Wrapper<struct A>::GetValue(struct WW<struct
244
+ // A>::Z)const
245
+ " ?GetValue@?$Wrapper@UA@@@@$$hQEBAHUZ@?$WW@UA@@@@@Z" ,
246
+ };
247
+
248
+ for (const auto &Arm64ECName : Arm64ECNames) {
249
+ // Check that this is a mangled name.
250
+ EXPECT_TRUE (isArm64ECMangledFunctionName (Arm64ECName))
251
+ << " Test case: " << Arm64ECName;
252
+ // Refuse to mangle it again.
253
+ EXPECT_FALSE (getArm64ECMangledFunctionName (Arm64ECName).has_value ())
254
+ << " Test case: " << Arm64ECName;
255
+
256
+ // Demangle.
257
+ auto Arm64Name = getArm64ECDemangledFunctionName (Arm64ECName);
258
+ EXPECT_TRUE (Arm64Name.has_value ()) << " Test case: " << Arm64ECName;
259
+ // Check that it is not mangled.
260
+ EXPECT_FALSE (isArm64ECMangledFunctionName (Arm64Name.value ()))
261
+ << " Test case: " << Arm64ECName;
262
+ // Refuse to demangle it again.
263
+ EXPECT_FALSE (getArm64ECDemangledFunctionName (Arm64Name.value ()).has_value ())
264
+ << " Test case: " << Arm64ECName;
265
+
266
+ // Round-trip.
267
+ auto RoundTripArm64ECName =
268
+ getArm64ECMangledFunctionName (Arm64Name.value ());
269
+ EXPECT_EQ (RoundTripArm64ECName, Arm64ECName);
270
+ }
271
+ }
272
+
273
+ } // end anonymous namespace
0 commit comments