-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[BOLT] Add support for safe-icf #116275
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
[BOLT] Add support for safe-icf #116275
Changes from 38 commits
03ca42c
237c02e
d794fb0
6e853ca
e36ec02
b83c335
39c7902
39586b3
debeb6f
429075e
29cc466
bf3bf2b
e867900
ab51077
8fe4b3c
dc41c58
6287a7f
c6a1965
d393b5e
4ace9bd
09bc3fa
3912b85
769cf24
d4f81c9
ec54f24
13bcc22
5110f74
d524ed5
77ae0a2
d03ff1d
38758ee
bfb1dc6
417196c
bbf015f
1ef1d27
f1813b3
eb882e5
f6dcb90
0070ceb
0f96524
a9cd467
6a89d5c
645aac2
23ea76b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,15 +27,53 @@ class IdenticalCodeFolding : public BinaryFunctionPass { | |
return false; | ||
if (BF.hasSDTMarker()) | ||
return false; | ||
if (BF.hasAddressTaken()) | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return false; | ||
return BinaryFunctionPass::shouldOptimize(BF); | ||
} | ||
|
||
public: | ||
enum class ICFLevel { | ||
None, // No ICF. (Default) | ||
Safe, // Safe ICF for all sections. | ||
All, // Aggressive ICF for code. | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
explicit IdenticalCodeFolding(const cl::opt<bool> &PrintPass) | ||
: BinaryFunctionPass(PrintPass) {} | ||
|
||
const char *getName() const override { return "identical-code-folding"; } | ||
Error runOnFunctions(BinaryContext &BC) override; | ||
|
||
private: | ||
/// Bit vector of memory addresses of vtables. | ||
llvm::BitVector VtableBitVector; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to use SparseBitVector? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My understanding random access is O(n) for it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, random access is O(N), but sequential is not:
Vtables should occupy a vanishingly small part of the binary, so sparse shouldn't be too inefficient. You can also drop an explicit size. Can you check the two and compare peak RSS (disabling debug info update) and pass wall time? Or let @maksfb weigh in. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BitVector Seems slightly faster with SparseBitVector. 🤷
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// Returns true if the memory address is in the bit vector of vtables. | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
bool isAddressInVTable(uint64_t Address) const { | ||
return VtableBitVector.test(Address / 8); | ||
} | ||
/// Initialize bit vector of memory addresses of vtables. | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
void initVtable() { | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
constexpr uint64_t PotentialRelocationAddressRange = | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(((uint64_t)1) << 32) / 8; | ||
VtableBitVector.resize(PotentialRelocationAddressRange); | ||
} | ||
/// Mark memory address of vtable as used. | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
void setAddressUsedInVTable(uint64_t Address) { | ||
VtableBitVector.set(Address / 8); | ||
} | ||
/// Scans symbol table and creates a bit vector of memory addresses of | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// vtables. | ||
void initVTableReferences(const BinaryContext &BC); | ||
/// Analyze .text section and relocations and mark functions that are not | ||
/// safe to fold. | ||
void markFunctionsUnsafeToFold(BinaryContext &BC); | ||
/// Process static and dynamic relocations in the data sections to identify | ||
/// function references, and marks them as unsafe to fold. It filters out | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// symbol references that are in vtables. | ||
void analyzeDataRelocations(BinaryContext &BC); | ||
/// Process functions that have CFG created and mark functions unsafe to fold | ||
ayermolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// that are used in non-control flow instructions. | ||
void analyzeFunctions(BinaryContext &BC); | ||
}; | ||
|
||
} // namespace bolt | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ extern cl::opt<bool> PrintDynoStats; | |
extern cl::opt<bool> DumpDotAll; | ||
extern cl::opt<std::string> AsmDump; | ||
extern cl::opt<bolt::PLTCall::OptType> PLT; | ||
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel> ICF; | ||
|
||
static cl::opt<bool> | ||
DynoStatsAll("dyno-stats-all", | ||
|
@@ -65,9 +66,6 @@ static cl::opt<bool> | |
cl::desc("eliminate unreachable code"), cl::init(true), | ||
cl::cat(BoltOptCategory)); | ||
|
||
cl::opt<bool> ICF("icf", cl::desc("fold functions with identical code"), | ||
cl::cat(BoltOptCategory)); | ||
|
||
static cl::opt<bool> JTFootprintReductionFlag( | ||
"jt-footprint-reduction", | ||
cl::desc("make jump tables size smaller at the cost of using more " | ||
|
@@ -398,7 +396,7 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { | |
opts::StripRepRet); | ||
|
||
Manager.registerPass(std::make_unique<IdenticalCodeFolding>(PrintICF), | ||
opts::ICF); | ||
opts::ICF != IdenticalCodeFolding::ICFLevel::None); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: define a helper method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems over complicating things over three checks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reduces diff changes. But it's a nit, so up to you. |
||
|
||
Manager.registerPass( | ||
std::make_unique<SpecializeMemcpy1>(NeverPrint, opts::SpecializeMemcpy1), | ||
|
@@ -423,7 +421,7 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { | |
Manager.registerPass(std::make_unique<Inliner>(PrintInline)); | ||
|
||
Manager.registerPass(std::make_unique<IdenticalCodeFolding>(PrintICF), | ||
opts::ICF); | ||
opts::ICF != IdenticalCodeFolding::ICFLevel::None); | ||
|
||
Manager.registerPass(std::make_unique<PLTCall>(PrintPLT)); | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.