Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / bolt / unittests / Core / MCPlusBuilder.cpp
blobb851c756e7960e9b21d08177300f19f2b9d2db50
1 #ifdef AARCH64_AVAILABLE
2 #include "AArch64Subtarget.h"
3 #endif // AARCH64_AVAILABLE
5 #ifdef X86_AVAILABLE
6 #include "X86Subtarget.h"
7 #endif // X86_AVAILABLE
9 #include "bolt/Core/BinaryBasicBlock.h"
10 #include "bolt/Core/BinaryFunction.h"
11 #include "bolt/Rewrite/RewriteInstance.h"
12 #include "llvm/BinaryFormat/ELF.h"
13 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14 #include "llvm/Object/ELFObjectFile.h"
15 #include "llvm/Support/TargetSelect.h"
16 #include "gtest/gtest.h"
18 using namespace llvm;
19 using namespace llvm::object;
20 using namespace llvm::ELF;
21 using namespace bolt;
23 namespace {
24 struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
25 void SetUp() override {
26 initalizeLLVM();
27 prepareElf();
28 initializeBolt();
31 protected:
32 void initalizeLLVM() {
33 llvm::InitializeAllTargetInfos();
34 llvm::InitializeAllTargetMCs();
35 llvm::InitializeAllAsmParsers();
36 llvm::InitializeAllDisassemblers();
37 llvm::InitializeAllTargets();
38 llvm::InitializeAllAsmPrinters();
41 void prepareElf() {
42 memcpy(ElfBuf, "\177ELF", 4);
43 ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
44 EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
45 EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
46 EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
47 MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
48 ObjFile = cantFail(ObjectFile::createObjectFile(Source));
51 void initializeBolt() {
52 BC = cantFail(BinaryContext::createBinaryContext(
53 ObjFile.get(), true, DWARFContext::create(*ObjFile.get())));
54 ASSERT_FALSE(!BC);
55 BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
56 createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(),
57 BC->MRI.get(), BC->STI.get())));
60 void testRegAliases(Triple::ArchType Arch, uint64_t Register,
61 uint64_t *Aliases, size_t Count,
62 bool OnlySmaller = false) {
63 if (GetParam() != Arch)
64 GTEST_SKIP();
66 const BitVector &BV = BC->MIB->getAliases(Register, OnlySmaller);
67 ASSERT_EQ(BV.count(), Count);
68 for (size_t I = 0; I < Count; ++I)
69 ASSERT_TRUE(BV[Aliases[I]]);
72 char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
73 std::unique_ptr<ObjectFile> ObjFile;
74 std::unique_ptr<BinaryContext> BC;
76 } // namespace
78 #ifdef AARCH64_AVAILABLE
80 INSTANTIATE_TEST_SUITE_P(AArch64, MCPlusBuilderTester,
81 ::testing::Values(Triple::aarch64));
83 TEST_P(MCPlusBuilderTester, AliasX0) {
84 uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0, AArch64::W0_W1,
85 AArch64::X0_X1, AArch64::X0_X1_X2_X3_X4_X5_X6_X7};
86 size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
87 testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count);
90 TEST_P(MCPlusBuilderTester, AliasSmallerX0) {
91 uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0};
92 size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
93 testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count, true);
96 #endif // AARCH64_AVAILABLE
98 #ifdef X86_AVAILABLE
100 INSTANTIATE_TEST_SUITE_P(X86, MCPlusBuilderTester,
101 ::testing::Values(Triple::x86_64));
103 TEST_P(MCPlusBuilderTester, AliasAX) {
104 uint64_t AliasesAX[] = {X86::RAX, X86::EAX, X86::AX, X86::AL, X86::AH};
105 size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
106 testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount);
109 TEST_P(MCPlusBuilderTester, AliasSmallerAX) {
110 uint64_t AliasesAX[] = {X86::AX, X86::AL, X86::AH};
111 size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
112 testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount, true);
115 TEST_P(MCPlusBuilderTester, ReplaceRegWithImm) {
116 if (GetParam() != Triple::x86_64)
117 GTEST_SKIP();
118 BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
119 std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
120 MCInst Inst; // cmpl %eax, %ebx
121 Inst.setOpcode(X86::CMP32rr);
122 Inst.addOperand(MCOperand::createReg(X86::EAX));
123 Inst.addOperand(MCOperand::createReg(X86::EBX));
124 auto II = BB->addInstruction(Inst);
125 bool Replaced = BC->MIB->replaceRegWithImm(*II, X86::EBX, 1);
126 ASSERT_TRUE(Replaced);
127 ASSERT_EQ(II->getOpcode(), X86::CMP32ri8);
128 ASSERT_EQ(II->getOperand(0).getReg(), X86::EAX);
129 ASSERT_EQ(II->getOperand(1).getImm(), 1);
132 #endif // X86_AVAILABLE
134 TEST_P(MCPlusBuilderTester, Annotation) {
135 MCInst Inst;
136 bool Success = BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
137 BC->Ctx.get());
138 ASSERT_TRUE(Success);
139 MCSymbol *LPSymbol = BC->Ctx->createNamedTempSymbol("LP");
140 uint64_t Value = INT32_MIN;
141 // Test encodeAnnotationImm using this indirect way
142 BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value));
143 // Round-trip encoding-decoding check for negative values
144 std::optional<MCPlus::MCLandingPad> EHInfo = BC->MIB->getEHInfo(Inst);
145 ASSERT_TRUE(EHInfo.has_value());
146 MCPlus::MCLandingPad LP = EHInfo.value();
147 uint64_t DecodedValue = LP.second;
148 ASSERT_EQ(Value, DecodedValue);
150 // Large int64 should trigger an out of range assertion
151 Value = 0x1FF'FFFF'FFFF'FFFFULL;
152 Inst.clear();
153 Success = BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
154 BC->Ctx.get());
155 ASSERT_TRUE(Success);
156 ASSERT_DEATH(BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value)),
157 "annotation value out of range");