Skip to content

Commit e900f05

Browse files
committed
[BOLT] Fix AARCH64 registers aliasing
The aarch64 platform has special registers like X0_X1_X2_X3_X4_X5_X6_X7. Using the downwards propagation this register will become a super register for all X0..X7 and its super registers which is not right. This patch replaces the downwards propagation with caching all the aliases using MCRegAliasIterator. Vladislav Khmelevsky, Advanced Software Technology Lab, Huawei Reviewed By: maksfb Differential Revision: https://reviews.llvm.org/D117394
1 parent 11c2ef5 commit e900f05

File tree

4 files changed

+159
-21
lines changed

4 files changed

+159
-21
lines changed

bolt/lib/Core/MCPlusBuilder.cpp

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -443,49 +443,46 @@ const BitVector &MCPlusBuilder::getAliases(MCPhysReg Reg,
443443
// AliasMap caches a mapping of registers to the set of registers that
444444
// alias (are sub or superregs of itself, including itself).
445445
static std::vector<BitVector> AliasMap;
446-
static std::vector<MCPhysReg> SuperReg;
446+
static std::vector<BitVector> SmallerAliasMap;
447447

448448
if (AliasMap.size() > 0) {
449449
if (OnlySmaller)
450-
return AliasMap[Reg];
451-
return AliasMap[SuperReg[Reg]];
450+
return SmallerAliasMap[Reg];
451+
return AliasMap[Reg];
452452
}
453+
453454
// Build alias map
454455
for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) {
455456
BitVector BV(RegInfo->getNumRegs(), false);
456457
BV.set(I);
457-
AliasMap.emplace_back(std::move(BV));
458-
SuperReg.emplace_back(I);
458+
AliasMap.emplace_back(BV);
459+
SmallerAliasMap.emplace_back(BV);
460+
}
461+
462+
// Cache all aliases for each register
463+
for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I != E; ++I) {
464+
for (MCRegAliasIterator AI(I, RegInfo, true); AI.isValid(); ++AI)
465+
AliasMap[I].set(*AI);
459466
}
467+
468+
// Propagate smaller alias info upwards. Skip reg 0 (mapped to NoRegister)
460469
std::queue<MCPhysReg> Worklist;
461-
// Propagate alias info upwards. Skip reg 0 (mapped to NoRegister)
462470
for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I)
463471
Worklist.push(I);
464472
while (!Worklist.empty()) {
465473
MCPhysReg I = Worklist.front();
466474
Worklist.pop();
467475
for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI)
468-
AliasMap[I] |= AliasMap[*SI];
476+
SmallerAliasMap[I] |= SmallerAliasMap[*SI];
469477
for (MCSuperRegIterator SI(I, RegInfo); SI.isValid(); ++SI)
470478
Worklist.push(*SI);
471479
}
472-
// Propagate parent reg downwards
473-
for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I)
474-
Worklist.push(I);
475-
while (!Worklist.empty()) {
476-
MCPhysReg I = Worklist.front();
477-
Worklist.pop();
478-
for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI) {
479-
SuperReg[*SI] = SuperReg[I];
480-
Worklist.push(*SI);
481-
}
482-
}
483480

484481
LLVM_DEBUG({
485482
dbgs() << "Dumping reg alias table:\n";
486483
for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) {
487484
dbgs() << "Reg " << I << ": ";
488-
const BitVector &BV = AliasMap[SuperReg[I]];
485+
const BitVector &BV = AliasMap[I];
489486
int Idx = BV.find_first();
490487
while (Idx != -1) {
491488
dbgs() << Idx << " ";
@@ -496,8 +493,8 @@ const BitVector &MCPlusBuilder::getAliases(MCPhysReg Reg,
496493
});
497494

498495
if (OnlySmaller)
499-
return AliasMap[Reg];
500-
return AliasMap[SuperReg[Reg]];
496+
return SmallerAliasMap[Reg];
497+
return AliasMap[Reg];
501498
}
502499

503500
uint8_t MCPlusBuilder::getRegSize(MCPhysReg Reg) const {

bolt/unittests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ set_target_properties(BoltUnitTests PROPERTIES FOLDER "BOLT tests")
44
function(add_bolt_unittest test_dirname)
55
add_unittest(BoltUnitTests ${test_dirname} ${ARGN})
66
endfunction()
7+
8+
add_subdirectory(Core)

bolt/unittests/Core/CMakeLists.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
set(LLVM_LINK_COMPONENTS
2+
BOLTRewrite
3+
)
4+
5+
add_bolt_unittest(CoreTests
6+
MCPlusBuilder.cpp
7+
)
8+
9+
string(FIND "${LLVM_TARGETS_TO_BUILD}" "AArch64" POSITION)
10+
if (NOT ${POSITION} EQUAL -1)
11+
include_directories(
12+
${CMAKE_SOURCE_DIR}/lib/Target/AArch64
13+
${CMAKE_BINARY_DIR}/lib/Target/AArch64
14+
)
15+
16+
target_compile_definitions(CoreTests PRIVATE AARCH64_AVAILABLE)
17+
endif()
18+
19+
string(FIND "${LLVM_TARGETS_TO_BUILD}" "X86" POSITION)
20+
if (NOT ${POSITION} EQUAL -1)
21+
include_directories(
22+
${LLVM_MAIN_SRC_DIR}/lib/Target/X86
23+
${LLVM_BINARY_DIR}/lib/Target/X86
24+
)
25+
26+
target_compile_definitions(CoreTests PRIVATE X86_AVAILABLE)
27+
endif()

bolt/unittests/Core/MCPlusBuilder.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#ifdef AARCH64_AVAILABLE
2+
#include "AArch64Subtarget.h"
3+
#endif // AARCH64_AVAILABLE
4+
5+
#ifdef X86_AVAILABLE
6+
#include "X86Subtarget.h"
7+
#endif // X86_AVAILABLE
8+
9+
#include "bolt/Rewrite/RewriteInstance.h"
10+
#include "llvm/BinaryFormat/ELF.h"
11+
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
12+
#include "llvm/Object/ELFObjectFile.h"
13+
#include "llvm/Support/TargetSelect.h"
14+
#include "gtest/gtest.h"
15+
16+
using namespace llvm;
17+
using namespace llvm::object;
18+
using namespace llvm::ELF;
19+
using namespace bolt;
20+
21+
namespace {
22+
struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
23+
void SetUp() override {
24+
initalizeLLVM();
25+
prepareElf();
26+
initializeBolt();
27+
}
28+
29+
protected:
30+
void initalizeLLVM() {
31+
llvm::InitializeAllTargetInfos();
32+
llvm::InitializeAllTargetMCs();
33+
llvm::InitializeAllAsmParsers();
34+
llvm::InitializeAllDisassemblers();
35+
llvm::InitializeAllTargets();
36+
llvm::InitializeAllAsmPrinters();
37+
}
38+
39+
void prepareElf() {
40+
memcpy(ElfBuf, "\177ELF", 4);
41+
ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
42+
EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
43+
EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
44+
EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
45+
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
46+
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
47+
}
48+
49+
void initializeBolt() {
50+
BC = BinaryContext::createBinaryContext(
51+
ObjFile.get(), true, DWARFContext::create(*ObjFile.get()));
52+
ASSERT_FALSE(!BC);
53+
BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(createMCPlusBuilder(
54+
GetParam(), BC->MIA.get(), BC->MII.get(), BC->MRI.get())));
55+
}
56+
57+
void testRegAliases(Triple::ArchType Arch, uint64_t Register,
58+
uint64_t *Aliases, size_t Count,
59+
bool OnlySmaller = false) {
60+
if (GetParam() != Arch)
61+
GTEST_SKIP();
62+
63+
const BitVector &BV = BC->MIB->getAliases(Register, OnlySmaller);
64+
ASSERT_EQ(BV.count(), Count);
65+
for (size_t I = 0; I < Count; ++I)
66+
ASSERT_TRUE(BV[Aliases[I]]);
67+
}
68+
69+
char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
70+
std::unique_ptr<ObjectFile> ObjFile;
71+
std::unique_ptr<BinaryContext> BC;
72+
};
73+
} // namespace
74+
75+
#ifdef AARCH64_AVAILABLE
76+
77+
INSTANTIATE_TEST_SUITE_P(AArch64, MCPlusBuilderTester,
78+
::testing::Values(Triple::aarch64));
79+
80+
TEST_P(MCPlusBuilderTester, AliasX0) {
81+
uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0, AArch64::W0_W1,
82+
AArch64::X0_X1, AArch64::X0_X1_X2_X3_X4_X5_X6_X7};
83+
size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
84+
testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count);
85+
}
86+
87+
TEST_P(MCPlusBuilderTester, AliasSmallerX0) {
88+
uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0};
89+
size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
90+
testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count, true);
91+
}
92+
93+
#endif // AARCH64_AVAILABLE
94+
95+
#ifdef X86_AVAILABLE
96+
97+
INSTANTIATE_TEST_SUITE_P(X86, MCPlusBuilderTester,
98+
::testing::Values(Triple::x86_64));
99+
100+
TEST_P(MCPlusBuilderTester, AliasAX) {
101+
uint64_t AliasesAX[] = {X86::RAX, X86::EAX, X86::AX, X86::AL, X86::AH};
102+
size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
103+
testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount);
104+
}
105+
106+
TEST_P(MCPlusBuilderTester, AliasSmallerAX) {
107+
uint64_t AliasesAX[] = {X86::AX, X86::AL, X86::AH};
108+
size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
109+
testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount, true);
110+
}
111+
112+
#endif // X86_AVAILABLE

0 commit comments

Comments
 (0)