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