1 //===- bolt/Passes/FrameAnalysis.cpp --------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the FrameAnalysis class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "bolt/Passes/FrameAnalysis.h" 14 #include "bolt/Core/ParallelUtilities.h" 15 #include "bolt/Passes/CallGraphWalker.h" 16 #include "llvm/Support/Timer.h" 17 #include <fstream> 18 #include <stack> 19 20 #define DEBUG_TYPE "fa" 21 22 using namespace llvm; 23 24 namespace opts { 25 extern cl::OptionCategory BoltOptCategory; 26 extern cl::opt<unsigned> Verbosity; 27 28 static cl::list<std::string> 29 FrameOptFunctionNames("funcs-fop", cl::CommaSeparated, 30 cl::desc("list of functions to apply frame opts"), 31 cl::value_desc("func1,func2,func3,...")); 32 33 static cl::opt<std::string> FrameOptFunctionNamesFile( 34 "funcs-file-fop", 35 cl::desc("file with list of functions to frame optimize")); 36 37 static cl::opt<bool> 38 TimeFA("time-fa", 39 cl::desc("time frame analysis steps"), 40 cl::ReallyHidden, 41 cl::ZeroOrMore, 42 cl::cat(BoltOptCategory)); 43 44 bool shouldFrameOptimize(const llvm::bolt::BinaryFunction &Function) { 45 if (Function.hasUnknownControlFlow()) 46 return false; 47 48 if (!FrameOptFunctionNamesFile.empty()) { 49 assert(!FrameOptFunctionNamesFile.empty() && "unexpected empty file name"); 50 std::ifstream FuncsFile(FrameOptFunctionNamesFile, std::ios::in); 51 std::string FuncName; 52 while (std::getline(FuncsFile, FuncName)) 53 FrameOptFunctionNames.push_back(FuncName); 54 FrameOptFunctionNamesFile = ""; 55 } 56 57 bool IsValid = true; 58 if (!FrameOptFunctionNames.empty()) { 59 IsValid = false; 60 for (std::string &Name : FrameOptFunctionNames) { 61 if (Function.hasName(Name)) { 62 IsValid = true; 63 break; 64 } 65 } 66 } 67 if (!IsValid) 68 return false; 69 70 return IsValid; 71 } 72 } // namespace opts 73 74 namespace llvm { 75 namespace bolt { 76 77 raw_ostream &operator<<(raw_ostream &OS, const FrameIndexEntry &FIE) { 78 OS << "FrameIndexEntry<IsLoad: " << FIE.IsLoad << ", IsStore: " << FIE.IsStore 79 << ", IsStoreFromReg: " << FIE.IsStoreFromReg 80 << ", RegOrImm: " << FIE.RegOrImm << ", StackOffset: "; 81 if (FIE.StackOffset < 0) 82 OS << "-" << Twine::utohexstr(-FIE.StackOffset); 83 else 84 OS << "+" << Twine::utohexstr(FIE.StackOffset); 85 OS << ", Size: " << static_cast<int>(FIE.Size) 86 << ", IsSimple: " << FIE.IsSimple << ">"; 87 return OS; 88 } 89 90 namespace { 91 92 /// This class should be used to iterate through basic blocks in layout order 93 /// to analyze instructions for frame accesses. The user should call 94 /// enterNewBB() whenever starting analyzing a new BB and doNext() for each 95 /// instruction. After doNext(), if isValidAccess() returns true, it means the 96 /// current instruction accesses the frame and getFIE() may be used to obtain 97 /// details about this access. 98 class FrameAccessAnalysis { 99 /// We depend on Stack Pointer Tracking to figure out the current SP offset 100 /// value at a given program point 101 StackPointerTracking &SPT; 102 103 /// Context vars 104 const BinaryContext &BC; 105 const BinaryFunction &BF; 106 // Vars used for storing useful CFI info to give us a hint about how the stack 107 // is used in this function 108 int SPOffset{0}; 109 int FPOffset{0}; 110 int64_t CfaOffset{-8}; 111 uint16_t CfaReg{7}; 112 std::stack<std::pair<int64_t, uint16_t>> CFIStack; 113 /// Our pointer to access SPT info 114 const MCInst *Prev{nullptr}; 115 /// Info about the last frame access 116 bool IsValidAccess{false}; 117 FrameIndexEntry FIE; 118 119 bool decodeFrameAccess(const MCInst &Inst) { 120 int32_t SrcImm = 0; 121 MCPhysReg Reg = 0; 122 int64_t StackOffset = 0; 123 bool IsIndexed = false; 124 if (!BC.MIB->isStackAccess( 125 Inst, FIE.IsLoad, FIE.IsStore, FIE.IsStoreFromReg, Reg, SrcImm, 126 FIE.StackPtrReg, StackOffset, FIE.Size, FIE.IsSimple, IsIndexed)) { 127 return true; 128 } 129 130 if (IsIndexed || FIE.Size == 0) { 131 LLVM_DEBUG(dbgs() << "Giving up on indexed memory access/unknown size\n"); 132 LLVM_DEBUG(dbgs() << "Blame insn: "); 133 LLVM_DEBUG(Inst.dump()); 134 return false; 135 } 136 137 assert(FIE.Size != 0); 138 139 FIE.RegOrImm = SrcImm; 140 if (FIE.IsLoad || FIE.IsStoreFromReg) 141 FIE.RegOrImm = Reg; 142 143 if (FIE.StackPtrReg == BC.MIB->getStackPointer() && SPOffset != SPT.EMPTY && 144 SPOffset != SPT.SUPERPOSITION) { 145 LLVM_DEBUG( 146 dbgs() << "Adding access via SP while CFA reg is another one\n"); 147 FIE.StackOffset = SPOffset + StackOffset; 148 } else if (FIE.StackPtrReg == BC.MIB->getFramePointer() && 149 FPOffset != SPT.EMPTY && FPOffset != SPT.SUPERPOSITION) { 150 LLVM_DEBUG( 151 dbgs() << "Adding access via FP while CFA reg is another one\n"); 152 FIE.StackOffset = FPOffset + StackOffset; 153 } else if (FIE.StackPtrReg == 154 *BC.MRI->getLLVMRegNum(CfaReg, /*isEH=*/false)) { 155 FIE.StackOffset = CfaOffset + StackOffset; 156 } else { 157 LLVM_DEBUG( 158 dbgs() << "Found stack access with reg different than cfa reg.\n"); 159 LLVM_DEBUG(dbgs() << "\tCurrent CFA reg: " << CfaReg 160 << "\n\tStack access reg: " << FIE.StackPtrReg << "\n"); 161 LLVM_DEBUG(dbgs() << "Blame insn: "); 162 LLVM_DEBUG(Inst.dump()); 163 return false; 164 } 165 IsValidAccess = true; 166 return true; 167 } 168 169 public: 170 FrameAccessAnalysis(BinaryFunction &BF, StackPointerTracking &SPT) 171 : SPT(SPT), BC(BF.getBinaryContext()), BF(BF) {} 172 173 void enterNewBB() { Prev = nullptr; } 174 const FrameIndexEntry &getFIE() const { return FIE; } 175 int getSPOffset() const { return SPOffset; } 176 bool isValidAccess() const { return IsValidAccess; } 177 178 bool doNext(const BinaryBasicBlock &BB, const MCInst &Inst) { 179 IsValidAccess = false; 180 std::tie(SPOffset, FPOffset) = 181 Prev ? *SPT.getStateAt(*Prev) : *SPT.getStateAt(BB); 182 Prev = &Inst; 183 // Use CFI information to keep track of which register is being used to 184 // access the frame 185 if (BC.MIB->isCFI(Inst)) { 186 const MCCFIInstruction *CFI = BF.getCFIFor(Inst); 187 switch (CFI->getOperation()) { 188 case MCCFIInstruction::OpDefCfa: 189 CfaOffset = CFI->getOffset(); 190 LLVM_FALLTHROUGH; 191 case MCCFIInstruction::OpDefCfaRegister: 192 CfaReg = CFI->getRegister(); 193 break; 194 case MCCFIInstruction::OpDefCfaOffset: 195 CfaOffset = CFI->getOffset(); 196 break; 197 case MCCFIInstruction::OpRememberState: 198 CFIStack.push(std::make_pair(CfaOffset, CfaReg)); 199 break; 200 case MCCFIInstruction::OpRestoreState: { 201 if (CFIStack.empty()) 202 dbgs() << "Assertion is about to fail: " << BF.getPrintName() << "\n"; 203 assert(!CFIStack.empty() && "Corrupt CFI stack"); 204 std::pair<int64_t, uint16_t> &Elem = CFIStack.top(); 205 CFIStack.pop(); 206 CfaOffset = Elem.first; 207 CfaReg = Elem.second; 208 break; 209 } 210 case MCCFIInstruction::OpAdjustCfaOffset: 211 llvm_unreachable("Unhandled AdjustCfaOffset"); 212 break; 213 default: 214 break; 215 } 216 return true; 217 } 218 219 if (BC.MIB->escapesVariable(Inst, SPT.HasFramePointer)) { 220 LLVM_DEBUG( 221 dbgs() << "Leaked stack address, giving up on this function.\n"); 222 LLVM_DEBUG(dbgs() << "Blame insn: "); 223 LLVM_DEBUG(Inst.dump()); 224 return false; 225 } 226 227 return decodeFrameAccess(Inst); 228 } 229 }; 230 231 } // end anonymous namespace 232 233 void FrameAnalysis::addArgAccessesFor(MCInst &Inst, ArgAccesses &&AA) { 234 if (ErrorOr<ArgAccesses &> OldAA = getArgAccessesFor(Inst)) { 235 if (OldAA->AssumeEverything) 236 return; 237 *OldAA = std::move(AA); 238 return; 239 } 240 if (AA.AssumeEverything) { 241 // Index 0 in ArgAccessesVector represents an "assumeeverything" entry 242 BC.MIB->addAnnotation(Inst, "ArgAccessEntry", 0U); 243 return; 244 } 245 BC.MIB->addAnnotation(Inst, "ArgAccessEntry", 246 (unsigned)ArgAccessesVector.size()); 247 ArgAccessesVector.emplace_back(std::move(AA)); 248 } 249 250 void FrameAnalysis::addArgInStackAccessFor(MCInst &Inst, 251 const ArgInStackAccess &Arg) { 252 ErrorOr<ArgAccesses &> AA = getArgAccessesFor(Inst); 253 if (!AA) { 254 addArgAccessesFor(Inst, ArgAccesses(false)); 255 AA = getArgAccessesFor(Inst); 256 assert(AA && "Object setup failed"); 257 } 258 std::set<ArgInStackAccess> &Set = AA->Set; 259 assert(!AA->AssumeEverything && "Adding arg to AssumeEverything set"); 260 Set.emplace(Arg); 261 } 262 263 void FrameAnalysis::addFIEFor(MCInst &Inst, const FrameIndexEntry &FIE) { 264 BC.MIB->addAnnotation(Inst, "FrameAccessEntry", (unsigned)FIEVector.size()); 265 FIEVector.emplace_back(FIE); 266 } 267 268 ErrorOr<ArgAccesses &> FrameAnalysis::getArgAccessesFor(const MCInst &Inst) { 269 if (auto Idx = BC.MIB->tryGetAnnotationAs<unsigned>(Inst, "ArgAccessEntry")) { 270 assert(ArgAccessesVector.size() > *Idx && "Out of bounds"); 271 return ArgAccessesVector[*Idx]; 272 } 273 return make_error_code(errc::result_out_of_range); 274 } 275 276 ErrorOr<const ArgAccesses &> 277 FrameAnalysis::getArgAccessesFor(const MCInst &Inst) const { 278 if (auto Idx = BC.MIB->tryGetAnnotationAs<unsigned>(Inst, "ArgAccessEntry")) { 279 assert(ArgAccessesVector.size() > *Idx && "Out of bounds"); 280 return ArgAccessesVector[*Idx]; 281 } 282 return make_error_code(errc::result_out_of_range); 283 } 284 285 ErrorOr<const FrameIndexEntry &> 286 FrameAnalysis::getFIEFor(const MCInst &Inst) const { 287 if (auto Idx = 288 BC.MIB->tryGetAnnotationAs<unsigned>(Inst, "FrameAccessEntry")) { 289 assert(FIEVector.size() > *Idx && "Out of bounds"); 290 return FIEVector[*Idx]; 291 } 292 return make_error_code(errc::result_out_of_range); 293 } 294 295 void FrameAnalysis::traverseCG(BinaryFunctionCallGraph &CG) { 296 CallGraphWalker CGWalker(CG); 297 298 CGWalker.registerVisitor( 299 [&](BinaryFunction *Func) -> bool { return computeArgsAccessed(*Func); }); 300 301 CGWalker.walk(); 302 303 DEBUG_WITH_TYPE("ra", { 304 for (auto &MapEntry : ArgsTouchedMap) { 305 const BinaryFunction *Func = MapEntry.first; 306 const auto &Set = MapEntry.second; 307 dbgs() << "Args accessed for " << Func->getPrintName() << ": "; 308 if (!Set.empty() && Set.count(std::make_pair(-1, 0))) 309 dbgs() << "assume everything"; 310 else 311 for (const std::pair<int64_t, uint8_t> &Entry : Set) 312 dbgs() << "[" << Entry.first << ", " << (int)Entry.second << "] "; 313 dbgs() << "\n"; 314 } 315 }); 316 } 317 318 bool FrameAnalysis::updateArgsTouchedFor(const BinaryFunction &BF, MCInst &Inst, 319 int CurOffset) { 320 if (!BC.MIB->isCall(Inst)) 321 return false; 322 323 std::set<int64_t> Res; 324 const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Inst); 325 // If indirect call, we conservatively assume it accesses all stack positions 326 if (TargetSymbol == nullptr) { 327 addArgAccessesFor(Inst, ArgAccesses(/*AssumeEverything=*/true)); 328 if (!FunctionsRequireAlignment.count(&BF)) { 329 FunctionsRequireAlignment.insert(&BF); 330 return true; 331 } 332 return false; 333 } 334 335 const BinaryFunction *Function = BC.getFunctionForSymbol(TargetSymbol); 336 // Call to a function without a BinaryFunction object. Conservatively assume 337 // it accesses all stack positions 338 if (Function == nullptr) { 339 addArgAccessesFor(Inst, ArgAccesses(/*AssumeEverything=*/true)); 340 if (!FunctionsRequireAlignment.count(&BF)) { 341 FunctionsRequireAlignment.insert(&BF); 342 return true; 343 } 344 return false; 345 } 346 347 auto Iter = ArgsTouchedMap.find(Function); 348 349 bool Changed = false; 350 if (BC.MIB->isTailCall(Inst) && Iter != ArgsTouchedMap.end()) { 351 // Ignore checking CurOffset because we can't always reliably determine the 352 // offset specially after an epilogue, where tailcalls happen. It should be 353 // -8. 354 for (std::pair<int64_t, uint8_t> Elem : Iter->second) { 355 if (ArgsTouchedMap[&BF].find(Elem) == ArgsTouchedMap[&BF].end()) { 356 ArgsTouchedMap[&BF].emplace(Elem); 357 Changed = true; 358 } 359 } 360 } 361 if (FunctionsRequireAlignment.count(Function) && 362 !FunctionsRequireAlignment.count(&BF)) { 363 Changed = true; 364 FunctionsRequireAlignment.insert(&BF); 365 } 366 if (Iter == ArgsTouchedMap.end()) 367 return Changed; 368 369 if (CurOffset == StackPointerTracking::EMPTY || 370 CurOffset == StackPointerTracking::SUPERPOSITION) { 371 addArgAccessesFor(Inst, ArgAccesses(/*AssumeEverything=*/true)); 372 return Changed; 373 } 374 375 for (std::pair<int64_t, uint8_t> Elem : Iter->second) { 376 if (Elem.first == -1) { 377 addArgAccessesFor(Inst, ArgAccesses(/*AssumeEverything=*/true)); 378 break; 379 } 380 LLVM_DEBUG(dbgs() << "Added arg in stack access annotation " 381 << CurOffset + Elem.first << "\n"); 382 addArgInStackAccessFor( 383 Inst, ArgInStackAccess{/*StackOffset=*/CurOffset + Elem.first, 384 /*Size=*/Elem.second}); 385 } 386 return Changed; 387 } 388 389 bool FrameAnalysis::computeArgsAccessed(BinaryFunction &BF) { 390 if (!BF.isSimple() || !BF.hasCFG()) { 391 LLVM_DEBUG(dbgs() << "Treating " << BF.getPrintName() 392 << " conservatively.\n"); 393 ArgsTouchedMap[&BF].emplace(std::make_pair(-1, 0)); 394 if (!FunctionsRequireAlignment.count(&BF)) { 395 FunctionsRequireAlignment.insert(&BF); 396 return true; 397 } 398 return false; 399 } 400 401 LLVM_DEBUG(dbgs() << "Now computing args accessed for: " << BF.getPrintName() 402 << "\n"); 403 bool UpdatedArgsTouched = false; 404 bool NoInfo = false; 405 FrameAccessAnalysis FAA(BF, getSPT(BF)); 406 407 for (BinaryBasicBlock *BB : BF.layout()) { 408 FAA.enterNewBB(); 409 410 for (MCInst &Inst : *BB) { 411 if (!FAA.doNext(*BB, Inst)) { 412 ArgsTouchedMap[&BF].emplace(std::make_pair(-1, 0)); 413 NoInfo = true; 414 break; 415 } 416 417 // Check for calls -- attach stack accessing info to them regarding their 418 // target 419 if (updateArgsTouchedFor(BF, Inst, FAA.getSPOffset())) 420 UpdatedArgsTouched = true; 421 422 // Check for stack accesses that affect callers 423 if (!FAA.isValidAccess()) 424 continue; 425 426 const FrameIndexEntry &FIE = FAA.getFIE(); 427 if (FIE.StackOffset < 0) 428 continue; 429 if (ArgsTouchedMap[&BF].find(std::make_pair(FIE.StackOffset, FIE.Size)) != 430 ArgsTouchedMap[&BF].end()) 431 continue; 432 433 // Record accesses to the previous stack frame 434 ArgsTouchedMap[&BF].emplace(std::make_pair(FIE.StackOffset, FIE.Size)); 435 UpdatedArgsTouched = true; 436 LLVM_DEBUG({ 437 dbgs() << "Arg access offset " << FIE.StackOffset << " added to:\n"; 438 BC.printInstruction(dbgs(), Inst, 0, &BF, true); 439 }); 440 } 441 if (NoInfo) 442 break; 443 } 444 if (FunctionsRequireAlignment.count(&BF)) 445 return UpdatedArgsTouched; 446 447 if (NoInfo) { 448 FunctionsRequireAlignment.insert(&BF); 449 return true; 450 } 451 452 for (BinaryBasicBlock &BB : BF) { 453 for (MCInst &Inst : BB) { 454 if (BC.MIB->requiresAlignedAddress(Inst)) { 455 FunctionsRequireAlignment.insert(&BF); 456 return true; 457 } 458 } 459 } 460 return UpdatedArgsTouched; 461 } 462 463 bool FrameAnalysis::restoreFrameIndex(BinaryFunction &BF) { 464 FrameAccessAnalysis FAA(BF, getSPT(BF)); 465 466 LLVM_DEBUG(dbgs() << "Restoring frame indices for \"" << BF.getPrintName() 467 << "\"\n"); 468 for (BinaryBasicBlock *BB : BF.layout()) { 469 LLVM_DEBUG(dbgs() << "\tNow at BB " << BB->getName() << "\n"); 470 FAA.enterNewBB(); 471 472 for (MCInst &Inst : *BB) { 473 if (!FAA.doNext(*BB, Inst)) 474 return false; 475 LLVM_DEBUG({ 476 dbgs() << "\t\tNow at "; 477 Inst.dump(); 478 dbgs() << "\t\t\tSP offset is " << FAA.getSPOffset() << "\n"; 479 }); 480 481 if (!FAA.isValidAccess()) 482 continue; 483 484 const FrameIndexEntry &FIE = FAA.getFIE(); 485 486 addFIEFor(Inst, FIE); 487 LLVM_DEBUG({ 488 dbgs() << "Frame index annotation " << FIE << " added to:\n"; 489 BC.printInstruction(dbgs(), Inst, 0, &BF, true); 490 }); 491 } 492 } 493 return true; 494 } 495 496 void FrameAnalysis::cleanAnnotations() { 497 NamedRegionTimer T("cleanannotations", "clean annotations", "FA", 498 "FA breakdown", opts::TimeFA); 499 500 ParallelUtilities::WorkFuncTy CleanFunction = [&](BinaryFunction &BF) { 501 for (BinaryBasicBlock &BB : BF) { 502 for (MCInst &Inst : BB) { 503 BC.MIB->removeAnnotation(Inst, "ArgAccessEntry"); 504 BC.MIB->removeAnnotation(Inst, "FrameAccessEntry"); 505 } 506 } 507 }; 508 509 ParallelUtilities::runOnEachFunction( 510 BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, CleanFunction, 511 ParallelUtilities::PredicateTy(nullptr), "cleanAnnotations"); 512 } 513 514 FrameAnalysis::FrameAnalysis(BinaryContext &BC, BinaryFunctionCallGraph &CG) 515 : BC(BC) { 516 // Position 0 of the vector should be always associated with "assume access 517 // everything". 518 ArgAccessesVector.emplace_back(ArgAccesses(/*AssumeEverything*/ true)); 519 520 if (!opts::NoThreads) { 521 NamedRegionTimer T1("precomputespt", "pre-compute spt", "FA", 522 "FA breakdown", opts::TimeFA); 523 preComputeSPT(); 524 } 525 526 { 527 NamedRegionTimer T1("traversecg", "traverse call graph", "FA", 528 "FA breakdown", opts::TimeFA); 529 traverseCG(CG); 530 } 531 532 for (auto &I : BC.getBinaryFunctions()) { 533 uint64_t Count = I.second.getExecutionCount(); 534 if (Count != BinaryFunction::COUNT_NO_PROFILE) 535 CountDenominator += Count; 536 537 // "shouldOptimize" for passes that run after finalize 538 if (!(I.second.isSimple() && I.second.hasCFG() && !I.second.isIgnored()) || 539 !opts::shouldFrameOptimize(I.second)) { 540 ++NumFunctionsNotOptimized; 541 if (Count != BinaryFunction::COUNT_NO_PROFILE) 542 CountFunctionsNotOptimized += Count; 543 continue; 544 } 545 546 { 547 NamedRegionTimer T1("restorefi", "restore frame index", "FA", 548 "FA breakdown", opts::TimeFA); 549 if (!restoreFrameIndex(I.second)) { 550 ++NumFunctionsFailedRestoreFI; 551 uint64_t Count = I.second.getExecutionCount(); 552 if (Count != BinaryFunction::COUNT_NO_PROFILE) 553 CountFunctionsFailedRestoreFI += Count; 554 continue; 555 } 556 } 557 AnalyzedFunctions.insert(&I.second); 558 } 559 560 { 561 NamedRegionTimer T1("clearspt", "clear spt", "FA", "FA breakdown", 562 opts::TimeFA); 563 clearSPTMap(); 564 565 // Clean up memory allocated for annotation values 566 if (!opts::NoThreads) 567 for (MCPlusBuilder::AllocatorIdTy Id : SPTAllocatorsId) 568 BC.MIB->freeValuesAllocator(Id); 569 } 570 } 571 572 void FrameAnalysis::printStats() { 573 outs() << "BOLT-INFO: FRAME ANALYSIS: " << NumFunctionsNotOptimized 574 << " function(s) " 575 << format("(%.1lf%% dyn cov)", 576 (100.0 * CountFunctionsNotOptimized / CountDenominator)) 577 << " were not optimized.\n" 578 << "BOLT-INFO: FRAME ANALYSIS: " << NumFunctionsFailedRestoreFI 579 << " function(s) " 580 << format("(%.1lf%% dyn cov)", 581 (100.0 * CountFunctionsFailedRestoreFI / CountDenominator)) 582 << " could not have its frame indices restored.\n"; 583 } 584 585 void FrameAnalysis::clearSPTMap() { 586 if (opts::NoThreads) { 587 SPTMap.clear(); 588 return; 589 } 590 591 ParallelUtilities::WorkFuncTy ClearFunctionSPT = [&](BinaryFunction &BF) { 592 std::unique_ptr<StackPointerTracking> &SPTPtr = SPTMap.find(&BF)->second; 593 SPTPtr.reset(); 594 }; 595 596 ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) { 597 return !BF.isSimple() || !BF.hasCFG(); 598 }; 599 600 ParallelUtilities::runOnEachFunction( 601 BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, ClearFunctionSPT, 602 SkipFunc, "clearSPTMap"); 603 604 SPTMap.clear(); 605 } 606 607 void FrameAnalysis::preComputeSPT() { 608 // Make sure that the SPTMap is empty 609 assert(SPTMap.size() == 0); 610 611 // Create map entries to allow lock-free parallel execution 612 for (auto &BFI : BC.getBinaryFunctions()) { 613 BinaryFunction &BF = BFI.second; 614 if (!BF.isSimple() || !BF.hasCFG()) 615 continue; 616 SPTMap.emplace(&BF, std::unique_ptr<StackPointerTracking>()); 617 } 618 619 // Create an index for the SPT annotation to allow lock-free parallel 620 // execution 621 BC.MIB->getOrCreateAnnotationIndex("StackPointerTracking"); 622 623 // Run SPT in parallel 624 ParallelUtilities::WorkFuncWithAllocTy ProcessFunction = 625 [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId) { 626 std::unique_ptr<StackPointerTracking> &SPTPtr = 627 SPTMap.find(&BF)->second; 628 SPTPtr = std::make_unique<StackPointerTracking>(BF, AllocId); 629 SPTPtr->run(); 630 }; 631 632 ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) { 633 return !BF.isSimple() || !BF.hasCFG(); 634 }; 635 636 ParallelUtilities::runOnEachFunctionWithUniqueAllocId( 637 BC, ParallelUtilities::SchedulingPolicy::SP_BB_QUADRATIC, ProcessFunction, 638 SkipPredicate, "preComputeSPT"); 639 } 640 641 } // namespace bolt 642 } // namespace llvm 643