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