[ICF] Don't re-fold functions in non-relocation mode.

Summary:
In-non relocation mode, when we run ICF the second time,
we fold the same functions again since they were not
removed from the function set. This diff marks them as
folded and ignores them during ICF optimization. Note
that we still want to optimize such functions since they
are potentially called from the code not covered by BOLT
in non-relocation mode.

Folded functions are also excluded from dyno stats with
this diff

Also print the number of times folded functions were called.
When 2 functions -  f1() and f2() are folded, that number
would be min(call_frequency(f1), call_frequency(f2)).

(cherry picked from FBD4399993)
This commit is contained in:
Maksim Panchenko 2017-01-10 11:20:56 -08:00
parent bc8a456309
commit 0894905373
4 changed files with 26 additions and 3 deletions

View File

@ -104,6 +104,7 @@ void BinaryContext::foldFunction(BinaryFunction &ChildBF,
ChildBF.Names.clear();
ChildBF.Names.push_back(NewName);
ChildBF.OutputSymbol = Ctx->getOrCreateSymbol(NewName);
ChildBF.setFolded();
}
}

View File

@ -3531,6 +3531,11 @@ DynoStats BinaryFunction::getDynoStats() const {
if (!isSimple() || !hasValidProfile())
return Stats;
// If the function was folded in non-relocation mode we keep its profile
// for optimization. However, it should be excluded from the dyno stats.
if (isFolded())
return Stats;
// Update enumeration of basic blocks for correct detection of branch'
// direction.
updateLayoutIndices();

View File

@ -253,6 +253,10 @@ private:
/// True if the function has more than one entry point.
bool IsMultiEntry{false};
/// Indicate if the function body was folded into another function. Used
/// for ICF optimization without relocations.
bool IsFolded{false};
/// The address for the code for this function in codegen memory.
uint64_t ImageAddress{0};
@ -1019,6 +1023,10 @@ public:
return IsMultiEntry;
}
bool isFolded() const {
return IsFolded;
}
/// Return true if the function uses jump tables.
bool hasJumpTables() const {
return JumpTables.size();
@ -1291,6 +1299,11 @@ public:
return *this;
}
BinaryFunction &setFolded(bool Folded = true) {
IsFolded = Folded;
return *this;
}
BinaryFunction &setPersonalityFunction(uint64_t Addr) {
PersonalityFunction = BC.getOrCreateGlobalSymbol(Addr, "FUNCat");
return *this;

View File

@ -1330,6 +1330,7 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC,
uint64_t NumFunctionsFolded = 0;
uint64_t NumJTFunctionsFolded = 0;
uint64_t BytesSavedEstimate = 0;
uint64_t CallsSavedEstimate = 0;
static bool UseDFS = opts::UseDFSForICF;
// This hash table is used to identify identical functions. It maps
@ -1356,7 +1357,7 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC,
KeyHash, KeyCongruent> CongruentBuckets;
for (auto &BFI : BFs) {
auto &BF = BFI.second;
if (!shouldOptimize(BF))
if (!shouldOptimize(BF) || BF.isFolded())
continue;
// Make sure indices are in-order.
@ -1414,9 +1415,11 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC,
Candidates.erase(FI);
// Fold the function and remove from the list of processed functions.
BytesSavedEstimate += ChildBF->getSize();
CallsSavedEstimate += std::min(ChildBF->getKnownExecutionCount(),
ParentBF->getKnownExecutionCount());
BC.foldFunction(*ChildBF, *ParentBF, BFs);
BytesSavedEstimate += ChildBF->getSize();
++NumFoldedLastIteration;
if (ParentBF->hasJumpTables())
@ -1456,7 +1459,8 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC,
<< NumJTFunctionsFolded << " functions had jump tables.\n"
<< "BOLT-INFO: Removing all identical functions will save "
<< format("%.2lf", (double) BytesSavedEstimate / 1024)
<< " KB of code space.\n";
<< " KB of code space. Folded functions were called "
<< CallsSavedEstimate << " times based on profile.\n";
}
}