Skip to content

Commit 790e325

Browse files
committed
[BOLT] Single-pass unittest for InsertNegateRAState
This commit creates a new directory: bolt/unittests/Passes, to be used by unittests that need to register and run passes with the BinaryFunctionPassManager. An example test is created for InsertNegateRAState pass. Actual tests will be added in followup commits.
1 parent 6ad31fe commit 790e325

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

bolt/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ endfunction()
77

88
add_subdirectory(Core)
99
add_subdirectory(Profile)
10+
add_subdirectory(Passes)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
set(LLVM_LINK_COMPONENTS
2+
DebugInfoDWARF
3+
Object
4+
MC
5+
${LLVM_TARGETS_TO_BUILD}
6+
)
7+
8+
add_bolt_unittest(PassTests
9+
InsertNegateRAState.cpp
10+
11+
DISABLE_LLVM_LINK_LLVM_DYLIB
12+
)
13+
14+
target_link_libraries(PassTests
15+
PRIVATE
16+
LLVMBOLTCore
17+
LLVMBOLTRewrite
18+
LLVMBOLTPasses
19+
LLVMBOLTProfile
20+
LLVMBOLTUtils
21+
)
22+
23+
foreach (tgt ${BOLT_TARGETS_TO_BUILD})
24+
include_directories(
25+
${LLVM_MAIN_SRC_DIR}/lib/Target/${tgt}
26+
${LLVM_BINARY_DIR}/lib/Target/${tgt}
27+
)
28+
string(TOUPPER "${tgt}" upper)
29+
target_compile_definitions(PassTests PRIVATE "${upper}_AVAILABLE")
30+
endforeach()
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
//===- bolt/unittest/Passes/InsertNegateRAState.cpp -----------------------===//
2+
//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifdef AARCH64_AVAILABLE
11+
#include "AArch64Subtarget.h"
12+
#include "MCTargetDesc/AArch64MCTargetDesc.h"
13+
#endif // AARCH64_AVAILABLE
14+
15+
#include "bolt/Core/BinaryBasicBlock.h"
16+
#include "bolt/Core/BinaryFunction.h"
17+
#include "bolt/Passes/InsertNegateRAStatePass.h"
18+
#include "bolt/Rewrite/BinaryPassManager.h"
19+
#include "bolt/Rewrite/RewriteInstance.h"
20+
#include "llvm/BinaryFormat/ELF.h"
21+
#include "llvm/MC/MCDwarf.h"
22+
#include "llvm/MC/MCInstBuilder.h"
23+
#include "llvm/Support/TargetSelect.h"
24+
#include "gtest/gtest.h"
25+
26+
using namespace llvm;
27+
using namespace llvm::object;
28+
using namespace llvm::ELF;
29+
using namespace bolt;
30+
31+
namespace {
32+
struct PassTester : public testing::TestWithParam<Triple::ArchType> {
33+
void SetUp() override {
34+
initalizeLLVM();
35+
prepareElf();
36+
initializeBolt();
37+
}
38+
39+
protected:
40+
void initalizeLLVM() {
41+
#define BOLT_TARGET(target) \
42+
LLVMInitialize##target##TargetInfo(); \
43+
LLVMInitialize##target##TargetMC(); \
44+
LLVMInitialize##target##AsmParser(); \
45+
LLVMInitialize##target##Disassembler(); \
46+
LLVMInitialize##target##Target(); \
47+
LLVMInitialize##target##AsmPrinter();
48+
49+
#include "bolt/Core/TargetConfig.def"
50+
}
51+
52+
#define PREPARE_FUNC(name) \
53+
constexpr uint64_t FunctionAddress = 0x1000; \
54+
BinaryFunction *BF = \
55+
BC->createBinaryFunction(name, *TextSection, FunctionAddress, \
56+
/*Size=*/0, /*SymbolSize=*/0, /*Alignment=*/16); \
57+
/* Make sure the pass runs on the BF.*/ \
58+
BF->updateState(BinaryFunction::State::CFG); \
59+
BF->setContainedNegateRAState(); \
60+
/* All tests need at least one BB. */ \
61+
BinaryBasicBlock *BB = BF->addBasicBlock(); \
62+
BF->addEntryPoint(*BB); \
63+
BB->setCFIState(0);
64+
65+
void prepareElf() {
66+
memcpy(ElfBuf, "\177ELF", 4);
67+
ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
68+
EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
69+
EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
70+
EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
71+
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
72+
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
73+
}
74+
void initializeBolt() {
75+
Relocation::Arch = ObjFile->makeTriple().getArch();
76+
BC = cantFail(BinaryContext::createBinaryContext(
77+
ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
78+
ObjFile->getFileName(), nullptr, true, DWARFContext::create(*ObjFile),
79+
{llvm::outs(), llvm::errs()}));
80+
ASSERT_FALSE(!BC);
81+
BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
82+
createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(),
83+
BC->MRI.get(), BC->STI.get())));
84+
85+
PassManager = std::make_unique<BinaryFunctionPassManager>(*BC);
86+
PassManager->registerPass(std::make_unique<InsertNegateRAState>());
87+
88+
TextSection = &BC->registerOrUpdateSection(
89+
".text", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR,
90+
/*Data=*/nullptr, /*Size=*/0,
91+
/*Alignment=*/16);
92+
}
93+
94+
std::vector<int> findCFIOffsets(BinaryFunction &BF) {
95+
std::vector<int> Locations;
96+
int Idx = 0;
97+
int InstSize = 4; // AArch64
98+
for (BinaryBasicBlock &BB : BF) {
99+
for (MCInst &Inst : BB) {
100+
if (BC->MIB->isCFI(Inst)) {
101+
const MCCFIInstruction *CFI = BF.getCFIFor(Inst);
102+
if (CFI->getOperation() == MCCFIInstruction::OpNegateRAState)
103+
Locations.push_back(Idx * InstSize);
104+
}
105+
Idx++;
106+
}
107+
}
108+
return Locations;
109+
}
110+
111+
char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
112+
std::unique_ptr<ObjectFile> ObjFile;
113+
std::unique_ptr<BinaryContext> BC;
114+
std::unique_ptr<BinaryFunctionPassManager> PassManager;
115+
BinarySection *TextSection;
116+
};
117+
} // namespace
118+
119+
TEST_P(PassTester, ExampleTest) {
120+
if (GetParam() != Triple::aarch64)
121+
GTEST_SKIP();
122+
123+
ASSERT_NE(TextSection, nullptr);
124+
125+
PREPARE_FUNC("ExampleFunction");
126+
127+
MCInst UnsignedInst = MCInstBuilder(AArch64::ADDSXri)
128+
.addReg(AArch64::X0)
129+
.addReg(AArch64::X0)
130+
.addImm(0)
131+
.addImm(0);
132+
BC->MIB->setRAState(UnsignedInst, false);
133+
BB->addInstruction(UnsignedInst);
134+
135+
MCInst SignedInst = MCInstBuilder(AArch64::ADDSXri)
136+
.addReg(AArch64::X0)
137+
.addReg(AArch64::X0)
138+
.addImm(1)
139+
.addImm(0);
140+
BC->MIB->setRAState(SignedInst, true);
141+
BB->addInstruction(SignedInst);
142+
143+
Error E = PassManager->runPasses();
144+
EXPECT_FALSE(E);
145+
146+
/* Expected layout of BF after the pass:
147+
148+
.LBB0 (3 instructions, align : 1)
149+
Entry Point
150+
CFI State : 0
151+
00000000: adds x0, x0, #0x0
152+
00000004: !CFI $0 ; OpNegateRAState
153+
00000004: adds x0, x0, #0x1
154+
CFI State: 0
155+
*/
156+
auto CFILoc = findCFIOffsets(*BF);
157+
EXPECT_EQ(CFILoc.size(), 1u);
158+
EXPECT_EQ(CFILoc[0], 4);
159+
}
160+
161+
#ifdef AARCH64_AVAILABLE
162+
INSTANTIATE_TEST_SUITE_P(AArch64, PassTester,
163+
::testing::Values(Triple::aarch64));
164+
#endif

0 commit comments

Comments
 (0)