Skip to content

Commit 18d5108

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.4
2 parents cde2ea3 + 3d2d135 commit 18d5108

38 files changed

+1114
-157
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,12 @@ class BinaryContext {
230230
/// Functions injected by BOLT
231231
std::vector<BinaryFunction *> InjectedBinaryFunctions;
232232

233+
/// Thunk functions.
234+
std::vector<BinaryFunction *> ThunkBinaryFunctions;
235+
236+
/// Function that precedes thunks in the binary.
237+
const BinaryFunction *ThunkLocation{nullptr};
238+
233239
/// Jump tables for all functions mapped by address.
234240
std::map<uint64_t, JumpTable *> JumpTables;
235241

@@ -435,7 +441,18 @@ class BinaryContext {
435441

436442
/// Return size of an entry for the given jump table \p Type.
437443
uint64_t getJumpTableEntrySize(JumpTable::JumpTableType Type) const {
438-
return Type == JumpTable::JTT_PIC ? 4 : AsmInfo->getCodePointerSize();
444+
switch (Type) {
445+
case JumpTable::JTT_X86_64_PIC4:
446+
return 4;
447+
case JumpTable::JTT_X86_64_ABS:
448+
return AsmInfo->getCodePointerSize();
449+
case JumpTable::JTT_AARCH64_REL1:
450+
return 1;
451+
case JumpTable::JTT_AARCH64_REL2:
452+
return 2;
453+
case JumpTable::JTT_AARCH64_REL4:
454+
return 4;
455+
}
439456
}
440457

441458
/// Return JumpTable containing a given \p Address.
@@ -553,6 +570,16 @@ class BinaryContext {
553570
return InjectedBinaryFunctions;
554571
}
555572

573+
BinaryFunction *createThunkBinaryFunction(const std::string &Name);
574+
575+
std::vector<BinaryFunction *> &getThunkBinaryFunctions() {
576+
return ThunkBinaryFunctions;
577+
}
578+
579+
const BinaryFunction *getThunkLocation() const { return ThunkLocation; }
580+
581+
void setThunkLocation(const BinaryFunction *BF) { ThunkLocation = BF; }
582+
556583
/// Return vector with all functions, i.e. include functions from the input
557584
/// binary and functions created by BOLT.
558585
std::vector<BinaryFunction *> getAllBinaryFunctions();
@@ -574,14 +601,13 @@ class BinaryContext {
574601
/// If \p NextJTAddress is different from zero, it is used as an upper
575602
/// bound for jump table memory layout.
576603
///
577-
/// Optionally, populate \p Address from jump table entries. The entries
578-
/// could be partially populated if the jump table detection fails.
604+
/// If \p JT is set, populate it with jump table entries. The entries could be
605+
/// partially populated if the jump table detection fails.
579606
bool analyzeJumpTable(const uint64_t Address,
580607
const JumpTable::JumpTableType Type,
581608
const BinaryFunction &BF,
582609
const uint64_t NextJTAddress = 0,
583-
JumpTable::AddressesType *EntriesAsAddress = nullptr,
584-
bool *HasEntryInFragment = nullptr) const;
610+
JumpTable *JT = nullptr) const;
585611

586612
/// After jump table locations are established, this function will populate
587613
/// their EntriesAsAddress based on memory contents.
@@ -1372,6 +1398,10 @@ class BinaryContext {
13721398
uint64_t
13731399
computeInstructionSize(const MCInst &Inst,
13741400
const MCCodeEmitter *Emitter = nullptr) const {
1401+
// FIXME: hack for faster size computation on aarch64.
1402+
if (isAArch64())
1403+
return MIB->isPseudo(Inst) ? 0 : 4;
1404+
13751405
if (std::optional<uint32_t> Size = MIB->getSize(Inst))
13761406
return *Size;
13771407

bolt/include/bolt/Core/BinaryFunction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ class BinaryFunction {
363363
/// True if the function should not have an associated symbol table entry.
364364
bool IsAnonymous{false};
365365

366+
/// True if the function is used for remapping hot text and shall not be
367+
/// placed on a huge page.
368+
bool IsHotTextMover{false};
369+
366370
/// Name for the section this function code should reside in.
367371
std::string CodeSectionName;
368372

@@ -1385,6 +1389,8 @@ class BinaryFunction {
13851389
/// Return true if the function uses ORC format for stack unwinding.
13861390
bool hasORC() const { return HasORC; }
13871391

1392+
bool isHotTextMover() const { return IsHotTextMover; }
1393+
13881394
const JumpTable *getJumpTable(const MCInst &Inst) const {
13891395
const uint64_t Address = BC.MIB->getJumpTable(Inst);
13901396
return getJumpTableContainingAddress(Address);
@@ -1735,6 +1741,8 @@ class BinaryFunction {
17351741
/// Mark function that should not be emitted.
17361742
void setIgnored();
17371743

1744+
void setHotTextMover(bool V) { IsHotTextMover = V; }
1745+
17381746
void setHasIndirectTargetToSplitFragment(bool V) {
17391747
HasIndirectTargetToSplitFragment = V;
17401748
}

bolt/include/bolt/Core/JumpTable.h

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "bolt/Core/BinaryData.h"
1818
#include <map>
19+
#include <variant>
1920
#include <vector>
2021

2122
namespace llvm {
@@ -40,17 +41,42 @@ class BinaryFunction;
4041
/// a different label at a different offset in this jump table.
4142
class JumpTable : public BinaryData {
4243
friend class BinaryContext;
44+
friend class JumpTableInfoReader;
4345

4446
JumpTable() = delete;
4547
JumpTable(const JumpTable &) = delete;
4648
JumpTable &operator=(const JumpTable &) = delete;
4749

4850
public:
4951
enum JumpTableType : char {
50-
JTT_NORMAL,
51-
JTT_PIC,
52+
JTT_X86_64_FIRST = 0,
53+
JTT_X86_64_ABS = JTT_X86_64_FIRST,
54+
JTT_X86_64_PIC4,
55+
JTT_X86_64_LAST = JTT_X86_64_PIC4,
56+
JTT_AARCH64_FIRST,
57+
JTT_AARCH64_REL1 = JTT_AARCH64_FIRST,
58+
JTT_AARCH64_REL2,
59+
JTT_AARCH64_REL4,
60+
JTT_AARCH64_LAST = JTT_AARCH64_REL4
5261
};
5362

63+
static StringRef getTypeStr(JumpTableType Type) {
64+
switch (Type) {
65+
case JTT_X86_64_ABS:
66+
return "X86_64_ABS";
67+
case JTT_X86_64_PIC4:
68+
return "X86_64_PIC4";
69+
case JTT_AARCH64_REL1:
70+
return "AARCH64_REL1";
71+
case JTT_AARCH64_REL2:
72+
return "AARCH64_REL2";
73+
case JTT_AARCH64_REL4:
74+
return "AARCH64_REL4";
75+
}
76+
}
77+
78+
const StringRef getTypeStr() { return getTypeStr(Type); }
79+
5480
/// Branch statistics for jump table entries.
5581
struct JumpInfo {
5682
uint64_t Mispreds{0};
@@ -92,6 +118,16 @@ class JumpTable : public BinaryData {
92118
/// BinaryFunction this jump tables belongs to.
93119
SmallVector<BinaryFunction *, 1> Parents;
94120

121+
///
122+
/// AArch64-specific fields
123+
///
124+
125+
/// Entries are offsets relative to an arbitrary function location.
126+
std::variant<uint64_t, MCSymbol *> BaseAddress;
127+
128+
/// Address of the instruction referencing the jump table (MemLocInstr).
129+
uint64_t MemLocInstrAddress{0};
130+
95131
private:
96132
/// Constructor should only be called by a BinaryContext.
97133
JumpTable(MCSymbol &Symbol, uint64_t Address, size_t EntrySize,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===- bolt/Passes/JumpTableTrampoline.h ------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Jump table trampolines insertion pass.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef BOLT_PASSES_JUMP_TABLE_TRAMPOLINE_H
14+
#define BOLT_PASSES_JUMP_TABLE_TRAMPOLINE_H
15+
16+
#include "bolt/Passes/BinaryPasses.h"
17+
18+
namespace llvm {
19+
namespace bolt {
20+
21+
/// This pass inserts trampolines for entries in cold fragment into the hot
22+
/// fragment so that offsets fit into the original jump table entry size.
23+
class JumpTableTrampoline : public BinaryFunctionPass {
24+
DenseSet<const BinaryFunction *> Modified;
25+
26+
/// Run a pass for \p Function
27+
void optimizeFunction(BinaryFunction &Function);
28+
29+
public:
30+
explicit JumpTableTrampoline(const cl::opt<bool> &PrintPass)
31+
: BinaryFunctionPass(PrintPass) {}
32+
33+
const char *getName() const override { return "jump-table-trampoline"; }
34+
bool shouldPrint(const BinaryFunction &BF) const override {
35+
return BinaryFunctionPass::shouldPrint(BF) && Modified.count(&BF);
36+
}
37+
Error runOnFunctions(BinaryContext &BC) override;
38+
};
39+
40+
} // namespace bolt
41+
} // namespace llvm
42+
43+
#endif

bolt/include/bolt/Passes/LongJmp.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,28 @@ class LongJmpPass : public BinaryFunctionPass {
7676
/// 128MB of each other.
7777
void relaxLocalBranches(BinaryFunction &BF);
7878

79+
struct FunctionCluster {
80+
DenseSet<BinaryFunction *> Functions;
81+
82+
// Functions that this cluster of functions is calling. Note that it
83+
// excludes all functions in the cluster itself.
84+
DenseSet<BinaryFunction *> Callees;
85+
86+
uint64_t Size{0};
87+
88+
// Last function in the cluster.
89+
BinaryFunction *LastBF{nullptr};
90+
};
91+
92+
/// Maximum size of the function cluster. Note that it's less than 128MB
93+
/// as the size of the cluster plus thunk island should be less than 128MB.
94+
static constexpr uint64_t MaxClusterSize = 125 * 1024 * 1024;
95+
96+
/// Relax calls for medium code model where code is < 256MB.
97+
/// A thunk island will be introduced between two clusters of functions to
98+
/// enable calls over 128MB.
99+
void relaxCalls(BinaryContext &BC);
100+
79101
/// -- Layout estimation methods --
80102
/// Try to do layout before running the emitter, by looking at BinaryFunctions
81103
/// and MCInsts -- this is an estimation. To be correct for longjmp inserter

bolt/include/bolt/Rewrite/MetadataManager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class MetadataManager {
3131
/// Run initializers after sections are discovered.
3232
void runSectionInitializers();
3333

34+
/// Execute metadata initializers when functions are discovered but not yet
35+
/// disassembled.
36+
void runInitializersPreDisasm();
37+
3438
/// Execute initialization of rewriters while functions are disassembled, but
3539
/// CFG is not yet built.
3640
void runInitializersPreCFG();

bolt/include/bolt/Rewrite/MetadataRewriter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ class MetadataRewriter {
4949
/// but before functions are discovered.
5050
virtual Error sectionInitializer() { return Error::success(); }
5151

52+
/// Run initialization after the functions are identified but not yet
53+
/// disassembled.
54+
virtual Error preDisasmInitializer() { return Error::success(); }
55+
5256
/// Interface for modifying/annotating functions in the binary based on the
5357
/// contents of the section. Functions are in pre-cfg state.
5458
virtual Error preCFGInitializer() { return Error::success(); }

bolt/include/bolt/Rewrite/MetadataRewriters.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ std::unique_ptr<MetadataRewriter> createPseudoProbeRewriter(BinaryContext &);
2727

2828
std::unique_ptr<MetadataRewriter> createSDTRewriter(BinaryContext &);
2929

30+
std::unique_ptr<MetadataRewriter> createJumpTableInfoReader(BinaryContext &);
31+
3032
} // namespace bolt
3133
} // namespace llvm
3234

bolt/include/bolt/Rewrite/RewriteInstance.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ class RewriteInstance {
181181
/// Process metadata in sections before functions are discovered.
182182
void processSectionMetadata();
183183

184+
/// Process metadata in special sections before functions are disassembled.
185+
void processMetadataPreDisasm();
186+
184187
/// Process metadata in special sections before CFG is built for functions.
185188
void processMetadataPreCFG();
186189

0 commit comments

Comments
 (0)