1111// ===----------------------------------------------------------------------===//
1212
1313#include " bolt/Passes/IdenticalCodeFolding.h"
14+ #include " bolt/Core/BinaryContext.h"
1415#include " bolt/Core/HashUtilities.h"
1516#include " bolt/Core/ParallelUtilities.h"
17+ #include " bolt/Rewrite/RewriteInstance.h"
1618#include " llvm/ADT/SmallVector.h"
1719#include " llvm/Support/CommandLine.h"
1820#include " llvm/Support/ThreadPool.h"
@@ -31,6 +33,7 @@ using namespace bolt;
3133namespace opts {
3234
3335extern cl::OptionCategory BoltOptCategory;
36+ extern cl::opt<unsigned > Verbosity;
3437
3538static cl::opt<bool >
3639 ICFUseDFS (" icf-dfs" , cl::desc(" use DFS ordering when using -icf option" ),
@@ -341,6 +344,75 @@ typedef std::unordered_map<BinaryFunction *, std::vector<BinaryFunction *>,
341344namespace llvm {
342345namespace bolt {
343346
347+ void IdenticalCodeFolding::processDataRelocations (
348+ BinaryContext &BC, const SectionRef &SecRefRelData) {
349+ for (const RelocationRef &Rel : SecRefRelData.relocations ()) {
350+ symbol_iterator SymbolIter = Rel.getSymbol ();
351+ const ObjectFile *OwningObj = Rel.getObject ();
352+ assert (SymbolIter != OwningObj->symbol_end () &&
353+ " relocation Symbol expected" );
354+ const SymbolRef &Symbol = *SymbolIter;
355+ const uint64_t SymbolAddress = cantFail (Symbol.getAddress ());
356+ const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(OwningObj);
357+ if (!ELFObj)
358+ assert (false && " Only ELFObjectFileBase is supported" );
359+ const int64_t Addend = BinaryContext::getRelocationAddend (ELFObj, Rel);
360+ BinaryFunction *BF = BC.getBinaryFunctionAtAddress (SymbolAddress + Addend);
361+ if (!BF)
362+ continue ;
363+ BF->setUnsetToICF ();
364+ }
365+ }
366+
367+ Error IdenticalCodeFolding::createFoldSkipList (BinaryContext &BC) {
368+ Error ErrorStatus = Error::success ();
369+ ErrorOr<BinarySection &> SecRelData = BC.getUniqueSectionByName (" .rela.data" );
370+ if (!BC.HasRelocations )
371+ ErrorStatus = joinErrors (
372+ std::move (ErrorStatus),
373+ createFatalBOLTError (Twine (" BOLT-ERROR: Binary built without "
374+ " relocations. Safe ICF is not supported" )));
375+ if (ErrorStatus)
376+ return ErrorStatus;
377+ if (SecRelData) {
378+ SectionRef SecRefRelData = SecRelData->getSectionRef ();
379+ processDataRelocations (BC, SecRefRelData);
380+ }
381+
382+ ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
383+ if (BF.getState () == BinaryFunction::State::CFG) {
384+ for (const BinaryBasicBlock *BB : BF.getLayout ().blocks ())
385+ for (const MCInst &Inst : *BB)
386+ BC.processInstructionForFuncReferences (Inst);
387+ }
388+ };
389+ ParallelUtilities::PredicateTy SkipFunc =
390+ [&](const BinaryFunction &BF) -> bool { return (bool )ErrorStatus; };
391+ ParallelUtilities::runOnEachFunction (
392+ BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, SkipFunc,
393+ " markUnsafe" , /* ForceSequential*/ false , 2 );
394+
395+ LLVM_DEBUG ({
396+ std::vector<StringRef> Vect;
397+ std::mutex PrintMutex;
398+ ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
399+ if (BF.isSafeToICF ())
400+ return ;
401+ std::lock_guard<std::mutex> Lock (PrintMutex);
402+ Vect.push_back (BF.getOneName ());
403+ };
404+ ParallelUtilities::PredicateTy SkipFunc =
405+ [&](const BinaryFunction &BF) -> bool { return false ; };
406+ ParallelUtilities::runOnEachFunction (
407+ BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, SkipFunc,
408+ " markUnsafe" , /* ForceSequential*/ false , 2 );
409+ llvm::sort (Vect);
410+ for (const auto &FuncName : Vect)
411+ dbgs () << " BOLT-DEBUG: skipping function " << FuncName << ' \n ' ;
412+ });
413+ return ErrorStatus;
414+ }
415+
344416Error IdenticalCodeFolding::runOnFunctions (BinaryContext &BC) {
345417 const size_t OriginalFunctionCount = BC.getBinaryFunctions ().size ();
346418 uint64_t NumFunctionsFolded = 0 ;
@@ -350,6 +422,9 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
350422 std::atomic<uint64_t > NumFoldedLastIteration{0 };
351423 CongruentBucketsMap CongruentBuckets;
352424
425+ auto SkipFuncShared = [&](const BinaryFunction &BF) {
426+ return !shouldOptimize (BF) || !BF.isSafeToICF ();
427+ };
353428 // Hash all the functions
354429 auto hashFunctions = [&]() {
355430 NamedRegionTimer HashFunctionsTimer (" hashing" , " hashing" , " ICF breakdown" ,
@@ -369,7 +444,7 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
369444 };
370445
371446 ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) {
372- return ! shouldOptimize (BF);
447+ return SkipFuncShared (BF);
373448 };
374449
375450 ParallelUtilities::runOnEachFunction (
@@ -385,7 +460,7 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
385460 " ICF breakdown" , opts::TimeICF);
386461 for (auto &BFI : BC.getBinaryFunctions ()) {
387462 BinaryFunction &BF = BFI.second ;
388- if (! this -> shouldOptimize (BF))
463+ if (SkipFuncShared (BF))
389464 continue ;
390465 CongruentBuckets[&BF].emplace (&BF);
391466 }
@@ -475,7 +550,11 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
475550
476551 LLVM_DEBUG (SinglePass.stopTimer ());
477552 };
478-
553+ if (IsSafeICF) {
554+ if (Error Err = createFoldSkipList (BC)) {
555+ return Err;
556+ }
557+ }
479558 hashFunctions ();
480559 createCongruentBuckets ();
481560
0 commit comments