xref: /llvm-project/bolt/unittests/Core/MCPlusBuilder.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
1fd38366eSAmir Ayupov //===- bolt/unittest/Core/MCPlusBuilder.cpp -------------------------------===//
2fd38366eSAmir Ayupov //
3fd38366eSAmir Ayupov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fd38366eSAmir Ayupov // See https://llvm.org/LICENSE.txt for license information.
5fd38366eSAmir Ayupov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fd38366eSAmir Ayupov //
7fd38366eSAmir Ayupov //===----------------------------------------------------------------------===//
8fd38366eSAmir Ayupov 
9e900f058SVladislav Khmelevsky #ifdef AARCH64_AVAILABLE
10e900f058SVladislav Khmelevsky #include "AArch64Subtarget.h"
11e900f058SVladislav Khmelevsky #endif // AARCH64_AVAILABLE
12e900f058SVladislav Khmelevsky 
13e900f058SVladislav Khmelevsky #ifdef X86_AVAILABLE
14e900f058SVladislav Khmelevsky #include "X86Subtarget.h"
15e900f058SVladislav Khmelevsky #endif // X86_AVAILABLE
16e900f058SVladislav Khmelevsky 
1708dcbed9SAmir Ayupov #include "bolt/Core/BinaryBasicBlock.h"
1808dcbed9SAmir Ayupov #include "bolt/Core/BinaryFunction.h"
19e900f058SVladislav Khmelevsky #include "bolt/Rewrite/RewriteInstance.h"
20e900f058SVladislav Khmelevsky #include "llvm/BinaryFormat/ELF.h"
21e900f058SVladislav Khmelevsky #include "llvm/DebugInfo/DWARF/DWARFContext.h"
22e900f058SVladislav Khmelevsky #include "llvm/Support/TargetSelect.h"
23e900f058SVladislav Khmelevsky #include "gtest/gtest.h"
24e900f058SVladislav Khmelevsky 
25e900f058SVladislav Khmelevsky using namespace llvm;
26e900f058SVladislav Khmelevsky using namespace llvm::object;
27e900f058SVladislav Khmelevsky using namespace llvm::ELF;
28e900f058SVladislav Khmelevsky using namespace bolt;
29e900f058SVladislav Khmelevsky 
30e900f058SVladislav Khmelevsky namespace {
31e900f058SVladislav Khmelevsky struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
32e900f058SVladislav Khmelevsky   void SetUp() override {
33e900f058SVladislav Khmelevsky     initalizeLLVM();
34e900f058SVladislav Khmelevsky     prepareElf();
35e900f058SVladislav Khmelevsky     initializeBolt();
36e900f058SVladislav Khmelevsky   }
37e900f058SVladislav Khmelevsky 
38e900f058SVladislav Khmelevsky protected:
39e900f058SVladislav Khmelevsky   void initalizeLLVM() {
40e900f058SVladislav Khmelevsky     llvm::InitializeAllTargetInfos();
41e900f058SVladislav Khmelevsky     llvm::InitializeAllTargetMCs();
42e900f058SVladislav Khmelevsky     llvm::InitializeAllAsmParsers();
43e900f058SVladislav Khmelevsky     llvm::InitializeAllDisassemblers();
44e900f058SVladislav Khmelevsky     llvm::InitializeAllTargets();
45e900f058SVladislav Khmelevsky     llvm::InitializeAllAsmPrinters();
46e900f058SVladislav Khmelevsky   }
47e900f058SVladislav Khmelevsky 
48e900f058SVladislav Khmelevsky   void prepareElf() {
49e900f058SVladislav Khmelevsky     memcpy(ElfBuf, "\177ELF", 4);
50e900f058SVladislav Khmelevsky     ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
51e900f058SVladislav Khmelevsky     EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
52e900f058SVladislav Khmelevsky     EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
53e900f058SVladislav Khmelevsky     EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
54e900f058SVladislav Khmelevsky     MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
55e900f058SVladislav Khmelevsky     ObjFile = cantFail(ObjectFile::createObjectFile(Source));
56e900f058SVladislav Khmelevsky   }
57e900f058SVladislav Khmelevsky 
58e900f058SVladislav Khmelevsky   void initializeBolt() {
5962e894e0SSayhaan Siddiqui     Relocation::Arch = ObjFile->makeTriple().getArch();
6032d2473aSAmir Ayupov     BC = cantFail(BinaryContext::createBinaryContext(
61*2ccf7ed2SJared Wyles         ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
62*2ccf7ed2SJared Wyles         ObjFile->getFileName(), nullptr, true,
63c0febca3SAmir Ayupov         DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
64e900f058SVladislav Khmelevsky     ASSERT_FALSE(!BC);
658fb83bf5SJob Noorman     BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
668fb83bf5SJob Noorman         createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(),
678fb83bf5SJob Noorman                             BC->MRI.get(), BC->STI.get())));
68e900f058SVladislav Khmelevsky   }
69e900f058SVladislav Khmelevsky 
70e900f058SVladislav Khmelevsky   void testRegAliases(Triple::ArchType Arch, uint64_t Register,
71e900f058SVladislav Khmelevsky                       uint64_t *Aliases, size_t Count,
72e900f058SVladislav Khmelevsky                       bool OnlySmaller = false) {
73e900f058SVladislav Khmelevsky     if (GetParam() != Arch)
74e900f058SVladislav Khmelevsky       GTEST_SKIP();
75e900f058SVladislav Khmelevsky 
76e900f058SVladislav Khmelevsky     const BitVector &BV = BC->MIB->getAliases(Register, OnlySmaller);
77e900f058SVladislav Khmelevsky     ASSERT_EQ(BV.count(), Count);
78e900f058SVladislav Khmelevsky     for (size_t I = 0; I < Count; ++I)
79e900f058SVladislav Khmelevsky       ASSERT_TRUE(BV[Aliases[I]]);
80e900f058SVladislav Khmelevsky   }
81e900f058SVladislav Khmelevsky 
82e900f058SVladislav Khmelevsky   char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
83e900f058SVladislav Khmelevsky   std::unique_ptr<ObjectFile> ObjFile;
84e900f058SVladislav Khmelevsky   std::unique_ptr<BinaryContext> BC;
85e900f058SVladislav Khmelevsky };
86e900f058SVladislav Khmelevsky } // namespace
87e900f058SVladislav Khmelevsky 
88e900f058SVladislav Khmelevsky #ifdef AARCH64_AVAILABLE
89e900f058SVladislav Khmelevsky 
90e900f058SVladislav Khmelevsky INSTANTIATE_TEST_SUITE_P(AArch64, MCPlusBuilderTester,
91e900f058SVladislav Khmelevsky                          ::testing::Values(Triple::aarch64));
92e900f058SVladislav Khmelevsky 
93e900f058SVladislav Khmelevsky TEST_P(MCPlusBuilderTester, AliasX0) {
94318c69deSSander de Smalen   uint64_t AliasesX0[] = {AArch64::W0,    AArch64::W0_HI,
95318c69deSSander de Smalen                           AArch64::X0,    AArch64::W0_W1,
96e900f058SVladislav Khmelevsky                           AArch64::X0_X1, AArch64::X0_X1_X2_X3_X4_X5_X6_X7};
97e900f058SVladislav Khmelevsky   size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
98e900f058SVladislav Khmelevsky   testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count);
99e900f058SVladislav Khmelevsky }
100e900f058SVladislav Khmelevsky 
101e900f058SVladislav Khmelevsky TEST_P(MCPlusBuilderTester, AliasSmallerX0) {
102318c69deSSander de Smalen   uint64_t AliasesX0[] = {AArch64::W0, AArch64::W0_HI, AArch64::X0};
103e900f058SVladislav Khmelevsky   size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
104e900f058SVladislav Khmelevsky   testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count, true);
105e900f058SVladislav Khmelevsky }
106e900f058SVladislav Khmelevsky 
107e900f058SVladislav Khmelevsky #endif // AARCH64_AVAILABLE
108e900f058SVladislav Khmelevsky 
109e900f058SVladislav Khmelevsky #ifdef X86_AVAILABLE
110e900f058SVladislav Khmelevsky 
111e900f058SVladislav Khmelevsky INSTANTIATE_TEST_SUITE_P(X86, MCPlusBuilderTester,
112e900f058SVladislav Khmelevsky                          ::testing::Values(Triple::x86_64));
113e900f058SVladislav Khmelevsky 
114e900f058SVladislav Khmelevsky TEST_P(MCPlusBuilderTester, AliasAX) {
115e900f058SVladislav Khmelevsky   uint64_t AliasesAX[] = {X86::RAX, X86::EAX, X86::AX, X86::AL, X86::AH};
116e900f058SVladislav Khmelevsky   size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
117e900f058SVladislav Khmelevsky   testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount);
118e900f058SVladislav Khmelevsky }
119e900f058SVladislav Khmelevsky 
120e900f058SVladislav Khmelevsky TEST_P(MCPlusBuilderTester, AliasSmallerAX) {
121e900f058SVladislav Khmelevsky   uint64_t AliasesAX[] = {X86::AX, X86::AL, X86::AH};
122e900f058SVladislav Khmelevsky   size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
123e900f058SVladislav Khmelevsky   testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount, true);
124e900f058SVladislav Khmelevsky }
125e900f058SVladislav Khmelevsky 
12608dcbed9SAmir Ayupov TEST_P(MCPlusBuilderTester, ReplaceRegWithImm) {
12708dcbed9SAmir Ayupov   if (GetParam() != Triple::x86_64)
12808dcbed9SAmir Ayupov     GTEST_SKIP();
12908dcbed9SAmir Ayupov   BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
1308228c703SMaksim Panchenko   std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
13108dcbed9SAmir Ayupov   MCInst Inst; // cmpl    %eax, %ebx
13208dcbed9SAmir Ayupov   Inst.setOpcode(X86::CMP32rr);
13308dcbed9SAmir Ayupov   Inst.addOperand(MCOperand::createReg(X86::EAX));
13408dcbed9SAmir Ayupov   Inst.addOperand(MCOperand::createReg(X86::EBX));
13508dcbed9SAmir Ayupov   auto II = BB->addInstruction(Inst);
13608dcbed9SAmir Ayupov   bool Replaced = BC->MIB->replaceRegWithImm(*II, X86::EBX, 1);
13708dcbed9SAmir Ayupov   ASSERT_TRUE(Replaced);
13808dcbed9SAmir Ayupov   ASSERT_EQ(II->getOpcode(), X86::CMP32ri8);
13908dcbed9SAmir Ayupov   ASSERT_EQ(II->getOperand(0).getReg(), X86::EAX);
14008dcbed9SAmir Ayupov   ASSERT_EQ(II->getOperand(1).getImm(), 1);
14108dcbed9SAmir Ayupov }
14208dcbed9SAmir Ayupov 
143e900f058SVladislav Khmelevsky #endif // X86_AVAILABLE
144454c1498SAmir Ayupov 
145454c1498SAmir Ayupov TEST_P(MCPlusBuilderTester, Annotation) {
146454c1498SAmir Ayupov   MCInst Inst;
147bba790dbSMaksim Panchenko   BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
148454c1498SAmir Ayupov                           BC->Ctx.get());
149454c1498SAmir Ayupov   MCSymbol *LPSymbol = BC->Ctx->createNamedTempSymbol("LP");
150454c1498SAmir Ayupov   uint64_t Value = INT32_MIN;
151454c1498SAmir Ayupov   // Test encodeAnnotationImm using this indirect way
152454c1498SAmir Ayupov   BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value));
153454c1498SAmir Ayupov   // Round-trip encoding-decoding check for negative values
1542563fd63SAmir Ayupov   std::optional<MCPlus::MCLandingPad> EHInfo = BC->MIB->getEHInfo(Inst);
1557430894aSFangrui Song   ASSERT_TRUE(EHInfo.has_value());
156c8e6ebd7SKazu Hirata   MCPlus::MCLandingPad LP = EHInfo.value();
157454c1498SAmir Ayupov   uint64_t DecodedValue = LP.second;
158454c1498SAmir Ayupov   ASSERT_EQ(Value, DecodedValue);
159454c1498SAmir Ayupov 
160454c1498SAmir Ayupov   // Large int64 should trigger an out of range assertion
161454c1498SAmir Ayupov   Value = 0x1FF'FFFF'FFFF'FFFFULL;
162454c1498SAmir Ayupov   Inst.clear();
163bba790dbSMaksim Panchenko   BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
164454c1498SAmir Ayupov                           BC->Ctx.get());
165454c1498SAmir Ayupov   ASSERT_DEATH(BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value)),
166454c1498SAmir Ayupov                "annotation value out of range");
167454c1498SAmir Ayupov }
168