1 //===- bolt/Passes/BinaryPasses.cpp - Binary-level passes -----------------===// 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 multiple passes for binary optimization and analysis. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "bolt/Passes/BinaryPasses.h" 14 #include "bolt/Core/ParallelUtilities.h" 15 #include "bolt/Passes/ReorderAlgorithm.h" 16 #include "bolt/Passes/ReorderFunctions.h" 17 #include "llvm/Support/CommandLine.h" 18 19 #include <numeric> 20 #include <vector> 21 22 #define DEBUG_TYPE "bolt-opts" 23 24 using namespace llvm; 25 using namespace bolt; 26 27 namespace { 28 29 const char *dynoStatsOptName(const bolt::DynoStats::Category C) { 30 if (C == bolt::DynoStats::FIRST_DYNO_STAT) 31 return "none"; 32 else if (C == bolt::DynoStats::LAST_DYNO_STAT) 33 return "all"; 34 35 static std::string OptNames[bolt::DynoStats::LAST_DYNO_STAT + 1]; 36 37 OptNames[C] = bolt::DynoStats::Description(C); 38 39 std::replace(OptNames[C].begin(), OptNames[C].end(), ' ', '-'); 40 41 return OptNames[C].c_str(); 42 } 43 44 const char *dynoStatsOptDesc(const bolt::DynoStats::Category C) { 45 if (C == bolt::DynoStats::FIRST_DYNO_STAT) 46 return "unsorted"; 47 else if (C == bolt::DynoStats::LAST_DYNO_STAT) 48 return "sorted by all stats"; 49 50 return bolt::DynoStats::Description(C); 51 } 52 53 } 54 55 namespace opts { 56 57 extern cl::OptionCategory BoltCategory; 58 extern cl::OptionCategory BoltOptCategory; 59 60 extern cl::opt<bolt::MacroFusionType> AlignMacroOpFusion; 61 extern cl::opt<unsigned> Verbosity; 62 extern cl::opt<bool> EnableBAT; 63 extern cl::opt<unsigned> ExecutionCountThreshold; 64 extern cl::opt<bool> UpdateDebugSections; 65 extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions; 66 67 enum DynoStatsSortOrder : char { 68 Ascending, 69 Descending 70 }; 71 72 static cl::opt<DynoStatsSortOrder> 73 DynoStatsSortOrderOpt("print-sorted-by-order", 74 cl::desc("use ascending or descending order when printing functions " 75 "ordered by dyno stats"), 76 cl::ZeroOrMore, 77 cl::init(DynoStatsSortOrder::Descending), 78 cl::cat(BoltOptCategory)); 79 80 cl::list<std::string> 81 HotTextMoveSections("hot-text-move-sections", 82 cl::desc("list of sections containing functions used for hugifying hot text. " 83 "BOLT makes sure these functions are not placed on the same page as " 84 "the hot text. (default=\'.stub,.mover\')."), 85 cl::value_desc("sec1,sec2,sec3,..."), 86 cl::CommaSeparated, 87 cl::ZeroOrMore, 88 cl::cat(BoltCategory)); 89 90 bool isHotTextMover(const BinaryFunction &Function) { 91 for (std::string &SectionName : opts::HotTextMoveSections) { 92 if (Function.getOriginSectionName() && 93 *Function.getOriginSectionName() == SectionName) 94 return true; 95 } 96 97 return false; 98 } 99 100 static cl::opt<bool> 101 MinBranchClusters("min-branch-clusters", 102 cl::desc("use a modified clustering algorithm geared towards minimizing " 103 "branches"), 104 cl::ZeroOrMore, 105 cl::Hidden, 106 cl::cat(BoltOptCategory)); 107 108 static cl::list<Peepholes::PeepholeOpts> Peepholes( 109 "peepholes", cl::CommaSeparated, cl::desc("enable peephole optimizations"), 110 cl::value_desc("opt1,opt2,opt3,..."), 111 cl::values(clEnumValN(Peepholes::PEEP_NONE, "none", "disable peepholes"), 112 clEnumValN(Peepholes::PEEP_DOUBLE_JUMPS, "double-jumps", 113 "remove double jumps when able"), 114 clEnumValN(Peepholes::PEEP_TAILCALL_TRAPS, "tailcall-traps", 115 "insert tail call traps"), 116 clEnumValN(Peepholes::PEEP_USELESS_BRANCHES, "useless-branches", 117 "remove useless conditional branches"), 118 clEnumValN(Peepholes::PEEP_ALL, "all", 119 "enable all peephole optimizations")), 120 cl::ZeroOrMore, cl::cat(BoltOptCategory)); 121 122 static cl::opt<unsigned> 123 PrintFuncStat("print-function-statistics", 124 cl::desc("print statistics about basic block ordering"), 125 cl::init(0), 126 cl::ZeroOrMore, 127 cl::cat(BoltOptCategory)); 128 129 static cl::list<bolt::DynoStats::Category> 130 PrintSortedBy("print-sorted-by", 131 cl::CommaSeparated, 132 cl::desc("print functions sorted by order of dyno stats"), 133 cl::value_desc("key1,key2,key3,..."), 134 cl::values( 135 #define D(name, ...) \ 136 clEnumValN(bolt::DynoStats::name, \ 137 dynoStatsOptName(bolt::DynoStats::name), \ 138 dynoStatsOptDesc(bolt::DynoStats::name)), 139 DYNO_STATS 140 #undef D 141 clEnumValN(0xffff, ".", ".") 142 ), 143 cl::ZeroOrMore, 144 cl::cat(BoltOptCategory)); 145 146 static cl::opt<bool> 147 PrintUnknown("print-unknown", 148 cl::desc("print names of functions with unknown control flow"), 149 cl::init(false), 150 cl::ZeroOrMore, 151 cl::cat(BoltCategory), 152 cl::Hidden); 153 154 static cl::opt<bool> 155 PrintUnknownCFG("print-unknown-cfg", 156 cl::desc("dump CFG of functions with unknown control flow"), 157 cl::init(false), 158 cl::ZeroOrMore, 159 cl::cat(BoltCategory), 160 cl::ReallyHidden); 161 162 cl::opt<bolt::ReorderBasicBlocks::LayoutType> ReorderBlocks( 163 "reorder-blocks", cl::desc("change layout of basic blocks in a function"), 164 cl::init(bolt::ReorderBasicBlocks::LT_NONE), 165 cl::values( 166 clEnumValN(bolt::ReorderBasicBlocks::LT_NONE, "none", 167 "do not reorder basic blocks"), 168 clEnumValN(bolt::ReorderBasicBlocks::LT_REVERSE, "reverse", 169 "layout blocks in reverse order"), 170 clEnumValN(bolt::ReorderBasicBlocks::LT_OPTIMIZE, "normal", 171 "perform optimal layout based on profile"), 172 clEnumValN(bolt::ReorderBasicBlocks::LT_OPTIMIZE_BRANCH, 173 "branch-predictor", 174 "perform optimal layout prioritizing branch " 175 "predictions"), 176 clEnumValN(bolt::ReorderBasicBlocks::LT_OPTIMIZE_CACHE, "cache", 177 "perform optimal layout prioritizing I-cache " 178 "behavior"), 179 clEnumValN(bolt::ReorderBasicBlocks::LT_OPTIMIZE_CACHE_PLUS, "cache+", 180 "perform layout optimizing I-cache behavior"), 181 clEnumValN(bolt::ReorderBasicBlocks::LT_OPTIMIZE_EXT_TSP, "ext-tsp", 182 "perform layout optimizing I-cache behavior"), 183 clEnumValN(bolt::ReorderBasicBlocks::LT_OPTIMIZE_SHUFFLE, 184 "cluster-shuffle", "perform random layout of clusters")), 185 cl::ZeroOrMore, cl::cat(BoltOptCategory), 186 cl::callback([](const bolt::ReorderBasicBlocks::LayoutType &option) { 187 if (option == bolt::ReorderBasicBlocks::LT_OPTIMIZE_CACHE_PLUS) { 188 WithColor::warning() 189 << "'-reorder-blocks=cache+' is deprecated, " 190 << "please use '-reorder-blocks=ext-tsp' instead\n"; 191 ReorderBlocks = bolt::ReorderBasicBlocks::LT_OPTIMIZE_EXT_TSP; 192 } 193 })); 194 195 static cl::opt<unsigned> 196 ReportBadLayout("report-bad-layout", 197 cl::desc("print top <uint> functions with suboptimal code layout on input"), 198 cl::init(0), 199 cl::ZeroOrMore, 200 cl::Hidden, 201 cl::cat(BoltOptCategory)); 202 203 static cl::opt<bool> 204 ReportStaleFuncs("report-stale", 205 cl::desc("print the list of functions with stale profile"), 206 cl::init(false), 207 cl::ZeroOrMore, 208 cl::Hidden, 209 cl::cat(BoltOptCategory)); 210 211 enum SctcModes : char { 212 SctcAlways, 213 SctcPreserveDirection, 214 SctcHeuristic 215 }; 216 217 static cl::opt<SctcModes> 218 SctcMode("sctc-mode", 219 cl::desc("mode for simplify conditional tail calls"), 220 cl::init(SctcAlways), 221 cl::values(clEnumValN(SctcAlways, "always", "always perform sctc"), 222 clEnumValN(SctcPreserveDirection, 223 "preserve", 224 "only perform sctc when branch direction is " 225 "preserved"), 226 clEnumValN(SctcHeuristic, 227 "heuristic", 228 "use branch prediction data to control sctc")), 229 cl::ZeroOrMore, 230 cl::cat(BoltOptCategory)); 231 232 static cl::opt<unsigned> 233 StaleThreshold("stale-threshold", 234 cl::desc( 235 "maximum percentage of stale functions to tolerate (default: 100)"), 236 cl::init(100), 237 cl::Hidden, 238 cl::cat(BoltOptCategory)); 239 240 static cl::opt<unsigned> 241 TSPThreshold("tsp-threshold", 242 cl::desc("maximum number of hot basic blocks in a function for which to use " 243 "a precise TSP solution while re-ordering basic blocks"), 244 cl::init(10), 245 cl::ZeroOrMore, 246 cl::Hidden, 247 cl::cat(BoltOptCategory)); 248 249 static cl::opt<unsigned> 250 TopCalledLimit("top-called-limit", 251 cl::desc("maximum number of functions to print in top called " 252 "functions section"), 253 cl::init(100), 254 cl::ZeroOrMore, 255 cl::Hidden, 256 cl::cat(BoltCategory)); 257 258 } // namespace opts 259 260 namespace llvm { 261 namespace bolt { 262 263 bool BinaryFunctionPass::shouldOptimize(const BinaryFunction &BF) const { 264 return BF.isSimple() && BF.getState() == BinaryFunction::State::CFG && 265 !BF.isIgnored(); 266 } 267 268 bool BinaryFunctionPass::shouldPrint(const BinaryFunction &BF) const { 269 return BF.isSimple() && !BF.isIgnored(); 270 } 271 272 void NormalizeCFG::runOnFunction(BinaryFunction &BF) { 273 uint64_t NumRemoved = 0; 274 uint64_t NumDuplicateEdges = 0; 275 uint64_t NeedsFixBranches = 0; 276 for (BinaryBasicBlock &BB : BF) { 277 if (!BB.empty()) 278 continue; 279 280 if (BB.isEntryPoint() || BB.isLandingPad()) 281 continue; 282 283 // Handle a dangling empty block. 284 if (BB.succ_size() == 0) { 285 // If an empty dangling basic block has a predecessor, it could be a 286 // result of codegen for __builtin_unreachable. In such case, do not 287 // remove the block. 288 if (BB.pred_size() == 0) { 289 BB.markValid(false); 290 ++NumRemoved; 291 } 292 continue; 293 } 294 295 // The block should have just one successor. 296 BinaryBasicBlock *Successor = BB.getSuccessor(); 297 assert(Successor && "invalid CFG encountered"); 298 299 // Redirect all predecessors to the successor block. 300 while (!BB.pred_empty()) { 301 BinaryBasicBlock *Predecessor = *BB.pred_begin(); 302 if (Predecessor->hasJumpTable()) 303 break; 304 305 if (Predecessor == Successor) 306 break; 307 308 BinaryBasicBlock::BinaryBranchInfo &BI = Predecessor->getBranchInfo(BB); 309 Predecessor->replaceSuccessor(&BB, Successor, BI.Count, 310 BI.MispredictedCount); 311 // We need to fix branches even if we failed to replace all successors 312 // and remove the block. 313 NeedsFixBranches = true; 314 } 315 316 if (BB.pred_empty()) { 317 BB.removeAllSuccessors(); 318 BB.markValid(false); 319 ++NumRemoved; 320 } 321 } 322 323 if (NumRemoved) 324 BF.eraseInvalidBBs(); 325 326 // Check for duplicate successors. Do it after the empty block elimination as 327 // we can get more duplicate successors. 328 for (BinaryBasicBlock &BB : BF) 329 if (!BB.hasJumpTable() && BB.succ_size() == 2 && 330 BB.getConditionalSuccessor(false) == BB.getConditionalSuccessor(true)) 331 ++NumDuplicateEdges; 332 333 // fixBranches() will get rid of duplicate edges and update jump instructions. 334 if (NumDuplicateEdges || NeedsFixBranches) 335 BF.fixBranches(); 336 337 NumDuplicateEdgesMerged += NumDuplicateEdges; 338 NumBlocksRemoved += NumRemoved; 339 } 340 341 void NormalizeCFG::runOnFunctions(BinaryContext &BC) { 342 ParallelUtilities::runOnEachFunction( 343 BC, ParallelUtilities::SchedulingPolicy::SP_BB_LINEAR, 344 [&](BinaryFunction &BF) { runOnFunction(BF); }, 345 [&](const BinaryFunction &BF) { return !shouldOptimize(BF); }, 346 "NormalizeCFG"); 347 if (NumBlocksRemoved) 348 outs() << "BOLT-INFO: removed " << NumBlocksRemoved << " empty block" 349 << (NumBlocksRemoved == 1 ? "" : "s") << '\n'; 350 if (NumDuplicateEdgesMerged) 351 outs() << "BOLT-INFO: merged " << NumDuplicateEdgesMerged 352 << " duplicate CFG edge" << (NumDuplicateEdgesMerged == 1 ? "" : "s") 353 << '\n'; 354 } 355 356 void EliminateUnreachableBlocks::runOnFunction(BinaryFunction &Function) { 357 if (Function.layout_size() > 0) { 358 unsigned Count; 359 uint64_t Bytes; 360 Function.markUnreachableBlocks(); 361 LLVM_DEBUG({ 362 for (BinaryBasicBlock *BB : Function.layout()) { 363 if (!BB->isValid()) { 364 dbgs() << "BOLT-INFO: UCE found unreachable block " << BB->getName() 365 << " in function " << Function << "\n"; 366 Function.dump(); 367 } 368 } 369 }); 370 std::tie(Count, Bytes) = Function.eraseInvalidBBs(); 371 DeletedBlocks += Count; 372 DeletedBytes += Bytes; 373 if (Count) { 374 Modified.insert(&Function); 375 if (opts::Verbosity > 0) 376 outs() << "BOLT-INFO: Removed " << Count 377 << " dead basic block(s) accounting for " << Bytes 378 << " bytes in function " << Function << '\n'; 379 } 380 } 381 } 382 383 void EliminateUnreachableBlocks::runOnFunctions(BinaryContext &BC) { 384 for (auto &It : BC.getBinaryFunctions()) { 385 BinaryFunction &Function = It.second; 386 if (shouldOptimize(Function)) 387 runOnFunction(Function); 388 } 389 390 outs() << "BOLT-INFO: UCE removed " << DeletedBlocks << " blocks and " 391 << DeletedBytes << " bytes of code.\n"; 392 } 393 394 bool ReorderBasicBlocks::shouldPrint(const BinaryFunction &BF) const { 395 return (BinaryFunctionPass::shouldPrint(BF) && 396 opts::ReorderBlocks != ReorderBasicBlocks::LT_NONE); 397 } 398 399 bool ReorderBasicBlocks::shouldOptimize(const BinaryFunction &BF) const { 400 // Apply execution count threshold 401 if (BF.getKnownExecutionCount() < opts::ExecutionCountThreshold) 402 return false; 403 404 return BinaryFunctionPass::shouldOptimize(BF); 405 } 406 407 void ReorderBasicBlocks::runOnFunctions(BinaryContext &BC) { 408 if (opts::ReorderBlocks == ReorderBasicBlocks::LT_NONE) 409 return; 410 411 std::atomic<uint64_t> ModifiedFuncCount{0}; 412 413 ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { 414 modifyFunctionLayout(BF, opts::ReorderBlocks, opts::MinBranchClusters); 415 if (BF.hasLayoutChanged()) 416 ++ModifiedFuncCount; 417 }; 418 419 ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) { 420 return !shouldOptimize(BF); 421 }; 422 423 ParallelUtilities::runOnEachFunction( 424 BC, ParallelUtilities::SchedulingPolicy::SP_BB_LINEAR, WorkFun, SkipFunc, 425 "ReorderBasicBlocks"); 426 427 outs() << "BOLT-INFO: basic block reordering modified layout of " 428 << format("%zu (%.2lf%%) functions\n", ModifiedFuncCount.load(), 429 100.0 * ModifiedFuncCount.load() / 430 BC.getBinaryFunctions().size()); 431 432 if (opts::PrintFuncStat > 0) { 433 raw_ostream &OS = outs(); 434 // Copy all the values into vector in order to sort them 435 std::map<uint64_t, BinaryFunction &> ScoreMap; 436 auto &BFs = BC.getBinaryFunctions(); 437 for (auto It = BFs.begin(); It != BFs.end(); ++It) 438 ScoreMap.insert(std::pair<uint64_t, BinaryFunction &>( 439 It->second.getFunctionScore(), It->second)); 440 441 OS << "\nBOLT-INFO: Printing Function Statistics:\n\n"; 442 OS << " There are " << BFs.size() << " functions in total. \n"; 443 OS << " Number of functions being modified: " 444 << ModifiedFuncCount.load() << "\n"; 445 OS << " User asks for detailed information on top " 446 << opts::PrintFuncStat << " functions. (Ranked by function score)" 447 << "\n\n"; 448 uint64_t I = 0; 449 for (std::map<uint64_t, BinaryFunction &>::reverse_iterator Rit = 450 ScoreMap.rbegin(); 451 Rit != ScoreMap.rend() && I < opts::PrintFuncStat; ++Rit, ++I) { 452 BinaryFunction &Function = Rit->second; 453 454 OS << " Information for function of top: " << (I + 1) << ": \n"; 455 OS << " Function Score is: " << Function.getFunctionScore() 456 << "\n"; 457 OS << " There are " << Function.size() 458 << " number of blocks in this function.\n"; 459 OS << " There are " << Function.getInstructionCount() 460 << " number of instructions in this function.\n"; 461 OS << " The edit distance for this function is: " 462 << Function.getEditDistance() << "\n\n"; 463 } 464 } 465 } 466 467 void ReorderBasicBlocks::modifyFunctionLayout(BinaryFunction &BF, 468 LayoutType Type, 469 bool MinBranchClusters) const { 470 if (BF.size() == 0 || Type == LT_NONE) 471 return; 472 473 BinaryFunction::BasicBlockOrderType NewLayout; 474 std::unique_ptr<ReorderAlgorithm> Algo; 475 476 // Cannot do optimal layout without profile. 477 if (Type != LT_REVERSE && !BF.hasValidProfile()) 478 return; 479 480 if (Type == LT_REVERSE) { 481 Algo.reset(new ReverseReorderAlgorithm()); 482 } else if (BF.size() <= opts::TSPThreshold && Type != LT_OPTIMIZE_SHUFFLE) { 483 // Work on optimal solution if problem is small enough 484 LLVM_DEBUG(dbgs() << "finding optimal block layout for " << BF << "\n"); 485 Algo.reset(new TSPReorderAlgorithm()); 486 } else { 487 LLVM_DEBUG(dbgs() << "running block layout heuristics on " << BF << "\n"); 488 489 std::unique_ptr<ClusterAlgorithm> CAlgo; 490 if (MinBranchClusters) 491 CAlgo.reset(new MinBranchGreedyClusterAlgorithm()); 492 else 493 CAlgo.reset(new PHGreedyClusterAlgorithm()); 494 495 switch (Type) { 496 case LT_OPTIMIZE: 497 Algo.reset(new OptimizeReorderAlgorithm(std::move(CAlgo))); 498 break; 499 500 case LT_OPTIMIZE_BRANCH: 501 Algo.reset(new OptimizeBranchReorderAlgorithm(std::move(CAlgo))); 502 break; 503 504 case LT_OPTIMIZE_CACHE: 505 Algo.reset(new OptimizeCacheReorderAlgorithm(std::move(CAlgo))); 506 break; 507 508 case LT_OPTIMIZE_EXT_TSP: 509 Algo.reset(new ExtTSPReorderAlgorithm()); 510 break; 511 512 case LT_OPTIMIZE_SHUFFLE: 513 Algo.reset(new RandomClusterReorderAlgorithm(std::move(CAlgo))); 514 break; 515 516 default: 517 llvm_unreachable("unexpected layout type"); 518 } 519 } 520 521 Algo->reorderBasicBlocks(BF, NewLayout); 522 523 BF.updateBasicBlockLayout(NewLayout); 524 } 525 526 void FixupBranches::runOnFunctions(BinaryContext &BC) { 527 for (auto &It : BC.getBinaryFunctions()) { 528 BinaryFunction &Function = It.second; 529 if (!BC.shouldEmit(Function) || !Function.isSimple()) 530 continue; 531 532 Function.fixBranches(); 533 } 534 } 535 536 void FinalizeFunctions::runOnFunctions(BinaryContext &BC) { 537 ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { 538 if (!BF.finalizeCFIState()) { 539 if (BC.HasRelocations) { 540 errs() << "BOLT-ERROR: unable to fix CFI state for function " << BF 541 << ". Exiting.\n"; 542 exit(1); 543 } 544 BF.setSimple(false); 545 return; 546 } 547 548 BF.setFinalized(); 549 550 // Update exception handling information. 551 BF.updateEHRanges(); 552 }; 553 554 ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) { 555 return !BC.shouldEmit(BF); 556 }; 557 558 ParallelUtilities::runOnEachFunction( 559 BC, ParallelUtilities::SchedulingPolicy::SP_CONSTANT, WorkFun, 560 SkipPredicate, "FinalizeFunctions"); 561 } 562 563 void CheckLargeFunctions::runOnFunctions(BinaryContext &BC) { 564 if (BC.HasRelocations) 565 return; 566 567 if (!opts::UpdateDebugSections) 568 return; 569 570 // If the function wouldn't fit, mark it as non-simple. Otherwise, we may emit 571 // incorrect debug info. 572 ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { 573 uint64_t HotSize, ColdSize; 574 std::tie(HotSize, ColdSize) = 575 BC.calculateEmittedSize(BF, /*FixBranches=*/false); 576 if (HotSize > BF.getMaxSize()) 577 BF.setSimple(false); 578 }; 579 580 ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) { 581 return !shouldOptimize(BF); 582 }; 583 584 ParallelUtilities::runOnEachFunction( 585 BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun, 586 SkipFunc, "CheckLargeFunctions"); 587 } 588 589 bool CheckLargeFunctions::shouldOptimize(const BinaryFunction &BF) const { 590 // Unlike other passes, allow functions in non-CFG state. 591 return BF.isSimple() && !BF.isIgnored(); 592 } 593 594 void LowerAnnotations::runOnFunctions(BinaryContext &BC) { 595 std::vector<std::pair<MCInst *, uint32_t>> PreservedOffsetAnnotations; 596 597 for (auto &It : BC.getBinaryFunctions()) { 598 BinaryFunction &BF = It.second; 599 int64_t CurrentGnuArgsSize = 0; 600 601 // Have we crossed hot/cold border for split functions? 602 bool SeenCold = false; 603 604 for (BinaryBasicBlock *BB : BF.layout()) { 605 if (BB->isCold() && !SeenCold) { 606 SeenCold = true; 607 CurrentGnuArgsSize = 0; 608 } 609 610 // First convert GnuArgsSize annotations into CFIs. This may change instr 611 // pointers, so do it before recording ptrs for preserved annotations 612 if (BF.usesGnuArgsSize()) { 613 for (auto II = BB->begin(); II != BB->end(); ++II) { 614 if (!BC.MIB->isInvoke(*II)) 615 continue; 616 const int64_t NewGnuArgsSize = BC.MIB->getGnuArgsSize(*II); 617 assert(NewGnuArgsSize >= 0 && "expected non-negative GNU_args_size"); 618 if (NewGnuArgsSize != CurrentGnuArgsSize) { 619 auto InsertII = BF.addCFIInstruction( 620 BB, II, 621 MCCFIInstruction::createGnuArgsSize(nullptr, NewGnuArgsSize)); 622 CurrentGnuArgsSize = NewGnuArgsSize; 623 II = std::next(InsertII); 624 } 625 } 626 } 627 628 // Now record preserved annotations separately and then strip annotations. 629 for (auto II = BB->begin(); II != BB->end(); ++II) { 630 if (BF.requiresAddressTranslation() && BC.MIB->getOffset(*II)) 631 PreservedOffsetAnnotations.emplace_back(&(*II), 632 *BC.MIB->getOffset(*II)); 633 BC.MIB->stripAnnotations(*II); 634 } 635 } 636 } 637 for (BinaryFunction *BF : BC.getInjectedBinaryFunctions()) 638 for (BinaryBasicBlock &BB : *BF) 639 for (MCInst &Instruction : BB) 640 BC.MIB->stripAnnotations(Instruction); 641 642 // Release all memory taken by annotations 643 BC.MIB->freeAnnotations(); 644 645 // Reinsert preserved annotations we need during code emission. 646 for (const std::pair<MCInst *, uint32_t> &Item : PreservedOffsetAnnotations) 647 BC.MIB->setOffset(*Item.first, Item.second); 648 } 649 650 namespace { 651 652 // This peephole fixes jump instructions that jump to another basic 653 // block with a single jump instruction, e.g. 654 // 655 // B0: ... 656 // jmp B1 (or jcc B1) 657 // 658 // B1: jmp B2 659 // 660 // -> 661 // 662 // B0: ... 663 // jmp B2 (or jcc B2) 664 // 665 uint64_t fixDoubleJumps(BinaryFunction &Function, bool MarkInvalid) { 666 uint64_t NumDoubleJumps = 0; 667 668 MCContext *Ctx = Function.getBinaryContext().Ctx.get(); 669 MCPlusBuilder *MIB = Function.getBinaryContext().MIB.get(); 670 for (BinaryBasicBlock &BB : Function) { 671 auto checkAndPatch = [&](BinaryBasicBlock *Pred, BinaryBasicBlock *Succ, 672 const MCSymbol *SuccSym) { 673 // Ignore infinite loop jumps or fallthrough tail jumps. 674 if (Pred == Succ || Succ == &BB) 675 return false; 676 677 if (Succ) { 678 const MCSymbol *TBB = nullptr; 679 const MCSymbol *FBB = nullptr; 680 MCInst *CondBranch = nullptr; 681 MCInst *UncondBranch = nullptr; 682 bool Res = Pred->analyzeBranch(TBB, FBB, CondBranch, UncondBranch); 683 if (!Res) { 684 LLVM_DEBUG(dbgs() << "analyzeBranch failed in peepholes in block:\n"; 685 Pred->dump()); 686 return false; 687 } 688 Pred->replaceSuccessor(&BB, Succ); 689 690 // We must patch up any existing branch instructions to match up 691 // with the new successor. 692 assert((CondBranch || (!CondBranch && Pred->succ_size() == 1)) && 693 "Predecessor block has inconsistent number of successors"); 694 if (CondBranch && MIB->getTargetSymbol(*CondBranch) == BB.getLabel()) { 695 MIB->replaceBranchTarget(*CondBranch, Succ->getLabel(), Ctx); 696 } else if (UncondBranch && 697 MIB->getTargetSymbol(*UncondBranch) == BB.getLabel()) { 698 MIB->replaceBranchTarget(*UncondBranch, Succ->getLabel(), Ctx); 699 } else if (!UncondBranch) { 700 assert(Function.getBasicBlockAfter(Pred, false) != Succ && 701 "Don't add an explicit jump to a fallthrough block."); 702 Pred->addBranchInstruction(Succ); 703 } 704 } else { 705 // Succ will be null in the tail call case. In this case we 706 // need to explicitly add a tail call instruction. 707 MCInst *Branch = Pred->getLastNonPseudoInstr(); 708 if (Branch && MIB->isUnconditionalBranch(*Branch)) { 709 assert(MIB->getTargetSymbol(*Branch) == BB.getLabel()); 710 Pred->removeSuccessor(&BB); 711 Pred->eraseInstruction(Pred->findInstruction(Branch)); 712 Pred->addTailCallInstruction(SuccSym); 713 } else { 714 return false; 715 } 716 } 717 718 ++NumDoubleJumps; 719 LLVM_DEBUG(dbgs() << "Removed double jump in " << Function << " from " 720 << Pred->getName() << " -> " << BB.getName() << " to " 721 << Pred->getName() << " -> " << SuccSym->getName() 722 << (!Succ ? " (tail)\n" : "\n")); 723 724 return true; 725 }; 726 727 if (BB.getNumNonPseudos() != 1 || BB.isLandingPad()) 728 continue; 729 730 MCInst *Inst = BB.getFirstNonPseudoInstr(); 731 const bool IsTailCall = MIB->isTailCall(*Inst); 732 733 if (!MIB->isUnconditionalBranch(*Inst) && !IsTailCall) 734 continue; 735 736 // If we operate after SCTC make sure it's not a conditional tail call. 737 if (IsTailCall && MIB->isConditionalBranch(*Inst)) 738 continue; 739 740 const MCSymbol *SuccSym = MIB->getTargetSymbol(*Inst); 741 BinaryBasicBlock *Succ = BB.getSuccessor(); 742 743 if (((!Succ || &BB == Succ) && !IsTailCall) || (IsTailCall && !SuccSym)) 744 continue; 745 746 std::vector<BinaryBasicBlock *> Preds = {BB.pred_begin(), BB.pred_end()}; 747 748 for (BinaryBasicBlock *Pred : Preds) { 749 if (Pred->isLandingPad()) 750 continue; 751 752 if (Pred->getSuccessor() == &BB || 753 (Pred->getConditionalSuccessor(true) == &BB && !IsTailCall) || 754 Pred->getConditionalSuccessor(false) == &BB) 755 if (checkAndPatch(Pred, Succ, SuccSym) && MarkInvalid) 756 BB.markValid(BB.pred_size() != 0 || BB.isLandingPad() || 757 BB.isEntryPoint()); 758 } 759 } 760 761 return NumDoubleJumps; 762 } 763 } // namespace 764 765 bool SimplifyConditionalTailCalls::shouldRewriteBranch( 766 const BinaryBasicBlock *PredBB, const MCInst &CondBranch, 767 const BinaryBasicBlock *BB, const bool DirectionFlag) { 768 if (BeenOptimized.count(PredBB)) 769 return false; 770 771 const bool IsForward = BinaryFunction::isForwardBranch(PredBB, BB); 772 773 if (IsForward) 774 ++NumOrigForwardBranches; 775 else 776 ++NumOrigBackwardBranches; 777 778 if (opts::SctcMode == opts::SctcAlways) 779 return true; 780 781 if (opts::SctcMode == opts::SctcPreserveDirection) 782 return IsForward == DirectionFlag; 783 784 const ErrorOr<std::pair<double, double>> Frequency = 785 PredBB->getBranchStats(BB); 786 787 // It's ok to rewrite the conditional branch if the new target will be 788 // a backward branch. 789 790 // If no data available for these branches, then it should be ok to 791 // do the optimization since it will reduce code size. 792 if (Frequency.getError()) 793 return true; 794 795 // TODO: should this use misprediction frequency instead? 796 const bool Result = (IsForward && Frequency.get().first >= 0.5) || 797 (!IsForward && Frequency.get().first <= 0.5); 798 799 return Result == DirectionFlag; 800 } 801 802 uint64_t SimplifyConditionalTailCalls::fixTailCalls(BinaryFunction &BF) { 803 // Need updated indices to correctly detect branch' direction. 804 BF.updateLayoutIndices(); 805 BF.markUnreachableBlocks(); 806 807 MCPlusBuilder *MIB = BF.getBinaryContext().MIB.get(); 808 MCContext *Ctx = BF.getBinaryContext().Ctx.get(); 809 uint64_t NumLocalCTCCandidates = 0; 810 uint64_t NumLocalCTCs = 0; 811 uint64_t LocalCTCTakenCount = 0; 812 uint64_t LocalCTCExecCount = 0; 813 std::vector<std::pair<BinaryBasicBlock *, const BinaryBasicBlock *>> 814 NeedsUncondBranch; 815 816 // Will block be deleted by UCE? 817 auto isValid = [](const BinaryBasicBlock *BB) { 818 return (BB->pred_size() != 0 || BB->isLandingPad() || BB->isEntryPoint()); 819 }; 820 821 for (BinaryBasicBlock *BB : BF.layout()) { 822 // Locate BB with a single direct tail-call instruction. 823 if (BB->getNumNonPseudos() != 1) 824 continue; 825 826 MCInst *Instr = BB->getFirstNonPseudoInstr(); 827 if (!MIB->isTailCall(*Instr) || MIB->isConditionalBranch(*Instr)) 828 continue; 829 830 const MCSymbol *CalleeSymbol = MIB->getTargetSymbol(*Instr); 831 if (!CalleeSymbol) 832 continue; 833 834 // Detect direction of the possible conditional tail call. 835 const bool IsForwardCTC = BF.isForwardCall(CalleeSymbol); 836 837 // Iterate through all predecessors. 838 for (BinaryBasicBlock *PredBB : BB->predecessors()) { 839 BinaryBasicBlock *CondSucc = PredBB->getConditionalSuccessor(true); 840 if (!CondSucc) 841 continue; 842 843 ++NumLocalCTCCandidates; 844 845 const MCSymbol *TBB = nullptr; 846 const MCSymbol *FBB = nullptr; 847 MCInst *CondBranch = nullptr; 848 MCInst *UncondBranch = nullptr; 849 bool Result = PredBB->analyzeBranch(TBB, FBB, CondBranch, UncondBranch); 850 851 // analyzeBranch() can fail due to unusual branch instructions, e.g. jrcxz 852 if (!Result) { 853 LLVM_DEBUG(dbgs() << "analyzeBranch failed in SCTC in block:\n"; 854 PredBB->dump()); 855 continue; 856 } 857 858 assert(Result && "internal error analyzing conditional branch"); 859 assert(CondBranch && "conditional branch expected"); 860 861 // It's possible that PredBB is also a successor to BB that may have 862 // been processed by a previous iteration of the SCTC loop, in which 863 // case it may have been marked invalid. We should skip rewriting in 864 // this case. 865 if (!PredBB->isValid()) { 866 assert(PredBB->isSuccessor(BB) && 867 "PredBB should be valid if it is not a successor to BB"); 868 continue; 869 } 870 871 // We don't want to reverse direction of the branch in new order 872 // without further profile analysis. 873 const bool DirectionFlag = CondSucc == BB ? IsForwardCTC : !IsForwardCTC; 874 if (!shouldRewriteBranch(PredBB, *CondBranch, BB, DirectionFlag)) 875 continue; 876 877 // Record this block so that we don't try to optimize it twice. 878 BeenOptimized.insert(PredBB); 879 880 uint64_t Count = 0; 881 if (CondSucc != BB) { 882 // Patch the new target address into the conditional branch. 883 MIB->reverseBranchCondition(*CondBranch, CalleeSymbol, Ctx); 884 // Since we reversed the condition on the branch we need to change 885 // the target for the unconditional branch or add a unconditional 886 // branch to the old target. This has to be done manually since 887 // fixupBranches is not called after SCTC. 888 NeedsUncondBranch.emplace_back(PredBB, CondSucc); 889 Count = PredBB->getFallthroughBranchInfo().Count; 890 } else { 891 // Change destination of the conditional branch. 892 MIB->replaceBranchTarget(*CondBranch, CalleeSymbol, Ctx); 893 Count = PredBB->getTakenBranchInfo().Count; 894 } 895 const uint64_t CTCTakenFreq = 896 Count == BinaryBasicBlock::COUNT_NO_PROFILE ? 0 : Count; 897 898 // Annotate it, so "isCall" returns true for this jcc 899 MIB->setConditionalTailCall(*CondBranch); 900 // Add info abount the conditional tail call frequency, otherwise this 901 // info will be lost when we delete the associated BranchInfo entry 902 auto &CTCAnnotation = 903 MIB->getOrCreateAnnotationAs<uint64_t>(*CondBranch, "CTCTakenCount"); 904 CTCAnnotation = CTCTakenFreq; 905 906 // Remove the unused successor which may be eliminated later 907 // if there are no other users. 908 PredBB->removeSuccessor(BB); 909 // Update BB execution count 910 if (CTCTakenFreq && CTCTakenFreq <= BB->getKnownExecutionCount()) 911 BB->setExecutionCount(BB->getExecutionCount() - CTCTakenFreq); 912 else if (CTCTakenFreq > BB->getKnownExecutionCount()) 913 BB->setExecutionCount(0); 914 915 ++NumLocalCTCs; 916 LocalCTCTakenCount += CTCTakenFreq; 917 LocalCTCExecCount += PredBB->getKnownExecutionCount(); 918 } 919 920 // Remove the block from CFG if all predecessors were removed. 921 BB->markValid(isValid(BB)); 922 } 923 924 // Add unconditional branches at the end of BBs to new successors 925 // as long as the successor is not a fallthrough. 926 for (auto &Entry : NeedsUncondBranch) { 927 BinaryBasicBlock *PredBB = Entry.first; 928 const BinaryBasicBlock *CondSucc = Entry.second; 929 930 const MCSymbol *TBB = nullptr; 931 const MCSymbol *FBB = nullptr; 932 MCInst *CondBranch = nullptr; 933 MCInst *UncondBranch = nullptr; 934 PredBB->analyzeBranch(TBB, FBB, CondBranch, UncondBranch); 935 936 // Find the next valid block. Invalid blocks will be deleted 937 // so they shouldn't be considered fallthrough targets. 938 const BinaryBasicBlock *NextBlock = BF.getBasicBlockAfter(PredBB, false); 939 while (NextBlock && !isValid(NextBlock)) 940 NextBlock = BF.getBasicBlockAfter(NextBlock, false); 941 942 // Get the unconditional successor to this block. 943 const BinaryBasicBlock *PredSucc = PredBB->getSuccessor(); 944 assert(PredSucc && "The other branch should be a tail call"); 945 946 const bool HasFallthrough = (NextBlock && PredSucc == NextBlock); 947 948 if (UncondBranch) { 949 if (HasFallthrough) 950 PredBB->eraseInstruction(PredBB->findInstruction(UncondBranch)); 951 else 952 MIB->replaceBranchTarget(*UncondBranch, CondSucc->getLabel(), Ctx); 953 } else if (!HasFallthrough) { 954 MCInst Branch; 955 MIB->createUncondBranch(Branch, CondSucc->getLabel(), Ctx); 956 PredBB->addInstruction(Branch); 957 } 958 } 959 960 if (NumLocalCTCs > 0) { 961 NumDoubleJumps += fixDoubleJumps(BF, true); 962 // Clean-up unreachable tail-call blocks. 963 const std::pair<unsigned, uint64_t> Stats = BF.eraseInvalidBBs(); 964 DeletedBlocks += Stats.first; 965 DeletedBytes += Stats.second; 966 967 assert(BF.validateCFG()); 968 } 969 970 LLVM_DEBUG(dbgs() << "BOLT: created " << NumLocalCTCs 971 << " conditional tail calls from a total of " 972 << NumLocalCTCCandidates << " candidates in function " << BF 973 << ". CTCs execution count for this function is " 974 << LocalCTCExecCount << " and CTC taken count is " 975 << LocalCTCTakenCount << "\n";); 976 977 NumTailCallsPatched += NumLocalCTCs; 978 NumCandidateTailCalls += NumLocalCTCCandidates; 979 CTCExecCount += LocalCTCExecCount; 980 CTCTakenCount += LocalCTCTakenCount; 981 982 return NumLocalCTCs > 0; 983 } 984 985 void SimplifyConditionalTailCalls::runOnFunctions(BinaryContext &BC) { 986 if (!BC.isX86()) 987 return; 988 989 for (auto &It : BC.getBinaryFunctions()) { 990 BinaryFunction &Function = It.second; 991 992 if (!shouldOptimize(Function)) 993 continue; 994 995 if (fixTailCalls(Function)) { 996 Modified.insert(&Function); 997 Function.setHasCanonicalCFG(false); 998 } 999 } 1000 1001 outs() << "BOLT-INFO: SCTC: patched " << NumTailCallsPatched 1002 << " tail calls (" << NumOrigForwardBranches << " forward)" 1003 << " tail calls (" << NumOrigBackwardBranches << " backward)" 1004 << " from a total of " << NumCandidateTailCalls << " while removing " 1005 << NumDoubleJumps << " double jumps" 1006 << " and removing " << DeletedBlocks << " basic blocks" 1007 << " totalling " << DeletedBytes 1008 << " bytes of code. CTCs total execution count is " << CTCExecCount 1009 << " and the number of times CTCs are taken is " << CTCTakenCount 1010 << ".\n"; 1011 } 1012 1013 uint64_t ShortenInstructions::shortenInstructions(BinaryFunction &Function) { 1014 uint64_t Count = 0; 1015 const BinaryContext &BC = Function.getBinaryContext(); 1016 for (BinaryBasicBlock &BB : Function) { 1017 for (MCInst &Inst : BB) { 1018 MCInst OriginalInst; 1019 if (opts::Verbosity > 2) 1020 OriginalInst = Inst; 1021 1022 if (!BC.MIB->shortenInstruction(Inst, *BC.STI)) 1023 continue; 1024 1025 if (opts::Verbosity > 2) { 1026 BC.scopeLock(); 1027 outs() << "BOLT-INFO: shortening:\nBOLT-INFO: "; 1028 BC.printInstruction(outs(), OriginalInst, 0, &Function); 1029 outs() << "BOLT-INFO: to:"; 1030 BC.printInstruction(outs(), Inst, 0, &Function); 1031 } 1032 1033 ++Count; 1034 } 1035 } 1036 1037 return Count; 1038 } 1039 1040 void ShortenInstructions::runOnFunctions(BinaryContext &BC) { 1041 std::atomic<uint64_t> NumShortened{0}; 1042 if (!BC.isX86()) 1043 return; 1044 1045 ParallelUtilities::runOnEachFunction( 1046 BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, 1047 [&](BinaryFunction &BF) { NumShortened += shortenInstructions(BF); }, 1048 nullptr, "ShortenInstructions"); 1049 1050 outs() << "BOLT-INFO: " << NumShortened << " instructions were shortened\n"; 1051 } 1052 1053 void Peepholes::addTailcallTraps(BinaryFunction &Function) { 1054 MCPlusBuilder *MIB = Function.getBinaryContext().MIB.get(); 1055 for (BinaryBasicBlock &BB : Function) { 1056 MCInst *Inst = BB.getLastNonPseudoInstr(); 1057 if (Inst && MIB->isTailCall(*Inst) && MIB->isIndirectBranch(*Inst)) { 1058 MCInst Trap; 1059 if (MIB->createTrap(Trap)) { 1060 BB.addInstruction(Trap); 1061 ++TailCallTraps; 1062 } 1063 } 1064 } 1065 } 1066 1067 void Peepholes::removeUselessCondBranches(BinaryFunction &Function) { 1068 for (BinaryBasicBlock &BB : Function) { 1069 if (BB.succ_size() != 2) 1070 continue; 1071 1072 BinaryBasicBlock *CondBB = BB.getConditionalSuccessor(true); 1073 BinaryBasicBlock *UncondBB = BB.getConditionalSuccessor(false); 1074 if (CondBB != UncondBB) 1075 continue; 1076 1077 const MCSymbol *TBB = nullptr; 1078 const MCSymbol *FBB = nullptr; 1079 MCInst *CondBranch = nullptr; 1080 MCInst *UncondBranch = nullptr; 1081 bool Result = BB.analyzeBranch(TBB, FBB, CondBranch, UncondBranch); 1082 1083 // analyzeBranch() can fail due to unusual branch instructions, 1084 // e.g. jrcxz, or jump tables (indirect jump). 1085 if (!Result || !CondBranch) 1086 continue; 1087 1088 BB.removeDuplicateConditionalSuccessor(CondBranch); 1089 ++NumUselessCondBranches; 1090 } 1091 } 1092 1093 void Peepholes::runOnFunctions(BinaryContext &BC) { 1094 const char Opts = 1095 std::accumulate(opts::Peepholes.begin(), opts::Peepholes.end(), 0, 1096 [](const char A, const PeepholeOpts B) { return A | B; }); 1097 if (Opts == PEEP_NONE) 1098 return; 1099 1100 for (auto &It : BC.getBinaryFunctions()) { 1101 BinaryFunction &Function = It.second; 1102 if (shouldOptimize(Function)) { 1103 if (Opts & PEEP_DOUBLE_JUMPS) 1104 NumDoubleJumps += fixDoubleJumps(Function, false); 1105 if (Opts & PEEP_TAILCALL_TRAPS) 1106 addTailcallTraps(Function); 1107 if (Opts & PEEP_USELESS_BRANCHES) 1108 removeUselessCondBranches(Function); 1109 assert(Function.validateCFG()); 1110 } 1111 } 1112 outs() << "BOLT-INFO: Peephole: " << NumDoubleJumps 1113 << " double jumps patched.\n" 1114 << "BOLT-INFO: Peephole: " << TailCallTraps 1115 << " tail call traps inserted.\n" 1116 << "BOLT-INFO: Peephole: " << NumUselessCondBranches 1117 << " useless conditional branches removed.\n"; 1118 } 1119 1120 bool SimplifyRODataLoads::simplifyRODataLoads(BinaryFunction &BF) { 1121 BinaryContext &BC = BF.getBinaryContext(); 1122 MCPlusBuilder *MIB = BC.MIB.get(); 1123 1124 uint64_t NumLocalLoadsSimplified = 0; 1125 uint64_t NumDynamicLocalLoadsSimplified = 0; 1126 uint64_t NumLocalLoadsFound = 0; 1127 uint64_t NumDynamicLocalLoadsFound = 0; 1128 1129 for (BinaryBasicBlock *BB : BF.layout()) { 1130 for (MCInst &Inst : *BB) { 1131 unsigned Opcode = Inst.getOpcode(); 1132 const MCInstrDesc &Desc = BC.MII->get(Opcode); 1133 1134 // Skip instructions that do not load from memory. 1135 if (!Desc.mayLoad()) 1136 continue; 1137 1138 // Try to statically evaluate the target memory address; 1139 uint64_t TargetAddress; 1140 1141 if (MIB->hasPCRelOperand(Inst)) { 1142 // Try to find the symbol that corresponds to the PC-relative operand. 1143 MCOperand *DispOpI = MIB->getMemOperandDisp(Inst); 1144 assert(DispOpI != Inst.end() && "expected PC-relative displacement"); 1145 assert(DispOpI->isExpr() && 1146 "found PC-relative with non-symbolic displacement"); 1147 1148 // Get displacement symbol. 1149 const MCSymbol *DisplSymbol; 1150 uint64_t DisplOffset; 1151 1152 std::tie(DisplSymbol, DisplOffset) = 1153 MIB->getTargetSymbolInfo(DispOpI->getExpr()); 1154 1155 if (!DisplSymbol) 1156 continue; 1157 1158 // Look up the symbol address in the global symbols map of the binary 1159 // context object. 1160 BinaryData *BD = BC.getBinaryDataByName(DisplSymbol->getName()); 1161 if (!BD) 1162 continue; 1163 TargetAddress = BD->getAddress() + DisplOffset; 1164 } else if (!MIB->evaluateMemOperandTarget(Inst, TargetAddress)) { 1165 continue; 1166 } 1167 1168 // Get the contents of the section containing the target address of the 1169 // memory operand. We are only interested in read-only sections. 1170 ErrorOr<BinarySection &> DataSection = 1171 BC.getSectionForAddress(TargetAddress); 1172 if (!DataSection || !DataSection->isReadOnly()) 1173 continue; 1174 1175 if (BC.getRelocationAt(TargetAddress) || 1176 BC.getDynamicRelocationAt(TargetAddress)) 1177 continue; 1178 1179 uint32_t Offset = TargetAddress - DataSection->getAddress(); 1180 StringRef ConstantData = DataSection->getContents(); 1181 1182 ++NumLocalLoadsFound; 1183 if (BB->hasProfile()) 1184 NumDynamicLocalLoadsFound += BB->getExecutionCount(); 1185 1186 if (MIB->replaceMemOperandWithImm(Inst, ConstantData, Offset)) { 1187 ++NumLocalLoadsSimplified; 1188 if (BB->hasProfile()) 1189 NumDynamicLocalLoadsSimplified += BB->getExecutionCount(); 1190 } 1191 } 1192 } 1193 1194 NumLoadsFound += NumLocalLoadsFound; 1195 NumDynamicLoadsFound += NumDynamicLocalLoadsFound; 1196 NumLoadsSimplified += NumLocalLoadsSimplified; 1197 NumDynamicLoadsSimplified += NumDynamicLocalLoadsSimplified; 1198 1199 return NumLocalLoadsSimplified > 0; 1200 } 1201 1202 void SimplifyRODataLoads::runOnFunctions(BinaryContext &BC) { 1203 for (auto &It : BC.getBinaryFunctions()) { 1204 BinaryFunction &Function = It.second; 1205 if (shouldOptimize(Function) && simplifyRODataLoads(Function)) 1206 Modified.insert(&Function); 1207 } 1208 1209 outs() << "BOLT-INFO: simplified " << NumLoadsSimplified << " out of " 1210 << NumLoadsFound << " loads from a statically computed address.\n" 1211 << "BOLT-INFO: dynamic loads simplified: " << NumDynamicLoadsSimplified 1212 << "\n" 1213 << "BOLT-INFO: dynamic loads found: " << NumDynamicLoadsFound << "\n"; 1214 } 1215 1216 void AssignSections::runOnFunctions(BinaryContext &BC) { 1217 for (BinaryFunction *Function : BC.getInjectedBinaryFunctions()) { 1218 Function->setCodeSectionName(BC.getInjectedCodeSectionName()); 1219 Function->setColdCodeSectionName(BC.getInjectedColdCodeSectionName()); 1220 } 1221 1222 // In non-relocation mode functions have pre-assigned section names. 1223 if (!BC.HasRelocations) 1224 return; 1225 1226 const bool UseColdSection = 1227 BC.NumProfiledFuncs > 0 || 1228 opts::ReorderFunctions == ReorderFunctions::RT_USER; 1229 for (auto &BFI : BC.getBinaryFunctions()) { 1230 BinaryFunction &Function = BFI.second; 1231 if (opts::isHotTextMover(Function)) { 1232 Function.setCodeSectionName(BC.getHotTextMoverSectionName()); 1233 Function.setColdCodeSectionName(BC.getHotTextMoverSectionName()); 1234 continue; 1235 } 1236 1237 if (!UseColdSection || Function.hasValidIndex() || 1238 Function.hasValidProfile()) 1239 Function.setCodeSectionName(BC.getMainCodeSectionName()); 1240 else 1241 Function.setCodeSectionName(BC.getColdCodeSectionName()); 1242 1243 if (Function.isSplit()) 1244 Function.setColdCodeSectionName(BC.getColdCodeSectionName()); 1245 } 1246 } 1247 1248 void PrintProfileStats::runOnFunctions(BinaryContext &BC) { 1249 double FlowImbalanceMean = 0.0; 1250 size_t NumBlocksConsidered = 0; 1251 double WorstBias = 0.0; 1252 const BinaryFunction *WorstBiasFunc = nullptr; 1253 1254 // For each function CFG, we fill an IncomingMap with the sum of the frequency 1255 // of incoming edges for each BB. Likewise for each OutgoingMap and the sum 1256 // of the frequency of outgoing edges. 1257 using FlowMapTy = std::unordered_map<const BinaryBasicBlock *, uint64_t>; 1258 std::unordered_map<const BinaryFunction *, FlowMapTy> TotalIncomingMaps; 1259 std::unordered_map<const BinaryFunction *, FlowMapTy> TotalOutgoingMaps; 1260 1261 // Compute mean 1262 for (const auto &BFI : BC.getBinaryFunctions()) { 1263 const BinaryFunction &Function = BFI.second; 1264 if (Function.empty() || !Function.isSimple()) 1265 continue; 1266 FlowMapTy &IncomingMap = TotalIncomingMaps[&Function]; 1267 FlowMapTy &OutgoingMap = TotalOutgoingMaps[&Function]; 1268 for (const BinaryBasicBlock &BB : Function) { 1269 uint64_t TotalOutgoing = 0ULL; 1270 auto SuccBIIter = BB.branch_info_begin(); 1271 for (BinaryBasicBlock *Succ : BB.successors()) { 1272 uint64_t Count = SuccBIIter->Count; 1273 if (Count == BinaryBasicBlock::COUNT_NO_PROFILE || Count == 0) { 1274 ++SuccBIIter; 1275 continue; 1276 } 1277 TotalOutgoing += Count; 1278 IncomingMap[Succ] += Count; 1279 ++SuccBIIter; 1280 } 1281 OutgoingMap[&BB] = TotalOutgoing; 1282 } 1283 1284 size_t NumBlocks = 0; 1285 double Mean = 0.0; 1286 for (const BinaryBasicBlock &BB : Function) { 1287 // Do not compute score for low frequency blocks, entry or exit blocks 1288 if (IncomingMap[&BB] < 100 || OutgoingMap[&BB] == 0 || BB.isEntryPoint()) 1289 continue; 1290 ++NumBlocks; 1291 const double Difference = (double)OutgoingMap[&BB] - IncomingMap[&BB]; 1292 Mean += fabs(Difference / IncomingMap[&BB]); 1293 } 1294 1295 FlowImbalanceMean += Mean; 1296 NumBlocksConsidered += NumBlocks; 1297 if (!NumBlocks) 1298 continue; 1299 double FuncMean = Mean / NumBlocks; 1300 if (FuncMean > WorstBias) { 1301 WorstBias = FuncMean; 1302 WorstBiasFunc = &Function; 1303 } 1304 } 1305 if (NumBlocksConsidered > 0) 1306 FlowImbalanceMean /= NumBlocksConsidered; 1307 1308 // Compute standard deviation 1309 NumBlocksConsidered = 0; 1310 double FlowImbalanceVar = 0.0; 1311 for (const auto &BFI : BC.getBinaryFunctions()) { 1312 const BinaryFunction &Function = BFI.second; 1313 if (Function.empty() || !Function.isSimple()) 1314 continue; 1315 FlowMapTy &IncomingMap = TotalIncomingMaps[&Function]; 1316 FlowMapTy &OutgoingMap = TotalOutgoingMaps[&Function]; 1317 for (const BinaryBasicBlock &BB : Function) { 1318 if (IncomingMap[&BB] < 100 || OutgoingMap[&BB] == 0) 1319 continue; 1320 ++NumBlocksConsidered; 1321 const double Difference = (double)OutgoingMap[&BB] - IncomingMap[&BB]; 1322 FlowImbalanceVar += 1323 pow(fabs(Difference / IncomingMap[&BB]) - FlowImbalanceMean, 2); 1324 } 1325 } 1326 if (NumBlocksConsidered) { 1327 FlowImbalanceVar /= NumBlocksConsidered; 1328 FlowImbalanceVar = sqrt(FlowImbalanceVar); 1329 } 1330 1331 // Report to user 1332 outs() << format("BOLT-INFO: Profile bias score: %.4lf%% StDev: %.4lf%%\n", 1333 (100.0 * FlowImbalanceMean), (100.0 * FlowImbalanceVar)); 1334 if (WorstBiasFunc && opts::Verbosity >= 1) { 1335 outs() << "Worst average bias observed in " << WorstBiasFunc->getPrintName() 1336 << "\n"; 1337 LLVM_DEBUG(WorstBiasFunc->dump()); 1338 } 1339 } 1340 1341 void PrintProgramStats::runOnFunctions(BinaryContext &BC) { 1342 uint64_t NumRegularFunctions = 0; 1343 uint64_t NumStaleProfileFunctions = 0; 1344 uint64_t NumNonSimpleProfiledFunctions = 0; 1345 uint64_t NumUnknownControlFlowFunctions = 0; 1346 uint64_t TotalSampleCount = 0; 1347 uint64_t StaleSampleCount = 0; 1348 std::vector<const BinaryFunction *> ProfiledFunctions; 1349 const char *StaleFuncsHeader = "BOLT-INFO: Functions with stale profile:\n"; 1350 for (auto &BFI : BC.getBinaryFunctions()) { 1351 const BinaryFunction &Function = BFI.second; 1352 1353 // Ignore PLT functions for stats. 1354 if (Function.isPLTFunction()) 1355 continue; 1356 1357 ++NumRegularFunctions; 1358 1359 if (!Function.isSimple()) { 1360 if (Function.hasProfile()) 1361 ++NumNonSimpleProfiledFunctions; 1362 continue; 1363 } 1364 1365 if (Function.hasUnknownControlFlow()) { 1366 if (opts::PrintUnknownCFG) 1367 Function.dump(); 1368 else if (opts::PrintUnknown) 1369 errs() << "function with unknown control flow: " << Function << '\n'; 1370 1371 ++NumUnknownControlFlowFunctions; 1372 } 1373 1374 if (!Function.hasProfile()) 1375 continue; 1376 1377 uint64_t SampleCount = Function.getRawBranchCount(); 1378 TotalSampleCount += SampleCount; 1379 1380 if (Function.hasValidProfile()) { 1381 ProfiledFunctions.push_back(&Function); 1382 } else { 1383 if (opts::ReportStaleFuncs) { 1384 outs() << StaleFuncsHeader; 1385 StaleFuncsHeader = ""; 1386 outs() << " " << Function << '\n'; 1387 } 1388 ++NumStaleProfileFunctions; 1389 StaleSampleCount += SampleCount; 1390 } 1391 } 1392 BC.NumProfiledFuncs = ProfiledFunctions.size(); 1393 1394 const size_t NumAllProfiledFunctions = 1395 ProfiledFunctions.size() + NumStaleProfileFunctions; 1396 outs() << "BOLT-INFO: " << NumAllProfiledFunctions << " out of " 1397 << NumRegularFunctions << " functions in the binary (" 1398 << format("%.1f", NumAllProfiledFunctions / 1399 (float)NumRegularFunctions * 100.0f) 1400 << "%) have non-empty execution profile\n"; 1401 if (NumNonSimpleProfiledFunctions) { 1402 outs() << "BOLT-INFO: " << NumNonSimpleProfiledFunctions << " function" 1403 << (NumNonSimpleProfiledFunctions == 1 ? "" : "s") 1404 << " with profile could not be optimized\n"; 1405 } 1406 if (NumStaleProfileFunctions) { 1407 const float PctStale = 1408 NumStaleProfileFunctions / (float)NumAllProfiledFunctions * 100.0f; 1409 auto printErrorOrWarning = [&]() { 1410 if (PctStale > opts::StaleThreshold) 1411 errs() << "BOLT-ERROR: "; 1412 else 1413 errs() << "BOLT-WARNING: "; 1414 }; 1415 printErrorOrWarning(); 1416 errs() << NumStaleProfileFunctions 1417 << format(" (%.1f%% of all profiled)", PctStale) << " function" 1418 << (NumStaleProfileFunctions == 1 ? "" : "s") 1419 << " have invalid (possibly stale) profile." 1420 " Use -report-stale to see the list.\n"; 1421 if (TotalSampleCount > 0) { 1422 printErrorOrWarning(); 1423 errs() << StaleSampleCount << " out of " << TotalSampleCount 1424 << " samples in the binary (" 1425 << format("%.1f", ((100.0f * StaleSampleCount) / TotalSampleCount)) 1426 << "%) belong to functions with invalid" 1427 " (possibly stale) profile.\n"; 1428 } 1429 if (PctStale > opts::StaleThreshold) { 1430 errs() << "BOLT-ERROR: stale functions exceed specified threshold of " 1431 << opts::StaleThreshold << "%. Exiting.\n"; 1432 exit(1); 1433 } 1434 } 1435 1436 if (const uint64_t NumUnusedObjects = BC.getNumUnusedProfiledObjects()) { 1437 outs() << "BOLT-INFO: profile for " << NumUnusedObjects 1438 << " objects was ignored\n"; 1439 } 1440 1441 if (ProfiledFunctions.size() > 10) { 1442 if (opts::Verbosity >= 1) { 1443 outs() << "BOLT-INFO: top called functions are:\n"; 1444 std::sort(ProfiledFunctions.begin(), ProfiledFunctions.end(), 1445 [](const BinaryFunction *A, const BinaryFunction *B) { 1446 return B->getExecutionCount() < A->getExecutionCount(); 1447 }); 1448 auto SFI = ProfiledFunctions.begin(); 1449 auto SFIend = ProfiledFunctions.end(); 1450 for (unsigned I = 0u; I < opts::TopCalledLimit && SFI != SFIend; 1451 ++SFI, ++I) 1452 outs() << " " << **SFI << " : " << (*SFI)->getExecutionCount() << '\n'; 1453 } 1454 } 1455 1456 if (!opts::PrintSortedBy.empty() && 1457 std::find(opts::PrintSortedBy.begin(), opts::PrintSortedBy.end(), 1458 DynoStats::FIRST_DYNO_STAT) == opts::PrintSortedBy.end()) { 1459 1460 std::vector<const BinaryFunction *> Functions; 1461 std::map<const BinaryFunction *, DynoStats> Stats; 1462 1463 for (const auto &BFI : BC.getBinaryFunctions()) { 1464 const BinaryFunction &BF = BFI.second; 1465 if (shouldOptimize(BF) && BF.hasValidProfile()) { 1466 Functions.push_back(&BF); 1467 Stats.emplace(&BF, getDynoStats(BF)); 1468 } 1469 } 1470 1471 const bool SortAll = 1472 std::find(opts::PrintSortedBy.begin(), opts::PrintSortedBy.end(), 1473 DynoStats::LAST_DYNO_STAT) != opts::PrintSortedBy.end(); 1474 1475 const bool Ascending = 1476 opts::DynoStatsSortOrderOpt == opts::DynoStatsSortOrder::Ascending; 1477 1478 if (SortAll) { 1479 std::stable_sort(Functions.begin(), Functions.end(), 1480 [Ascending, &Stats](const BinaryFunction *A, 1481 const BinaryFunction *B) { 1482 return Ascending ? Stats.at(A) < Stats.at(B) 1483 : Stats.at(B) < Stats.at(A); 1484 }); 1485 } else { 1486 std::stable_sort( 1487 Functions.begin(), Functions.end(), 1488 [Ascending, &Stats](const BinaryFunction *A, 1489 const BinaryFunction *B) { 1490 const DynoStats &StatsA = Stats.at(A); 1491 const DynoStats &StatsB = Stats.at(B); 1492 return Ascending ? StatsA.lessThan(StatsB, opts::PrintSortedBy) 1493 : StatsB.lessThan(StatsA, opts::PrintSortedBy); 1494 }); 1495 } 1496 1497 outs() << "BOLT-INFO: top functions sorted by "; 1498 if (SortAll) { 1499 outs() << "dyno stats"; 1500 } else { 1501 outs() << "("; 1502 bool PrintComma = false; 1503 for (const DynoStats::Category Category : opts::PrintSortedBy) { 1504 if (PrintComma) 1505 outs() << ", "; 1506 outs() << DynoStats::Description(Category); 1507 PrintComma = true; 1508 } 1509 outs() << ")"; 1510 } 1511 1512 outs() << " are:\n"; 1513 auto SFI = Functions.begin(); 1514 for (unsigned I = 0; I < 100 && SFI != Functions.end(); ++SFI, ++I) { 1515 const DynoStats Stats = getDynoStats(**SFI); 1516 outs() << " " << **SFI; 1517 if (!SortAll) { 1518 outs() << " ("; 1519 bool PrintComma = false; 1520 for (const DynoStats::Category Category : opts::PrintSortedBy) { 1521 if (PrintComma) 1522 outs() << ", "; 1523 outs() << dynoStatsOptName(Category) << "=" << Stats[Category]; 1524 PrintComma = true; 1525 } 1526 outs() << ")"; 1527 } 1528 outs() << "\n"; 1529 } 1530 } 1531 1532 if (!BC.TrappedFunctions.empty()) { 1533 errs() << "BOLT-WARNING: " << BC.TrappedFunctions.size() << " function" 1534 << (BC.TrappedFunctions.size() > 1 ? "s" : "") 1535 << " will trap on entry. Use -trap-avx512=0 to disable" 1536 " traps."; 1537 if (opts::Verbosity >= 1 || BC.TrappedFunctions.size() <= 5) { 1538 errs() << '\n'; 1539 for (const BinaryFunction *Function : BC.TrappedFunctions) 1540 errs() << " " << *Function << '\n'; 1541 } else { 1542 errs() << " Use -v=1 to see the list.\n"; 1543 } 1544 } 1545 1546 // Print information on missed macro-fusion opportunities seen on input. 1547 if (BC.MissedMacroFusionPairs) { 1548 outs() << "BOLT-INFO: the input contains " << BC.MissedMacroFusionPairs 1549 << " (dynamic count : " << BC.MissedMacroFusionExecCount 1550 << ") opportunities for macro-fusion optimization"; 1551 switch (opts::AlignMacroOpFusion) { 1552 case MFT_NONE: 1553 outs() << ". Use -align-macro-fusion to fix.\n"; 1554 break; 1555 case MFT_HOT: 1556 outs() << ". Will fix instances on a hot path.\n"; 1557 break; 1558 case MFT_ALL: 1559 outs() << " that are going to be fixed\n"; 1560 break; 1561 } 1562 } 1563 1564 // Collect and print information about suboptimal code layout on input. 1565 if (opts::ReportBadLayout) { 1566 std::vector<const BinaryFunction *> SuboptimalFuncs; 1567 for (auto &BFI : BC.getBinaryFunctions()) { 1568 const BinaryFunction &BF = BFI.second; 1569 if (!BF.hasValidProfile()) 1570 continue; 1571 1572 const uint64_t HotThreshold = 1573 std::max<uint64_t>(BF.getKnownExecutionCount(), 1); 1574 bool HotSeen = false; 1575 for (const BinaryBasicBlock *BB : BF.rlayout()) { 1576 if (!HotSeen && BB->getKnownExecutionCount() > HotThreshold) { 1577 HotSeen = true; 1578 continue; 1579 } 1580 if (HotSeen && BB->getKnownExecutionCount() == 0) { 1581 SuboptimalFuncs.push_back(&BF); 1582 break; 1583 } 1584 } 1585 } 1586 1587 if (!SuboptimalFuncs.empty()) { 1588 std::sort(SuboptimalFuncs.begin(), SuboptimalFuncs.end(), 1589 [](const BinaryFunction *A, const BinaryFunction *B) { 1590 return A->getKnownExecutionCount() / A->getSize() > 1591 B->getKnownExecutionCount() / B->getSize(); 1592 }); 1593 1594 outs() << "BOLT-INFO: " << SuboptimalFuncs.size() 1595 << " functions have " 1596 "cold code in the middle of hot code. Top functions are:\n"; 1597 for (unsigned I = 0; 1598 I < std::min(static_cast<size_t>(opts::ReportBadLayout), 1599 SuboptimalFuncs.size()); 1600 ++I) 1601 SuboptimalFuncs[I]->print(outs()); 1602 } 1603 } 1604 1605 if (NumUnknownControlFlowFunctions) { 1606 outs() << "BOLT-INFO: " << NumUnknownControlFlowFunctions 1607 << " functions have instructions with unknown control flow"; 1608 if (!opts::PrintUnknown) 1609 outs() << ". Use -print-unknown to see the list."; 1610 outs() << '\n'; 1611 } 1612 } 1613 1614 void InstructionLowering::runOnFunctions(BinaryContext &BC) { 1615 for (auto &BFI : BC.getBinaryFunctions()) 1616 for (BinaryBasicBlock &BB : BFI.second) 1617 for (MCInst &Instruction : BB) 1618 BC.MIB->lowerTailCall(Instruction); 1619 } 1620 1621 void StripRepRet::runOnFunctions(BinaryContext &BC) { 1622 uint64_t NumPrefixesRemoved = 0; 1623 uint64_t NumBytesSaved = 0; 1624 for (auto &BFI : BC.getBinaryFunctions()) { 1625 for (BinaryBasicBlock &BB : BFI.second) { 1626 auto LastInstRIter = BB.getLastNonPseudo(); 1627 if (LastInstRIter == BB.rend() || !BC.MIB->isReturn(*LastInstRIter) || 1628 !BC.MIB->deleteREPPrefix(*LastInstRIter)) 1629 continue; 1630 1631 NumPrefixesRemoved += BB.getKnownExecutionCount(); 1632 ++NumBytesSaved; 1633 } 1634 } 1635 1636 if (NumBytesSaved) 1637 outs() << "BOLT-INFO: removed " << NumBytesSaved 1638 << " 'repz' prefixes" 1639 " with estimated execution count of " 1640 << NumPrefixesRemoved << " times.\n"; 1641 } 1642 1643 void InlineMemcpy::runOnFunctions(BinaryContext &BC) { 1644 if (!BC.isX86()) 1645 return; 1646 1647 uint64_t NumInlined = 0; 1648 uint64_t NumInlinedDyno = 0; 1649 for (auto &BFI : BC.getBinaryFunctions()) { 1650 for (BinaryBasicBlock &BB : BFI.second) { 1651 for (auto II = BB.begin(); II != BB.end(); ++II) { 1652 MCInst &Inst = *II; 1653 1654 if (!BC.MIB->isCall(Inst) || MCPlus::getNumPrimeOperands(Inst) != 1 || 1655 !Inst.getOperand(0).isExpr()) 1656 continue; 1657 1658 const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Inst); 1659 if (CalleeSymbol->getName() != "memcpy" && 1660 CalleeSymbol->getName() != "memcpy@PLT" && 1661 CalleeSymbol->getName() != "_memcpy8") 1662 continue; 1663 1664 const bool IsMemcpy8 = (CalleeSymbol->getName() == "_memcpy8"); 1665 const bool IsTailCall = BC.MIB->isTailCall(Inst); 1666 1667 const InstructionListType NewCode = 1668 BC.MIB->createInlineMemcpy(IsMemcpy8); 1669 II = BB.replaceInstruction(II, NewCode); 1670 std::advance(II, NewCode.size() - 1); 1671 if (IsTailCall) { 1672 MCInst Return; 1673 BC.MIB->createReturn(Return); 1674 II = BB.insertInstruction(std::next(II), std::move(Return)); 1675 } 1676 1677 ++NumInlined; 1678 NumInlinedDyno += BB.getKnownExecutionCount(); 1679 } 1680 } 1681 } 1682 1683 if (NumInlined) { 1684 outs() << "BOLT-INFO: inlined " << NumInlined << " memcpy() calls"; 1685 if (NumInlinedDyno) 1686 outs() << ". The calls were executed " << NumInlinedDyno 1687 << " times based on profile."; 1688 outs() << '\n'; 1689 } 1690 } 1691 1692 bool SpecializeMemcpy1::shouldOptimize(const BinaryFunction &Function) const { 1693 if (!BinaryFunctionPass::shouldOptimize(Function)) 1694 return false; 1695 1696 for (const std::string &FunctionSpec : Spec) { 1697 StringRef FunctionName = StringRef(FunctionSpec).split(':').first; 1698 if (Function.hasNameRegex(FunctionName)) 1699 return true; 1700 } 1701 1702 return false; 1703 } 1704 1705 std::set<size_t> SpecializeMemcpy1::getCallSitesToOptimize( 1706 const BinaryFunction &Function) const { 1707 StringRef SitesString; 1708 for (const std::string &FunctionSpec : Spec) { 1709 StringRef FunctionName; 1710 std::tie(FunctionName, SitesString) = StringRef(FunctionSpec).split(':'); 1711 if (Function.hasNameRegex(FunctionName)) 1712 break; 1713 SitesString = ""; 1714 } 1715 1716 std::set<size_t> Sites; 1717 SmallVector<StringRef, 4> SitesVec; 1718 SitesString.split(SitesVec, ':'); 1719 for (StringRef SiteString : SitesVec) { 1720 if (SiteString.empty()) 1721 continue; 1722 size_t Result; 1723 if (!SiteString.getAsInteger(10, Result)) 1724 Sites.emplace(Result); 1725 } 1726 1727 return Sites; 1728 } 1729 1730 void SpecializeMemcpy1::runOnFunctions(BinaryContext &BC) { 1731 if (!BC.isX86()) 1732 return; 1733 1734 uint64_t NumSpecialized = 0; 1735 uint64_t NumSpecializedDyno = 0; 1736 for (auto &BFI : BC.getBinaryFunctions()) { 1737 BinaryFunction &Function = BFI.second; 1738 if (!shouldOptimize(Function)) 1739 continue; 1740 1741 std::set<size_t> CallsToOptimize = getCallSitesToOptimize(Function); 1742 auto shouldOptimize = [&](size_t N) { 1743 return CallsToOptimize.empty() || CallsToOptimize.count(N); 1744 }; 1745 1746 std::vector<BinaryBasicBlock *> Blocks(Function.pbegin(), Function.pend()); 1747 size_t CallSiteID = 0; 1748 for (BinaryBasicBlock *CurBB : Blocks) { 1749 for (auto II = CurBB->begin(); II != CurBB->end(); ++II) { 1750 MCInst &Inst = *II; 1751 1752 if (!BC.MIB->isCall(Inst) || MCPlus::getNumPrimeOperands(Inst) != 1 || 1753 !Inst.getOperand(0).isExpr()) 1754 continue; 1755 1756 const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Inst); 1757 if (CalleeSymbol->getName() != "memcpy" && 1758 CalleeSymbol->getName() != "memcpy@PLT") 1759 continue; 1760 1761 if (BC.MIB->isTailCall(Inst)) 1762 continue; 1763 1764 ++CallSiteID; 1765 1766 if (!shouldOptimize(CallSiteID)) 1767 continue; 1768 1769 // Create a copy of a call to memcpy(dest, src, size). 1770 MCInst MemcpyInstr = Inst; 1771 1772 BinaryBasicBlock *OneByteMemcpyBB = CurBB->splitAt(II); 1773 1774 BinaryBasicBlock *NextBB = nullptr; 1775 if (OneByteMemcpyBB->getNumNonPseudos() > 1) { 1776 NextBB = OneByteMemcpyBB->splitAt(OneByteMemcpyBB->begin()); 1777 NextBB->eraseInstruction(NextBB->begin()); 1778 } else { 1779 NextBB = OneByteMemcpyBB->getSuccessor(); 1780 OneByteMemcpyBB->eraseInstruction(OneByteMemcpyBB->begin()); 1781 assert(NextBB && "unexpected call to memcpy() with no return"); 1782 } 1783 1784 BinaryBasicBlock *MemcpyBB = 1785 Function.addBasicBlock(CurBB->getInputOffset()); 1786 InstructionListType CmpJCC = 1787 BC.MIB->createCmpJE(BC.MIB->getIntArgRegister(2), 1, 1788 OneByteMemcpyBB->getLabel(), BC.Ctx.get()); 1789 CurBB->addInstructions(CmpJCC); 1790 CurBB->addSuccessor(MemcpyBB); 1791 1792 MemcpyBB->addInstruction(std::move(MemcpyInstr)); 1793 MemcpyBB->addSuccessor(NextBB); 1794 MemcpyBB->setCFIState(NextBB->getCFIState()); 1795 MemcpyBB->setExecutionCount(0); 1796 1797 // To prevent the actual call from being moved to cold, we set its 1798 // execution count to 1. 1799 if (CurBB->getKnownExecutionCount() > 0) 1800 MemcpyBB->setExecutionCount(1); 1801 1802 InstructionListType OneByteMemcpy = BC.MIB->createOneByteMemcpy(); 1803 OneByteMemcpyBB->addInstructions(OneByteMemcpy); 1804 1805 ++NumSpecialized; 1806 NumSpecializedDyno += CurBB->getKnownExecutionCount(); 1807 1808 CurBB = NextBB; 1809 1810 // Note: we don't expect the next instruction to be a call to memcpy. 1811 II = CurBB->begin(); 1812 } 1813 } 1814 } 1815 1816 if (NumSpecialized) { 1817 outs() << "BOLT-INFO: specialized " << NumSpecialized 1818 << " memcpy() call sites for size 1"; 1819 if (NumSpecializedDyno) 1820 outs() << ". The calls were executed " << NumSpecializedDyno 1821 << " times based on profile."; 1822 outs() << '\n'; 1823 } 1824 } 1825 1826 void RemoveNops::runOnFunction(BinaryFunction &BF) { 1827 const BinaryContext &BC = BF.getBinaryContext(); 1828 for (BinaryBasicBlock &BB : BF) { 1829 for (int64_t I = BB.size() - 1; I >= 0; --I) { 1830 MCInst &Inst = BB.getInstructionAtIndex(I); 1831 if (BC.MIB->isNoop(Inst) && BC.MIB->hasAnnotation(Inst, "NOP")) 1832 BB.eraseInstructionAtIndex(I); 1833 } 1834 } 1835 } 1836 1837 void RemoveNops::runOnFunctions(BinaryContext &BC) { 1838 ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { 1839 runOnFunction(BF); 1840 }; 1841 1842 ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) { 1843 return BF.shouldPreserveNops(); 1844 }; 1845 1846 ParallelUtilities::runOnEachFunction( 1847 BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun, 1848 SkipFunc, "RemoveNops"); 1849 } 1850 1851 } // namespace bolt 1852 } // namespace llvm 1853