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