diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp --- a/bolt/lib/Core/MCPlusBuilder.cpp +++ b/bolt/lib/Core/MCPlusBuilder.cpp @@ -443,49 +443,46 @@ // AliasMap caches a mapping of registers to the set of registers that // alias (are sub or superregs of itself, including itself). static std::vector AliasMap; - static std::vector SuperReg; + static std::vector SmallerAliasMap; if (AliasMap.size() > 0) { if (OnlySmaller) - return AliasMap[Reg]; - return AliasMap[SuperReg[Reg]]; + return SmallerAliasMap[Reg]; + return AliasMap[Reg]; } + // Build alias map for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) { BitVector BV(RegInfo->getNumRegs(), false); BV.set(I); - AliasMap.emplace_back(std::move(BV)); - SuperReg.emplace_back(I); + AliasMap.emplace_back(BV); + SmallerAliasMap.emplace_back(BV); + } + + // Cache all aliases for each register + for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I != E; ++I) { + for (MCRegAliasIterator AI(I, RegInfo, true); AI.isValid(); ++AI) + AliasMap[I].set(*AI); } + + // Propagate smaller alias info upwards. Skip reg 0 (mapped to NoRegister) std::queue Worklist; - // Propagate alias info upwards. Skip reg 0 (mapped to NoRegister) for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I) Worklist.push(I); while (!Worklist.empty()) { MCPhysReg I = Worklist.front(); Worklist.pop(); for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI) - AliasMap[I] |= AliasMap[*SI]; + SmallerAliasMap[I] |= SmallerAliasMap[*SI]; for (MCSuperRegIterator SI(I, RegInfo); SI.isValid(); ++SI) Worklist.push(*SI); } - // Propagate parent reg downwards - for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I) - Worklist.push(I); - while (!Worklist.empty()) { - MCPhysReg I = Worklist.front(); - Worklist.pop(); - for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI) { - SuperReg[*SI] = SuperReg[I]; - Worklist.push(*SI); - } - } LLVM_DEBUG({ dbgs() << "Dumping reg alias table:\n"; for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) { dbgs() << "Reg " << I << ": "; - const BitVector &BV = AliasMap[SuperReg[I]]; + const BitVector &BV = AliasMap[I]; int Idx = BV.find_first(); while (Idx != -1) { dbgs() << Idx << " "; @@ -496,8 +493,8 @@ }); if (OnlySmaller) - return AliasMap[Reg]; - return AliasMap[SuperReg[Reg]]; + return SmallerAliasMap[Reg]; + return AliasMap[Reg]; } uint8_t MCPlusBuilder::getRegSize(MCPhysReg Reg) const { diff --git a/bolt/unittests/CMakeLists.txt b/bolt/unittests/CMakeLists.txt --- a/bolt/unittests/CMakeLists.txt +++ b/bolt/unittests/CMakeLists.txt @@ -4,3 +4,5 @@ function(add_bolt_unittest test_dirname) add_unittest(BoltUnitTests ${test_dirname} ${ARGN}) endfunction() + +add_subdirectory(Core) diff --git a/bolt/unittests/Core/CMakeLists.txt b/bolt/unittests/Core/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/bolt/unittests/Core/CMakeLists.txt @@ -0,0 +1,27 @@ +set(LLVM_LINK_COMPONENTS + BOLTRewrite + ) + +add_bolt_unittest(CoreTests + MCPlusBuilder.cpp + ) + +string(FIND "${LLVM_TARGETS_TO_BUILD}" "AArch64" POSITION) +if (NOT ${POSITION} EQUAL -1) + include_directories( + ${CMAKE_SOURCE_DIR}/lib/Target/AArch64 + ${CMAKE_BINARY_DIR}/lib/Target/AArch64 + ) + + target_compile_definitions(CoreTests PRIVATE AARCH64_AVAILABLE) +endif() + +string(FIND "${LLVM_TARGETS_TO_BUILD}" "X86" POSITION) +if (NOT ${POSITION} EQUAL -1) + include_directories( + ${LLVM_MAIN_SRC_DIR}/lib/Target/X86 + ${LLVM_BINARY_DIR}/lib/Target/X86 + ) + + target_compile_definitions(CoreTests PRIVATE X86_AVAILABLE) +endif() diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp new file mode 100644 --- /dev/null +++ b/bolt/unittests/Core/MCPlusBuilder.cpp @@ -0,0 +1,112 @@ +#ifdef AARCH64_AVAILABLE +#include "AArch64Subtarget.h" +#endif // AARCH64_AVAILABLE + +#ifdef X86_AVAILABLE +#include "X86Subtarget.h" +#endif // X86_AVAILABLE + +#include "bolt/Rewrite/RewriteInstance.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; +using namespace bolt; + +namespace { +struct MCPlusBuilderTester : public testing::TestWithParam { + void SetUp() override { + initalizeLLVM(); + prepareElf(); + initializeBolt(); + } + +protected: + void initalizeLLVM() { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllDisassemblers(); + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + } + + void prepareElf() { + memcpy(ElfBuf, "\177ELF", 4); + ELF64LE::Ehdr *EHdr = reinterpret_cast(ElfBuf); + EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64; + EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB; + EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64; + MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF"); + ObjFile = cantFail(ObjectFile::createObjectFile(Source)); + } + + void initializeBolt() { + BC = BinaryContext::createBinaryContext( + ObjFile.get(), true, DWARFContext::create(*ObjFile.get())); + ASSERT_FALSE(!BC); + BC->initializeTarget(std::unique_ptr(createMCPlusBuilder( + GetParam(), BC->MIA.get(), BC->MII.get(), BC->MRI.get()))); + } + + void testRegAliases(Triple::ArchType Arch, uint64_t Register, + uint64_t *Aliases, size_t Count, + bool OnlySmaller = false) { + if (GetParam() != Arch) + GTEST_SKIP(); + + const BitVector &BV = BC->MIB->getAliases(Register, OnlySmaller); + ASSERT_EQ(BV.count(), Count); + for (size_t I = 0; I < Count; ++I) + ASSERT_TRUE(BV[Aliases[I]]); + } + + char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {}; + std::unique_ptr ObjFile; + std::unique_ptr BC; +}; +} // namespace + +#ifdef AARCH64_AVAILABLE + +INSTANTIATE_TEST_SUITE_P(AArch64, MCPlusBuilderTester, + ::testing::Values(Triple::aarch64)); + +TEST_P(MCPlusBuilderTester, AliasX0) { + uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0, AArch64::W0_W1, + AArch64::X0_X1, AArch64::X0_X1_X2_X3_X4_X5_X6_X7}; + size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0); + testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count); +} + +TEST_P(MCPlusBuilderTester, AliasSmallerX0) { + uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0}; + size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0); + testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count, true); +} + +#endif // AARCH64_AVAILABLE + +#ifdef X86_AVAILABLE + +INSTANTIATE_TEST_SUITE_P(X86, MCPlusBuilderTester, + ::testing::Values(Triple::x86_64)); + +TEST_P(MCPlusBuilderTester, AliasAX) { + uint64_t AliasesAX[] = {X86::RAX, X86::EAX, X86::AX, X86::AL, X86::AH}; + size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX); + testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount); +} + +TEST_P(MCPlusBuilderTester, AliasSmallerAX) { + uint64_t AliasesAX[] = {X86::AX, X86::AL, X86::AH}; + size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX); + testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount, true); +} + +#endif // X86_AVAILABLE