Skip to content

[BOLT][NFC] Define AArch64 jump table types #132109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: users/aaupov/spr/main.boltnfc-define-aarch64-jump-table-types
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion bolt/include/bolt/Core/BinaryContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,18 @@ class BinaryContext {

/// Return size of an entry for the given jump table \p Type.
uint64_t getJumpTableEntrySize(JumpTable::JumpTableType Type) const {
return Type == JumpTable::JTT_PIC ? 4 : AsmInfo->getCodePointerSize();
switch (Type) {
case JumpTable::JTT_X86_64_PIC4:
return 4;
case JumpTable::JTT_X86_64_ABS:
return AsmInfo->getCodePointerSize();
case JumpTable::JTT_AARCH64_REL1:
return 1;
case JumpTable::JTT_AARCH64_REL2:
return 2;
case JumpTable::JTT_AARCH64_REL4:
return 4;
}
}

/// Return JumpTable containing a given \p Address.
Expand Down
28 changes: 26 additions & 2 deletions bolt/include/bolt/Core/JumpTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,34 @@ class JumpTable : public BinaryData {

public:
enum JumpTableType : char {
JTT_NORMAL,
JTT_PIC,
JTT_X86_64_FIRST = 0,
JTT_X86_64_ABS = JTT_X86_64_FIRST,
JTT_X86_64_PIC4,
JTT_X86_64_LAST = JTT_X86_64_PIC4,
JTT_AARCH64_FIRST,
JTT_AARCH64_REL1 = JTT_AARCH64_FIRST,
JTT_AARCH64_REL2,
JTT_AARCH64_REL4,
JTT_AARCH64_LAST = JTT_AARCH64_REL4
};

static StringRef getTypeStr(JumpTableType Type) {
switch (Type) {
case JTT_X86_64_ABS:
return "X86_64_ABS";
case JTT_X86_64_PIC4:
return "X86_64_PIC4";
case JTT_AARCH64_REL1:
return "AARCH64_REL1";
case JTT_AARCH64_REL2:
return "AARCH64_REL2";
case JTT_AARCH64_REL4:
return "AARCH64_REL4";
}
}

const StringRef getTypeStr() { return getTypeStr(Type); }

/// Branch statistics for jump table entries.
struct JumpInfo {
uint64_t Mispreds{0};
Expand Down
38 changes: 21 additions & 17 deletions bolt/lib/Core/BinaryContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ BinaryContext::handleAddressRef(uint64_t Address, BinaryFunction &BF,
const MemoryContentsType MemType = analyzeMemoryAt(Address, BF);
if (MemType == MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE && IsPCRel) {
const MCSymbol *Symbol =
getOrCreateJumpTable(BF, Address, JumpTable::JTT_PIC);
getOrCreateJumpTable(BF, Address, JumpTable::JTT_X86_64_PIC4);

return std::make_pair(Symbol, 0);
}
Expand Down Expand Up @@ -540,10 +540,10 @@ MemoryContentsType BinaryContext::analyzeMemoryAt(uint64_t Address,

// Start with checking for PIC jump table. We expect non-PIC jump tables
// to have high 32 bits set to 0.
if (analyzeJumpTable(Address, JumpTable::JTT_PIC, BF))
if (analyzeJumpTable(Address, JumpTable::JTT_X86_64_PIC4, BF))
return MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE;

if (analyzeJumpTable(Address, JumpTable::JTT_NORMAL, BF))
if (analyzeJumpTable(Address, JumpTable::JTT_X86_64_ABS, BF))
return MemoryContentsType::POSSIBLE_JUMP_TABLE;

return MemoryContentsType::UNKNOWN;
Expand Down Expand Up @@ -594,37 +594,41 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
if (NextJTAddress)
UpperBound = std::min(NextJTAddress, UpperBound);

LLVM_DEBUG({
using JTT = JumpTable::JumpTableType;
dbgs() << formatv("BOLT-DEBUG: analyzeJumpTable @{0:x} in {1}, JTT={2}\n",
Address, BF.getPrintName(),
Type == JTT::JTT_PIC ? "PIC" : "Normal");
});
LLVM_DEBUG(
dbgs() << formatv("BOLT-DEBUG: analyzeJumpTable @{0:x} in {1}, JTT={2}\n",
Address, BF, JumpTable::getTypeStr(Type)));
const uint64_t EntrySize = getJumpTableEntrySize(Type);
for (uint64_t EntryAddress = Address; EntryAddress <= UpperBound - EntrySize;
EntryAddress += EntrySize) {
LLVM_DEBUG(dbgs() << " * Checking 0x" << Twine::utohexstr(EntryAddress)
<< " -> ");
// Check if there's a proper relocation against the jump table entry.
if (HasRelocations) {
if (Type == JumpTable::JTT_PIC &&
if (Type == JumpTable::JTT_X86_64_PIC4 &&
!DataPCRelocations.count(EntryAddress)) {
LLVM_DEBUG(
dbgs() << "FAIL: JTT_PIC table, no relocation for this address\n");
break;
}
if (Type == JumpTable::JTT_NORMAL && !getRelocationAt(EntryAddress)) {
if (Type == JumpTable::JTT_X86_64_ABS && !getRelocationAt(EntryAddress)) {
LLVM_DEBUG(
dbgs()
<< "FAIL: JTT_NORMAL table, no relocation for this address\n");
break;
}
}

const uint64_t Value =
(Type == JumpTable::JTT_PIC)
? Address + *getSignedValueAtAddress(EntryAddress, EntrySize)
: *getPointerAtAddress(EntryAddress);
uint64_t Value = 0;
switch (Type) {
case JumpTable::JTT_X86_64_PIC4:
Value = Address + *getSignedValueAtAddress(EntryAddress, EntrySize);
break;
case JumpTable::JTT_X86_64_ABS:
Value = *getPointerAtAddress(EntryAddress);
break;
default:
llvm_unreachable("Unhandled jump table type");
}

// __builtin_unreachable() case.
if (Value == UnreachableAddress) {
Expand Down Expand Up @@ -679,7 +683,7 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,

// Trim direct/normal jump table to exclude trailing unreachable entries that
// can collide with a function address.
if (Type == JumpTable::JTT_NORMAL && EntriesAsAddress &&
if (Type == JumpTable::JTT_X86_64_ABS && EntriesAsAddress &&
TrimmedSize != EntriesAsAddress->size() &&
getBinaryFunctionAtAddress(UnreachableAddress))
EntriesAsAddress->resize(TrimmedSize);
Expand Down Expand Up @@ -736,7 +740,7 @@ void BinaryContext::populateJumpTables() {

// In strict mode, erase PC-relative relocation record. Later we check that
// all such records are erased and thus have been accounted for.
if (opts::StrictMode && JT->Type == JumpTable::JTT_PIC) {
if (opts::StrictMode && JT->Type == JumpTable::JTT_X86_64_PIC4) {
for (uint64_t Address = JT->getAddress();
Address < JT->getAddress() + JT->getSize();
Address += JT->EntrySize) {
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Core/BinaryEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ void BinaryEmitter::emitJumpTable(const JumpTable &JT, MCSection *HotSection,
}
LastLabel = LI->second;
}
if (JT.Type == JumpTable::JTT_NORMAL) {
if (JT.Type == JumpTable::JTT_X86_64_ABS) {
Streamer.emitSymbolValue(Entry, JT.OutputEntrySize);
} else { // JTT_PIC
const MCSymbolRefExpr *JTExpr =
Expand Down
17 changes: 10 additions & 7 deletions bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
"Invalid memory instruction");
const MCExpr *FixedEntryDispExpr = FixedEntryDispOperand->getExpr();
const uint64_t EntryAddress = getExprValue(FixedEntryDispExpr);
uint64_t EntrySize = BC.getJumpTableEntrySize(JumpTable::JTT_PIC);
uint64_t EntrySize = BC.getJumpTableEntrySize(JumpTable::JTT_X86_64_PIC4);
ErrorOr<int64_t> Value =
BC.getSignedValueAtAddress(EntryAddress, EntrySize);
if (!Value)
Expand Down Expand Up @@ -982,12 +982,14 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
MemoryContentsType MemType;
if (JumpTable *JT = BC.getJumpTableContainingAddress(ArrayStart)) {
switch (JT->Type) {
case JumpTable::JTT_NORMAL:
case JumpTable::JTT_X86_64_ABS:
MemType = MemoryContentsType::POSSIBLE_JUMP_TABLE;
break;
case JumpTable::JTT_PIC:
case JumpTable::JTT_X86_64_PIC4:
MemType = MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE;
break;
default:
llvm_unreachable("Unhandled jump table type");
}
} else {
MemType = BC.analyzeMemoryAt(ArrayStart, *this);
Expand All @@ -998,7 +1000,7 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
if (BranchType == IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE) {
if (MemType != MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE)
return IndirectBranchType::UNKNOWN;
JTType = JumpTable::JTT_PIC;
JTType = JumpTable::JTT_X86_64_PIC4;
} else {
if (MemType == MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE)
return IndirectBranchType::UNKNOWN;
Expand All @@ -1007,7 +1009,7 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
return IndirectBranchType::POSSIBLE_TAIL_CALL;

BranchType = IndirectBranchType::POSSIBLE_JUMP_TABLE;
JTType = JumpTable::JTT_NORMAL;
JTType = JumpTable::JTT_X86_64_ABS;
}

// Convert the instruction into jump table branch.
Expand Down Expand Up @@ -1779,7 +1781,8 @@ void BinaryFunction::postProcessJumpTables() {
// Create labels for all entries.
for (auto &JTI : JumpTables) {
JumpTable &JT = *JTI.second;
if (JT.Type == JumpTable::JTT_PIC && opts::JumpTables == JTS_BASIC) {
if (JT.Type == JumpTable::JTT_X86_64_PIC4 &&
opts::JumpTables == JTS_BASIC) {
opts::JumpTables = JTS_MOVE;
BC.outs() << "BOLT-INFO: forcing -jump-tables=move as PIC jump table was "
"detected in function "
Expand Down Expand Up @@ -1974,7 +1977,7 @@ bool BinaryFunction::postProcessIndirectBranches(
BC.MIB->unsetJumpTable(Instr);

JumpTable *JT = BC.getJumpTableContainingAddress(LastJT);
if (JT->Type == JumpTable::JTT_NORMAL) {
if (JT->Type == JumpTable::JTT_X86_64_ABS) {
// Invalidating the jump table may also invalidate other jump table
// boundaries. Until we have/need a support for this, mark the
// function as non-simple.
Expand Down
6 changes: 3 additions & 3 deletions bolt/lib/Core/JumpTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ void bolt::JumpTable::updateOriginal() {
uint64_t EntryOffset = BaseOffset;
for (MCSymbol *Entry : Entries) {
const uint64_t RelType =
Type == JTT_NORMAL ? ELF::R_X86_64_64 : ELF::R_X86_64_PC32;
Type == JTT_X86_64_ABS ? ELF::R_X86_64_64 : ELF::R_X86_64_PC32;
const uint64_t RelAddend =
Type == JTT_NORMAL ? 0 : EntryOffset - BaseOffset;
Type == JTT_X86_64_ABS ? 0 : EntryOffset - BaseOffset;
// Replace existing relocation with the new one to allow any modifications
// to the original jump table.
if (BC.HasRelocations)
Expand All @@ -99,7 +99,7 @@ void bolt::JumpTable::updateOriginal() {

void bolt::JumpTable::print(raw_ostream &OS) const {
uint64_t Offset = 0;
if (Type == JTT_PIC)
if (Type == JTT_X86_64_PIC4)
OS << "PIC ";
ListSeparator LS;

Expand Down
4 changes: 2 additions & 2 deletions bolt/lib/Passes/IndirectCallPromotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ IndirectCallPromotion::getCallTargets(BinaryBasicBlock &BB,

if (const JumpTable *JT = BF.getJumpTable(Inst)) {
// Don't support PIC jump tables for now
if (!opts::ICPJumpTablesByTarget && JT->Type == JumpTable::JTT_PIC)
if (!opts::ICPJumpTablesByTarget && JT->Type == JumpTable::JTT_X86_64_PIC4)
return Targets;
const Location From(BF.getSymbol());
const std::pair<size_t, size_t> Range =
Expand All @@ -256,7 +256,7 @@ IndirectCallPromotion::getCallTargets(BinaryBasicBlock &BB,
const JumpTable::JumpInfo *JI =
JT->Counts.empty() ? &DefaultJI : &JT->Counts[Range.first];
const size_t JIAdj = JT->Counts.empty() ? 0 : 1;
assert(JT->Type == JumpTable::JTT_PIC ||
assert(JT->Type == JumpTable::JTT_X86_64_PIC4 ||
JT->EntrySize == BC.AsmInfo->getCodePointerSize());
for (size_t I = Range.first; I < Range.second; ++I, JI += JIAdj) {
MCSymbol *Entry = JT->Entries[I];
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Passes/JTFootprintReduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ bool JTFootprintReduction::tryOptimizePIC(BinaryContext &BC,

JumpTable->OutputEntrySize = 4;
// DePICify
JumpTable->Type = JumpTable::JTT_NORMAL;
JumpTable->Type = JumpTable::JTT_X86_64_ABS;

BB.replaceInstruction(Inst, NewFrag.begin(), NewFrag.end());
return true;
Expand Down