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