xref: /llvm-project/bolt/lib/Passes/IdenticalCodeFolding.cpp (revision 3c357a49d61e4c81a1ac016502ee504521bc8dda)
1 //===- bolt/Passes/IdenticalCodeFolding.cpp -------------------------------===//
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 // This file implements the IdenticalCodeFolding class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "bolt/Passes/IdenticalCodeFolding.h"
14 #include "bolt/Core/HashUtilities.h"
15 #include "bolt/Core/ParallelUtilities.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/FormatVariadic.h"
19 #include "llvm/Support/ThreadPool.h"
20 #include "llvm/Support/Timer.h"
21 #include <atomic>
22 #include <iterator>
23 #include <map>
24 #include <set>
25 #include <unordered_map>
26 
27 #define DEBUG_TYPE "bolt-icf"
28 
29 using namespace llvm;
30 using namespace bolt;
31 
32 namespace opts {
33 
34 extern cl::OptionCategory BoltOptCategory;
35 
36 static cl::opt<bool>
37     ICFUseDFS("icf-dfs", cl::desc("use DFS ordering when using -icf option"),
38               cl::ReallyHidden, cl::cat(BoltOptCategory));
39 
40 static cl::opt<bool>
41 TimeICF("time-icf",
42   cl::desc("time icf steps"),
43   cl::ReallyHidden,
44   cl::ZeroOrMore,
45   cl::cat(BoltOptCategory));
46 
47 cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
48         DeprecatedICFNumericOptionParser>
49     ICF("icf", cl::desc("fold functions with identical code"),
50         cl::init(bolt::IdenticalCodeFolding::ICFLevel::None),
51         cl::values(clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::All, "all",
52                               "Enable identical code folding"),
53                    clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::All, "1",
54                               "Enable identical code folding"),
55                    clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::All, "",
56                               "Enable identical code folding"),
57                    clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::None,
58                               "none",
59                               "Disable identical code folding (default)"),
60                    clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::None, "0",
61                               "Disable identical code folding (default)"),
62                    clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::Safe,
63                               "safe", "Enable safe identical code folding")),
64         cl::ZeroOrMore, cl::ValueOptional, cl::cat(BoltOptCategory));
65 } // namespace opts
66 
67 bool IdenticalCodeFolding::shouldOptimize(const BinaryFunction &BF) const {
68   if (BF.hasUnknownControlFlow())
69     return false;
70   if (BF.isFolded())
71     return false;
72   if (BF.hasSDTMarker())
73     return false;
74   if (BF.isPseudo())
75     return false;
76   if (opts::ICF == ICFLevel::Safe && BF.hasAddressTaken())
77     return false;
78   return BinaryFunctionPass::shouldOptimize(BF);
79 }
80 
81 /// Compare two jump tables in 2 functions. The function relies on consistent
82 /// ordering of basic blocks in both binary functions (e.g. DFS).
83 static bool equalJumpTables(const JumpTable &JumpTableA,
84                             const JumpTable &JumpTableB,
85                             const BinaryFunction &FunctionA,
86                             const BinaryFunction &FunctionB) {
87   if (JumpTableA.EntrySize != JumpTableB.EntrySize)
88     return false;
89 
90   if (JumpTableA.Type != JumpTableB.Type)
91     return false;
92 
93   if (JumpTableA.getSize() != JumpTableB.getSize())
94     return false;
95 
96   for (uint64_t Index = 0; Index < JumpTableA.Entries.size(); ++Index) {
97     const MCSymbol *LabelA = JumpTableA.Entries[Index];
98     const MCSymbol *LabelB = JumpTableB.Entries[Index];
99 
100     const BinaryBasicBlock *TargetA = FunctionA.getBasicBlockForLabel(LabelA);
101     const BinaryBasicBlock *TargetB = FunctionB.getBasicBlockForLabel(LabelB);
102 
103     if (!TargetA || !TargetB) {
104       assert((TargetA || LabelA == FunctionA.getFunctionEndLabel()) &&
105              "no target basic block found");
106       assert((TargetB || LabelB == FunctionB.getFunctionEndLabel()) &&
107              "no target basic block found");
108 
109       if (TargetA != TargetB)
110         return false;
111 
112       continue;
113     }
114 
115     assert(TargetA && TargetB && "cannot locate target block(s)");
116 
117     if (TargetA->getLayoutIndex() != TargetB->getLayoutIndex())
118       return false;
119   }
120 
121   return true;
122 }
123 
124 /// Helper function that compares an instruction of this function to the
125 /// given instruction of the given function. The functions should have
126 /// identical CFG.
127 template <class Compare>
128 static bool isInstrEquivalentWith(const MCInst &InstA,
129                                   const BinaryBasicBlock &BBA,
130                                   const MCInst &InstB,
131                                   const BinaryBasicBlock &BBB, Compare Comp) {
132   if (InstA.getOpcode() != InstB.getOpcode())
133     return false;
134 
135   const BinaryContext &BC = BBA.getFunction()->getBinaryContext();
136 
137   // In this function we check for special conditions:
138   //
139   //    * instructions with landing pads
140   //
141   // Most of the common cases should be handled by MCPlus::equals()
142   // that compares regular instruction operands.
143   //
144   // NB: there's no need to compare jump table indirect jump instructions
145   //     separately as jump tables are handled by comparing corresponding
146   //     symbols.
147   const std::optional<MCPlus::MCLandingPad> EHInfoA = BC.MIB->getEHInfo(InstA);
148   const std::optional<MCPlus::MCLandingPad> EHInfoB = BC.MIB->getEHInfo(InstB);
149 
150   if (EHInfoA || EHInfoB) {
151     if (!EHInfoA && (EHInfoB->first || EHInfoB->second))
152       return false;
153 
154     if (!EHInfoB && (EHInfoA->first || EHInfoA->second))
155       return false;
156 
157     if (EHInfoA && EHInfoB) {
158       // Action indices should match.
159       if (EHInfoA->second != EHInfoB->second)
160         return false;
161 
162       if (!EHInfoA->first != !EHInfoB->first)
163         return false;
164 
165       if (EHInfoA->first && EHInfoB->first) {
166         const BinaryBasicBlock *LPA = BBA.getLandingPad(EHInfoA->first);
167         const BinaryBasicBlock *LPB = BBB.getLandingPad(EHInfoB->first);
168         assert(LPA && LPB && "cannot locate landing pad(s)");
169 
170         if (LPA->getLayoutIndex() != LPB->getLayoutIndex())
171           return false;
172       }
173     }
174   }
175 
176   return BC.MIB->equals(InstA, InstB, Comp);
177 }
178 
179 /// Returns true if this function has identical code and CFG with
180 /// the given function \p BF.
181 ///
182 /// If \p CongruentSymbols is set to true, then symbolic operands that reference
183 /// potentially identical but different functions are ignored during the
184 /// comparison.
185 static bool isIdenticalWith(const BinaryFunction &A, const BinaryFunction &B,
186                             bool CongruentSymbols) {
187   assert(A.hasCFG() && B.hasCFG() && "both functions should have CFG");
188 
189   // Compare the two functions, one basic block at a time.
190   // Currently we require two identical basic blocks to have identical
191   // instruction sequences and the same index in their corresponding
192   // functions. The latter is important for CFG equality.
193 
194   if (A.getLayout().block_size() != B.getLayout().block_size())
195     return false;
196 
197   // Comparing multi-entry functions could be non-trivial.
198   if (A.isMultiEntry() || B.isMultiEntry())
199     return false;
200 
201   if (A.hasIslandsInfo() || B.hasIslandsInfo())
202     return false;
203 
204   // Process both functions in either DFS or existing order.
205   SmallVector<const BinaryBasicBlock *, 0> OrderA;
206   SmallVector<const BinaryBasicBlock *, 0> OrderB;
207   if (opts::ICFUseDFS) {
208     copy(A.dfs(), std::back_inserter(OrderA));
209     copy(B.dfs(), std::back_inserter(OrderB));
210   } else {
211     copy(A.getLayout().blocks(), std::back_inserter(OrderA));
212     copy(B.getLayout().blocks(), std::back_inserter(OrderB));
213   }
214 
215   const BinaryContext &BC = A.getBinaryContext();
216 
217   auto BBI = OrderB.begin();
218   for (const BinaryBasicBlock *BB : OrderA) {
219     const BinaryBasicBlock *OtherBB = *BBI;
220 
221     if (BB->getLayoutIndex() != OtherBB->getLayoutIndex())
222       return false;
223 
224     // Compare successor basic blocks.
225     // NOTE: the comparison for jump tables is only partially verified here.
226     if (BB->succ_size() != OtherBB->succ_size())
227       return false;
228 
229     auto SuccBBI = OtherBB->succ_begin();
230     for (const BinaryBasicBlock *SuccBB : BB->successors()) {
231       const BinaryBasicBlock *SuccOtherBB = *SuccBBI;
232       if (SuccBB->getLayoutIndex() != SuccOtherBB->getLayoutIndex())
233         return false;
234       ++SuccBBI;
235     }
236 
237     // Compare all instructions including pseudos.
238     auto I = BB->begin(), E = BB->end();
239     auto OtherI = OtherBB->begin(), OtherE = OtherBB->end();
240     while (I != E && OtherI != OtherE) {
241       // Compare symbols.
242       auto AreSymbolsIdentical = [&](const MCSymbol *SymbolA,
243                                      const MCSymbol *SymbolB) {
244         if (SymbolA == SymbolB)
245           return true;
246 
247         // All local symbols are considered identical since they affect a
248         // control flow and we check the control flow separately.
249         // If a local symbol is escaped, then the function (potentially) has
250         // multiple entry points and we exclude such functions from
251         // comparison.
252         if (SymbolA->isTemporary() && SymbolB->isTemporary())
253           return true;
254 
255         // Compare symbols as functions.
256         uint64_t EntryIDA = 0;
257         uint64_t EntryIDB = 0;
258         const BinaryFunction *FunctionA =
259             BC.getFunctionForSymbol(SymbolA, &EntryIDA);
260         const BinaryFunction *FunctionB =
261             BC.getFunctionForSymbol(SymbolB, &EntryIDB);
262         if (FunctionA && EntryIDA)
263           FunctionA = nullptr;
264         if (FunctionB && EntryIDB)
265           FunctionB = nullptr;
266         if (FunctionA && FunctionB) {
267           // Self-referencing functions and recursive calls.
268           if (FunctionA == &A && FunctionB == &B)
269             return true;
270 
271           // Functions with different hash values can never become identical,
272           // hence A and B are different.
273           if (CongruentSymbols)
274             return FunctionA->getHash() == FunctionB->getHash();
275 
276           return FunctionA == FunctionB;
277         }
278 
279         // One of the symbols represents a function, the other one does not.
280         if (FunctionA != FunctionB)
281           return false;
282 
283         // Check if symbols are jump tables.
284         const BinaryData *SIA = BC.getBinaryDataByName(SymbolA->getName());
285         if (!SIA)
286           return false;
287         const BinaryData *SIB = BC.getBinaryDataByName(SymbolB->getName());
288         if (!SIB)
289           return false;
290 
291         assert((SIA->getAddress() != SIB->getAddress()) &&
292                "different symbols should not have the same value");
293 
294         const JumpTable *JumpTableA =
295             A.getJumpTableContainingAddress(SIA->getAddress());
296         if (!JumpTableA)
297           return false;
298 
299         const JumpTable *JumpTableB =
300             B.getJumpTableContainingAddress(SIB->getAddress());
301         if (!JumpTableB)
302           return false;
303 
304         if ((SIA->getAddress() - JumpTableA->getAddress()) !=
305             (SIB->getAddress() - JumpTableB->getAddress()))
306           return false;
307 
308         return equalJumpTables(*JumpTableA, *JumpTableB, A, B);
309       };
310 
311       if (!isInstrEquivalentWith(*I, *BB, *OtherI, *OtherBB,
312                                  AreSymbolsIdentical))
313         return false;
314 
315       ++I;
316       ++OtherI;
317     }
318 
319     // One of the identical blocks may have a trailing unconditional jump that
320     // is ignored for CFG purposes.
321     const MCInst *TrailingInstr =
322         (I != E ? &(*I) : (OtherI != OtherE ? &(*OtherI) : nullptr));
323     if (TrailingInstr && !BC.MIB->isUnconditionalBranch(*TrailingInstr))
324       return false;
325 
326     ++BBI;
327   }
328 
329   // Compare exceptions action tables.
330   if (A.getLSDAActionTable() != B.getLSDAActionTable() ||
331       A.getLSDATypeTable() != B.getLSDATypeTable() ||
332       A.getLSDATypeIndexTable() != B.getLSDATypeIndexTable())
333     return false;
334 
335   return true;
336 }
337 
338 // This hash table is used to identify identical functions. It maps
339 // a function to a bucket of functions identical to it.
340 struct KeyHash {
341   size_t operator()(const BinaryFunction *F) const { return F->getHash(); }
342 };
343 
344 /// Identify two congruent functions. Two functions are considered congruent,
345 /// if they are identical/equal except for some of their instruction operands
346 /// that reference potentially identical functions, i.e. functions that could
347 /// be folded later. Congruent functions are candidates for folding in our
348 /// iterative ICF algorithm.
349 ///
350 /// Congruent functions are required to have identical hash.
351 struct KeyCongruent {
352   bool operator()(const BinaryFunction *A, const BinaryFunction *B) const {
353     if (A == B)
354       return true;
355     return isIdenticalWith(*A, *B, /*CongruentSymbols=*/true);
356   }
357 };
358 
359 struct KeyEqual {
360   bool operator()(const BinaryFunction *A, const BinaryFunction *B) const {
361     if (A == B)
362       return true;
363     return isIdenticalWith(*A, *B, /*CongruentSymbols=*/false);
364   }
365 };
366 
367 typedef std::unordered_map<BinaryFunction *, std::set<BinaryFunction *>,
368                            KeyHash, KeyCongruent>
369     CongruentBucketsMap;
370 
371 typedef std::unordered_map<BinaryFunction *, std::vector<BinaryFunction *>,
372                            KeyHash, KeyEqual>
373     IdenticalBucketsMap;
374 
375 namespace llvm {
376 namespace bolt {
377 void IdenticalCodeFolding::initVTableReferences(const BinaryContext &BC) {
378   for (const auto &[Address, Data] : BC.getBinaryData()) {
379     // Filter out all symbols that are not vtables.
380     if (!Data->getName().starts_with("_ZTV"))
381       continue;
382     for (uint64_t I = Address, End = I + Data->getSize(); I < End; I += 8)
383       setAddressUsedInVTable(I);
384   }
385 }
386 
387 void IdenticalCodeFolding::analyzeDataRelocations(BinaryContext &BC) {
388   initVTableReferences(BC);
389   // For static relocations there should be a symbol for function references.
390   for (const BinarySection &Sec : BC.sections()) {
391     if (!Sec.hasSectionRef() || !Sec.isData())
392       continue;
393     for (const auto &Rel : Sec.relocations()) {
394       const uint64_t RelAddr = Rel.Offset + Sec.getAddress();
395       if (isAddressInVTable(RelAddr))
396         continue;
397       if (BinaryFunction *BF = BC.getFunctionForSymbol(Rel.Symbol))
398         BF->setHasAddressTaken(true);
399     }
400     // For dynamic relocations there are two cases:
401     // 1: No symbol and only addend.
402     // 2: There is a symbol, but it does not references a function in a binary.
403     for (const auto &Rel : Sec.dynamicRelocations()) {
404       const uint64_t RelAddr = Rel.Offset + Sec.getAddress();
405       if (isAddressInVTable(RelAddr))
406         continue;
407       if (BinaryFunction *BF = BC.getBinaryFunctionAtAddress(Rel.Addend))
408         BF->setHasAddressTaken(true);
409     }
410   }
411 }
412 
413 void IdenticalCodeFolding::analyzeFunctions(BinaryContext &BC) {
414   ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
415     for (const BinaryBasicBlock &BB : BF)
416       for (const MCInst &Inst : BB)
417         if (!(BC.MIB->isCall(Inst) || BC.MIB->isBranch(Inst)))
418           BF.analyzeInstructionForFuncReference(Inst);
419   };
420   ParallelUtilities::PredicateTy SkipFunc =
421       [&](const BinaryFunction &BF) -> bool { return !BF.hasCFG(); };
422   ParallelUtilities::runOnEachFunction(
423       BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun,
424       SkipFunc, "markUnsafe");
425 
426   LLVM_DEBUG({
427     for (const auto &BFIter : BC.getBinaryFunctions()) {
428       if (!BFIter.second.hasAddressTaken())
429         continue;
430       dbgs() << "BOLT-DEBUG: skipping function with reference taken "
431              << BFIter.second.getOneName() << '\n';
432     }
433   });
434 }
435 
436 void IdenticalCodeFolding::markFunctionsUnsafeToFold(BinaryContext &BC) {
437   NamedRegionTimer MarkFunctionsUnsafeToFoldTimer(
438       "markFunctionsUnsafeToFold", "markFunctionsUnsafeToFold", "ICF breakdown",
439       "ICF breakdown", opts::TimeICF);
440   if (!BC.isX86())
441     BC.outs() << "BOLT-WARNING: safe ICF is only supported for x86\n";
442   analyzeDataRelocations(BC);
443   analyzeFunctions(BC);
444 }
445 
446 Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
447   const size_t OriginalFunctionCount = BC.getBinaryFunctions().size();
448   uint64_t NumFunctionsFolded = 0;
449   std::atomic<uint64_t> NumJTFunctionsFolded{0};
450   std::atomic<uint64_t> BytesSavedEstimate{0};
451   std::atomic<uint64_t> NumCalled{0};
452   std::atomic<uint64_t> NumFoldedLastIteration{0};
453   CongruentBucketsMap CongruentBuckets;
454 
455   // Hash all the functions
456   auto hashFunctions = [&]() {
457     NamedRegionTimer HashFunctionsTimer("hashing", "hashing", "ICF breakdown",
458                                         "ICF breakdown", opts::TimeICF);
459     ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
460       // Make sure indices are in-order.
461       if (opts::ICFUseDFS)
462         BF.getLayout().updateLayoutIndices(BF.dfs());
463       else
464         BF.getLayout().updateLayoutIndices();
465 
466       // Pre-compute hash before pushing into hashtable.
467       // Hash instruction operands to minimize hash collisions.
468       BF.computeHash(
469           opts::ICFUseDFS, HashFunction::Default,
470           [&BC](const MCOperand &Op) { return hashInstOperand(BC, Op); });
471     };
472 
473     ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) {
474       return !shouldOptimize(BF);
475     };
476 
477     ParallelUtilities::runOnEachFunction(
478         BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, SkipFunc,
479         "hashFunctions", /*ForceSequential*/ false, 2);
480   };
481 
482   // Creates buckets with congruent functions - functions that potentially
483   // could  be folded.
484   auto createCongruentBuckets = [&]() {
485     NamedRegionTimer CongruentBucketsTimer("congruent buckets",
486                                            "congruent buckets", "ICF breakdown",
487                                            "ICF breakdown", opts::TimeICF);
488     for (auto &BFI : BC.getBinaryFunctions()) {
489       BinaryFunction &BF = BFI.second;
490       if (!shouldOptimize(BF))
491         continue;
492       CongruentBuckets[&BF].emplace(&BF);
493     }
494   };
495 
496   // Partition each set of congruent functions into sets of identical functions
497   // and fold them
498   auto performFoldingPass = [&]() {
499     NamedRegionTimer FoldingPassesTimer("folding passes", "folding passes",
500                                         "ICF breakdown", "ICF breakdown",
501                                         opts::TimeICF);
502     Timer SinglePass("single fold pass", "single fold pass");
503     LLVM_DEBUG(SinglePass.startTimer());
504 
505     ThreadPoolInterface *ThPool;
506     if (!opts::NoThreads)
507       ThPool = &ParallelUtilities::getThreadPool();
508 
509     // Fold identical functions within a single congruent bucket
510     auto processSingleBucket = [&](std::set<BinaryFunction *> &Candidates) {
511       Timer T("folding single congruent list", "folding single congruent list");
512       LLVM_DEBUG(T.startTimer());
513 
514       // Identical functions go into the same bucket.
515       IdenticalBucketsMap IdenticalBuckets;
516       for (BinaryFunction *BF : Candidates) {
517         IdenticalBuckets[BF].emplace_back(BF);
518       }
519 
520       for (auto &IBI : IdenticalBuckets) {
521         // Functions identified as identical.
522         std::vector<BinaryFunction *> &Twins = IBI.second;
523         if (Twins.size() < 2)
524           continue;
525 
526         // Fold functions. Keep the order consistent across invocations with
527         // different options.
528         llvm::stable_sort(
529             Twins, [](const BinaryFunction *A, const BinaryFunction *B) {
530               return A->getFunctionNumber() < B->getFunctionNumber();
531             });
532 
533         BinaryFunction *ParentBF = Twins[0];
534         if (!ParentBF->hasFunctionsFoldedInto())
535           NumCalled += ParentBF->getKnownExecutionCount();
536         for (unsigned I = 1; I < Twins.size(); ++I) {
537           BinaryFunction *ChildBF = Twins[I];
538           LLVM_DEBUG(dbgs() << "BOLT-DEBUG: folding " << *ChildBF << " into "
539                             << *ParentBF << '\n');
540 
541           // Remove child function from the list of candidates.
542           auto FI = Candidates.find(ChildBF);
543           assert(FI != Candidates.end() &&
544                  "function expected to be in the set");
545           Candidates.erase(FI);
546 
547           // Fold the function and remove from the list of processed functions.
548           BytesSavedEstimate += ChildBF->getSize();
549           if (!ChildBF->hasFunctionsFoldedInto())
550             NumCalled += ChildBF->getKnownExecutionCount();
551           BC.foldFunction(*ChildBF, *ParentBF);
552 
553           ++NumFoldedLastIteration;
554 
555           if (ParentBF->hasJumpTables())
556             ++NumJTFunctionsFolded;
557         }
558       }
559 
560       LLVM_DEBUG(T.stopTimer());
561     };
562 
563     // Create a task for each congruent bucket
564     for (auto &Entry : CongruentBuckets) {
565       std::set<BinaryFunction *> &Bucket = Entry.second;
566       if (Bucket.size() < 2)
567         continue;
568 
569       if (opts::NoThreads)
570         processSingleBucket(Bucket);
571       else
572         ThPool->async(processSingleBucket, std::ref(Bucket));
573     }
574 
575     if (!opts::NoThreads)
576       ThPool->wait();
577 
578     LLVM_DEBUG(SinglePass.stopTimer());
579   };
580   if (opts::ICF == ICFLevel::Safe)
581     markFunctionsUnsafeToFold(BC);
582   hashFunctions();
583   createCongruentBuckets();
584 
585   unsigned Iteration = 1;
586   // We repeat the pass until no new modifications happen.
587   do {
588     NumFoldedLastIteration = 0;
589     LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ICF iteration " << Iteration << "...\n");
590 
591     performFoldingPass();
592 
593     NumFunctionsFolded += NumFoldedLastIteration;
594     ++Iteration;
595 
596   } while (NumFoldedLastIteration > 0);
597 
598   LLVM_DEBUG({
599     // Print functions that are congruent but not identical.
600     for (auto &CBI : CongruentBuckets) {
601       std::set<BinaryFunction *> &Candidates = CBI.second;
602       if (Candidates.size() < 2)
603         continue;
604       dbgs() << "BOLT-DEBUG: the following " << Candidates.size()
605              << " functions (each of size " << (*Candidates.begin())->getSize()
606              << " bytes) are congruent but not identical:\n";
607       for (BinaryFunction *BF : Candidates) {
608         dbgs() << "  " << *BF;
609         if (BF->getKnownExecutionCount())
610           dbgs() << " (executed " << BF->getKnownExecutionCount() << " times)";
611         dbgs() << '\n';
612       }
613     }
614   });
615 
616   if (NumFunctionsFolded)
617     BC.outs() << "BOLT-INFO: ICF folded " << NumFunctionsFolded << " out of "
618               << OriginalFunctionCount << " functions in " << Iteration
619               << " passes. " << NumJTFunctionsFolded
620               << " functions had jump tables.\n"
621               << "BOLT-INFO: Removing all identical functions will save "
622               << format("%.2lf", (double)BytesSavedEstimate / 1024)
623               << " KB of code space. Folded functions were called " << NumCalled
624               << " times based on profile.\n";
625 
626   return Error::success();
627 }
628 
629 } // namespace bolt
630 } // namespace llvm
631