1 //===- bolt/unittest/Core/MCPlusBuilder.cpp -------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifdef AARCH64_AVAILABLE
10 #include "AArch64Subtarget.h"
11 #endif // AARCH64_AVAILABLE
14 #include "X86Subtarget.h"
15 #endif // X86_AVAILABLE
17 #include "bolt/Core/BinaryBasicBlock.h"
18 #include "bolt/Core/BinaryFunction.h"
19 #include "bolt/Rewrite/RewriteInstance.h"
20 #include "llvm/BinaryFormat/ELF.h"
21 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
22 #include "llvm/Support/TargetSelect.h"
23 #include "gtest/gtest.h"
26 using namespace llvm::object
;
27 using namespace llvm::ELF
;
31 struct MCPlusBuilderTester
: public testing::TestWithParam
<Triple::ArchType
> {
32 void SetUp() override
{
39 void initalizeLLVM() {
40 llvm::InitializeAllTargetInfos();
41 llvm::InitializeAllTargetMCs();
42 llvm::InitializeAllAsmParsers();
43 llvm::InitializeAllDisassemblers();
44 llvm::InitializeAllTargets();
45 llvm::InitializeAllAsmPrinters();
49 memcpy(ElfBuf
, "\177ELF", 4);
50 ELF64LE::Ehdr
*EHdr
= reinterpret_cast<typename
ELF64LE::Ehdr
*>(ElfBuf
);
51 EHdr
->e_ident
[llvm::ELF::EI_CLASS
] = llvm::ELF::ELFCLASS64
;
52 EHdr
->e_ident
[llvm::ELF::EI_DATA
] = llvm::ELF::ELFDATA2LSB
;
53 EHdr
->e_machine
= GetParam() == Triple::aarch64
? EM_AARCH64
: EM_X86_64
;
54 MemoryBufferRef
Source(StringRef(ElfBuf
, sizeof(ElfBuf
)), "ELF");
55 ObjFile
= cantFail(ObjectFile::createObjectFile(Source
));
58 void initializeBolt() {
59 Relocation::Arch
= ObjFile
->makeTriple().getArch();
60 BC
= cantFail(BinaryContext::createBinaryContext(
61 ObjFile
->makeTriple(), ObjFile
->getFileName(), nullptr, true,
62 DWARFContext::create(*ObjFile
.get()), {llvm::outs(), llvm::errs()}));
64 BC
->initializeTarget(std::unique_ptr
<MCPlusBuilder
>(
65 createMCPlusBuilder(GetParam(), BC
->MIA
.get(), BC
->MII
.get(),
66 BC
->MRI
.get(), BC
->STI
.get())));
69 void testRegAliases(Triple::ArchType Arch
, uint64_t Register
,
70 uint64_t *Aliases
, size_t Count
,
71 bool OnlySmaller
= false) {
72 if (GetParam() != Arch
)
75 const BitVector
&BV
= BC
->MIB
->getAliases(Register
, OnlySmaller
);
76 ASSERT_EQ(BV
.count(), Count
);
77 for (size_t I
= 0; I
< Count
; ++I
)
78 ASSERT_TRUE(BV
[Aliases
[I
]]);
81 char ElfBuf
[sizeof(typename
ELF64LE::Ehdr
)] = {};
82 std::unique_ptr
<ObjectFile
> ObjFile
;
83 std::unique_ptr
<BinaryContext
> BC
;
87 #ifdef AARCH64_AVAILABLE
89 INSTANTIATE_TEST_SUITE_P(AArch64
, MCPlusBuilderTester
,
90 ::testing::Values(Triple::aarch64
));
92 TEST_P(MCPlusBuilderTester
, AliasX0
) {
93 uint64_t AliasesX0
[] = {AArch64::W0
, AArch64::W0_HI
,
94 AArch64::X0
, AArch64::W0_W1
,
95 AArch64::X0_X1
, AArch64::X0_X1_X2_X3_X4_X5_X6_X7
};
96 size_t AliasesX0Count
= sizeof(AliasesX0
) / sizeof(*AliasesX0
);
97 testRegAliases(Triple::aarch64
, AArch64::X0
, AliasesX0
, AliasesX0Count
);
100 TEST_P(MCPlusBuilderTester
, AliasSmallerX0
) {
101 uint64_t AliasesX0
[] = {AArch64::W0
, AArch64::W0_HI
, AArch64::X0
};
102 size_t AliasesX0Count
= sizeof(AliasesX0
) / sizeof(*AliasesX0
);
103 testRegAliases(Triple::aarch64
, AArch64::X0
, AliasesX0
, AliasesX0Count
, true);
106 #endif // AARCH64_AVAILABLE
110 INSTANTIATE_TEST_SUITE_P(X86
, MCPlusBuilderTester
,
111 ::testing::Values(Triple::x86_64
));
113 TEST_P(MCPlusBuilderTester
, AliasAX
) {
114 uint64_t AliasesAX
[] = {X86::RAX
, X86::EAX
, X86::AX
, X86::AL
, X86::AH
};
115 size_t AliasesAXCount
= sizeof(AliasesAX
) / sizeof(*AliasesAX
);
116 testRegAliases(Triple::x86_64
, X86::AX
, AliasesAX
, AliasesAXCount
);
119 TEST_P(MCPlusBuilderTester
, AliasSmallerAX
) {
120 uint64_t AliasesAX
[] = {X86::AX
, X86::AL
, X86::AH
};
121 size_t AliasesAXCount
= sizeof(AliasesAX
) / sizeof(*AliasesAX
);
122 testRegAliases(Triple::x86_64
, X86::AX
, AliasesAX
, AliasesAXCount
, true);
125 TEST_P(MCPlusBuilderTester
, ReplaceRegWithImm
) {
126 if (GetParam() != Triple::x86_64
)
128 BinaryFunction
*BF
= BC
->createInjectedBinaryFunction("BF", true);
129 std::unique_ptr
<BinaryBasicBlock
> BB
= BF
->createBasicBlock();
130 MCInst Inst
; // cmpl %eax, %ebx
131 Inst
.setOpcode(X86::CMP32rr
);
132 Inst
.addOperand(MCOperand::createReg(X86::EAX
));
133 Inst
.addOperand(MCOperand::createReg(X86::EBX
));
134 auto II
= BB
->addInstruction(Inst
);
135 bool Replaced
= BC
->MIB
->replaceRegWithImm(*II
, X86::EBX
, 1);
136 ASSERT_TRUE(Replaced
);
137 ASSERT_EQ(II
->getOpcode(), X86::CMP32ri8
);
138 ASSERT_EQ(II
->getOperand(0).getReg(), X86::EAX
);
139 ASSERT_EQ(II
->getOperand(1).getImm(), 1);
142 #endif // X86_AVAILABLE
144 TEST_P(MCPlusBuilderTester
, Annotation
) {
146 BC
->MIB
->createTailCall(Inst
, BC
->Ctx
->createNamedTempSymbol(),
148 MCSymbol
*LPSymbol
= BC
->Ctx
->createNamedTempSymbol("LP");
149 uint64_t Value
= INT32_MIN
;
150 // Test encodeAnnotationImm using this indirect way
151 BC
->MIB
->addEHInfo(Inst
, MCPlus::MCLandingPad(LPSymbol
, Value
));
152 // Round-trip encoding-decoding check for negative values
153 std::optional
<MCPlus::MCLandingPad
> EHInfo
= BC
->MIB
->getEHInfo(Inst
);
154 ASSERT_TRUE(EHInfo
.has_value());
155 MCPlus::MCLandingPad LP
= EHInfo
.value();
156 uint64_t DecodedValue
= LP
.second
;
157 ASSERT_EQ(Value
, DecodedValue
);
159 // Large int64 should trigger an out of range assertion
160 Value
= 0x1FF'FFFF'FFFF'FFFFULL
;
162 BC
->MIB
->createTailCall(Inst
, BC
->Ctx
->createNamedTempSymbol(),
164 ASSERT_DEATH(BC
->MIB
->addEHInfo(Inst
, MCPlus::MCLandingPad(LPSymbol
, Value
)),
165 "annotation value out of range");