277 lines · cpp
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-exception6//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 16using namespace llvm;17 18static 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 26static 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 43namespace {44 45TEST(ManglerTest, MachO) {46 LLVMContext Ctx;47 DataLayout DL("m:o"); // macho48 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 65TEST(ManglerTest, WindowsX86) {66 LLVMContext Ctx;67 DataLayout DL("m:x-p:32:32"); // 32-bit windows68 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 101TEST(ManglerTest, WindowsX64) {102 LLVMContext Ctx;103 DataLayout DL("m:w-p:64:64"); // windows104 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 137TEST(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_64141 Module Mod("test", Ctx);142 Mod.setDataLayout(DL);143 Mangler Mang;144 EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");145 EXPECT_EQ(mangleStr("\01foo", 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 158TEST(ManglerTest, XCOFF) {159 LLVMContext Ctx;160 DataLayout DL("m:a"); // XCOFF/AIX161 Module Mod("test", Ctx);162 Mod.setDataLayout(DL);163 Mangler Mang;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::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 178TEST(ManglerTest, GOFF) {179 LLVMContext Ctx;180 DataLayout DL("m:l"); // GOFF181 Module Mod("test", Ctx);182 Mod.setDataLayout(DL);183 Mangler Mang;184 185 EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");186 EXPECT_EQ(mangleStr("\01foo", 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 196TEST(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/115231205 "?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) const240 // { return 3; }241 // template class Wrapper<A>;242 // ```243 // public: int __cdecl Wrapper<struct A>::GetValue(struct WW<struct244 // A>::Z)const245 "?GetValue@?$Wrapper@UA@@@@$$hQEBAHUZ@?$WW@UA@@@@@Z",246 247 // MD5 symbol248 "??@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@$$h@",249 };250 251 for (const auto &Arm64ECName : Arm64ECNames) {252 // Check that this is a mangled name.253 EXPECT_TRUE(isArm64ECMangledFunctionName(Arm64ECName))254 << "Test case: " << Arm64ECName;255 // Refuse to mangle it again.256 EXPECT_FALSE(getArm64ECMangledFunctionName(Arm64ECName).has_value())257 << "Test case: " << Arm64ECName;258 259 // Demangle.260 auto Arm64Name = getArm64ECDemangledFunctionName(Arm64ECName);261 EXPECT_TRUE(Arm64Name.has_value()) << "Test case: " << Arm64ECName;262 // Check that it is not mangled.263 EXPECT_FALSE(isArm64ECMangledFunctionName(Arm64Name.value()))264 << "Test case: " << Arm64ECName;265 // Refuse to demangle it again.266 EXPECT_FALSE(getArm64ECDemangledFunctionName(Arm64Name.value()).has_value())267 << "Test case: " << Arm64ECName;268 269 // Round-trip.270 auto RoundTripArm64ECName =271 getArm64ECMangledFunctionName(Arm64Name.value());272 EXPECT_EQ(RoundTripArm64ECName, Arm64ECName);273 }274}275 276} // end anonymous namespace277