274 lines
9.9 KiB
C++
274 lines
9.9 KiB
C++
//===- llvm/unittest/IR/ManglerTest.cpp - Mangler unit tests --------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/IR/Mangler.h"
|
|
#include "llvm/IR/CallingConv.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/GlobalValue.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static std::string mangleStr(StringRef IRName, Mangler &Mang,
|
|
const DataLayout &DL) {
|
|
std::string Mangled;
|
|
raw_string_ostream SS(Mangled);
|
|
Mang.getNameWithPrefix(SS, IRName, DL);
|
|
return Mangled;
|
|
}
|
|
|
|
static std::string mangleFunc(StringRef IRName,
|
|
GlobalValue::LinkageTypes Linkage,
|
|
llvm::CallingConv::ID CC, Module &Mod,
|
|
Mangler &Mang) {
|
|
Type *VoidTy = Type::getVoidTy(Mod.getContext());
|
|
Type *I32Ty = Type::getInt32Ty(Mod.getContext());
|
|
FunctionType *FTy =
|
|
FunctionType::get(VoidTy, {I32Ty, I32Ty, I32Ty}, /*isVarArg=*/false);
|
|
Function *F = Function::Create(FTy, Linkage, IRName, &Mod);
|
|
F->setCallingConv(CC);
|
|
std::string Mangled;
|
|
raw_string_ostream SS(Mangled);
|
|
Mang.getNameWithPrefix(SS, F, false);
|
|
F->eraseFromParent();
|
|
return Mangled;
|
|
}
|
|
|
|
namespace {
|
|
|
|
TEST(ManglerTest, MachO) {
|
|
LLVMContext Ctx;
|
|
DataLayout DL("m:o"); // macho
|
|
Module Mod("test", Ctx);
|
|
Mod.setDataLayout(DL);
|
|
Mangler Mang;
|
|
EXPECT_EQ(mangleStr("foo", Mang, DL), "_foo");
|
|
EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("?foo", Mang, DL), "_?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"_foo");
|
|
EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"_?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"L_foo");
|
|
}
|
|
|
|
TEST(ManglerTest, WindowsX86) {
|
|
LLVMContext Ctx;
|
|
DataLayout DL("m:x-p:32:32"); // 32-bit windows
|
|
Module Mod("test", Ctx);
|
|
Mod.setDataLayout(DL);
|
|
Mangler Mang;
|
|
EXPECT_EQ(mangleStr("foo", Mang, DL), "_foo");
|
|
EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"_foo");
|
|
EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"L_foo");
|
|
|
|
// Test calling conv mangling.
|
|
EXPECT_EQ(mangleFunc("stdcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_StdCall, Mod, Mang),
|
|
"_stdcall@12");
|
|
EXPECT_EQ(mangleFunc("fastcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_FastCall, Mod, Mang),
|
|
"@fastcall@12");
|
|
EXPECT_EQ(mangleFunc("vectorcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_VectorCall, Mod, Mang),
|
|
"vectorcall@@12");
|
|
|
|
// Adding a '?' prefix blocks calling convention mangling.
|
|
EXPECT_EQ(mangleFunc("?fastcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_FastCall, Mod, Mang),
|
|
"?fastcall");
|
|
}
|
|
|
|
TEST(ManglerTest, WindowsX64) {
|
|
LLVMContext Ctx;
|
|
DataLayout DL("m:w-p:64:64"); // windows
|
|
Module Mod("test", Ctx);
|
|
Mod.setDataLayout(DL);
|
|
Mangler Mang;
|
|
EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"foo");
|
|
EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
".Lfoo");
|
|
|
|
// Test calling conv mangling.
|
|
EXPECT_EQ(mangleFunc("stdcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_StdCall, Mod, Mang),
|
|
"stdcall");
|
|
EXPECT_EQ(mangleFunc("fastcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_FastCall, Mod, Mang),
|
|
"fastcall");
|
|
EXPECT_EQ(mangleFunc("vectorcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_VectorCall, Mod, Mang),
|
|
"vectorcall@@24");
|
|
|
|
// Adding a '?' prefix blocks calling convention mangling.
|
|
EXPECT_EQ(mangleFunc("?vectorcall", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::X86_VectorCall, Mod, Mang),
|
|
"?vectorcall");
|
|
}
|
|
|
|
TEST(ManglerTest, UEFIX64) {
|
|
LLVMContext Ctx;
|
|
DataLayout DL("e-m:w-p270:32:32-p271:32:32-p272:64:64-"
|
|
"i64:64-i128:128-f80:128-n8:16:32:64-S128"); // uefi X86_64
|
|
Module Mod("test", Ctx);
|
|
Mod.setDataLayout(DL);
|
|
Mangler Mang;
|
|
EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"foo");
|
|
EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
".Lfoo");
|
|
}
|
|
|
|
TEST(ManglerTest, XCOFF) {
|
|
LLVMContext Ctx;
|
|
DataLayout DL("m:a"); // XCOFF/AIX
|
|
Module Mod("test", Ctx);
|
|
Mod.setDataLayout(DL);
|
|
Mangler Mang;
|
|
EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"foo");
|
|
EXPECT_EQ(mangleFunc("?foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"L..foo");
|
|
}
|
|
|
|
TEST(ManglerTest, GOFF) {
|
|
LLVMContext Ctx;
|
|
DataLayout DL("m:l"); // GOFF
|
|
Module Mod("test", Ctx);
|
|
Mod.setDataLayout(DL);
|
|
Mangler Mang;
|
|
|
|
EXPECT_EQ(mangleStr("foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("\01foo", Mang, DL), "foo");
|
|
EXPECT_EQ(mangleStr("?foo", Mang, DL), "?foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::ExternalLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"foo");
|
|
EXPECT_EQ(mangleFunc("foo", llvm::GlobalValue::PrivateLinkage,
|
|
llvm::CallingConv::C, Mod, Mang),
|
|
"L#foo");
|
|
}
|
|
|
|
TEST(ManglerTest, Arm64EC) {
|
|
constexpr std::string_view Arm64ECNames[] = {
|
|
// Basic C name.
|
|
"#Foo",
|
|
|
|
// Basic C++ name.
|
|
"?foo@@$$hYAHXZ",
|
|
|
|
// Regression test: https://github.com/llvm/llvm-project/issues/115231
|
|
"?GetValue@?$Wrapper@UA@@@@$$hQEBAHXZ",
|
|
|
|
// Symbols from:
|
|
// ```
|
|
// namespace A::B::C::D {
|
|
// struct Base {
|
|
// virtual int f() { return 0; }
|
|
// };
|
|
// }
|
|
// struct Derived : public A::B::C::D::Base {
|
|
// virtual int f() override { return 1; }
|
|
// };
|
|
// A::B::C::D::Base* MakeObj() { return new Derived(); }
|
|
// ```
|
|
// void * __cdecl operator new(unsigned __int64)
|
|
"??2@$$hYAPEAX_K@Z",
|
|
// public: virtual int __cdecl A::B::C::D::Base::f(void)
|
|
"?f@Base@D@C@B@A@@$$hUEAAHXZ",
|
|
// public: __cdecl A::B::C::D::Base::Base(void)
|
|
"??0Base@D@C@B@A@@$$hQEAA@XZ",
|
|
// public: virtual int __cdecl Derived::f(void)
|
|
"?f@Derived@@$$hUEAAHXZ",
|
|
// public: __cdecl Derived::Derived(void)
|
|
"??0Derived@@$$hQEAA@XZ",
|
|
// struct A::B::C::D::Base * __cdecl MakeObj(void)
|
|
"?MakeObj@@$$hYAPEAUBase@D@C@B@A@@XZ",
|
|
|
|
// Symbols from:
|
|
// ```
|
|
// template <typename T> struct WW { struct Z{}; };
|
|
// template <typename X> struct Wrapper {
|
|
// int GetValue(typename WW<X>::Z) const;
|
|
// };
|
|
// struct A { };
|
|
// template <typename X> int Wrapper<X>::GetValue(typename WW<X>::Z) const
|
|
// { return 3; }
|
|
// template class Wrapper<A>;
|
|
// ```
|
|
// public: int __cdecl Wrapper<struct A>::GetValue(struct WW<struct
|
|
// A>::Z)const
|
|
"?GetValue@?$Wrapper@UA@@@@$$hQEBAHUZ@?$WW@UA@@@@@Z",
|
|
};
|
|
|
|
for (const auto &Arm64ECName : Arm64ECNames) {
|
|
// Check that this is a mangled name.
|
|
EXPECT_TRUE(isArm64ECMangledFunctionName(Arm64ECName))
|
|
<< "Test case: " << Arm64ECName;
|
|
// Refuse to mangle it again.
|
|
EXPECT_FALSE(getArm64ECMangledFunctionName(Arm64ECName).has_value())
|
|
<< "Test case: " << Arm64ECName;
|
|
|
|
// Demangle.
|
|
auto Arm64Name = getArm64ECDemangledFunctionName(Arm64ECName);
|
|
EXPECT_TRUE(Arm64Name.has_value()) << "Test case: " << Arm64ECName;
|
|
// Check that it is not mangled.
|
|
EXPECT_FALSE(isArm64ECMangledFunctionName(Arm64Name.value()))
|
|
<< "Test case: " << Arm64ECName;
|
|
// Refuse to demangle it again.
|
|
EXPECT_FALSE(getArm64ECDemangledFunctionName(Arm64Name.value()).has_value())
|
|
<< "Test case: " << Arm64ECName;
|
|
|
|
// Round-trip.
|
|
auto RoundTripArm64ECName =
|
|
getArm64ECMangledFunctionName(Arm64Name.value());
|
|
EXPECT_EQ(RoundTripArm64ECName, Arm64ECName);
|
|
}
|
|
}
|
|
|
|
} // end anonymous namespace
|