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