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