1 //===- bolt/Passes/ShrinkWrapping.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 ShrinkWrapping class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "bolt/Passes/ShrinkWrapping.h" 14 #include "bolt/Core/MCPlus.h" 15 #include "bolt/Passes/DataflowInfoManager.h" 16 #include <numeric> 17 #include <stack> 18 19 #define DEBUG_TYPE "shrinkwrapping" 20 21 using namespace llvm; 22 23 namespace opts { 24 25 extern cl::opt<bool> TimeOpts; 26 extern cl::OptionCategory BoltOptCategory; 27 28 static cl::opt<unsigned> ShrinkWrappingThreshold( 29 "shrink-wrapping-threshold", 30 cl::desc("Percentage of prologue execution count to use as threshold when" 31 " evaluating whether a block is cold enough to be profitable to" 32 " move eligible spills there"), 33 cl::init(30), cl::ZeroOrMore, cl::cat(BoltOptCategory)); 34 } // namespace opts 35 36 namespace llvm { 37 namespace bolt { 38 39 void CalleeSavedAnalysis::analyzeSaves() { 40 ReachingDefOrUse</*Def=*/true> &RD = Info.getReachingDefs(); 41 StackReachingUses &SRU = Info.getStackReachingUses(); 42 auto &InsnToBB = Info.getInsnToBBMap(); 43 BitVector BlacklistedRegs(BC.MRI->getNumRegs(), false); 44 45 LLVM_DEBUG(dbgs() << "Checking spill locations\n"); 46 for (BinaryBasicBlock &BB : BF) { 47 LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n"); 48 const MCInst *Prev = nullptr; 49 for (MCInst &Inst : BB) { 50 if (ErrorOr<const FrameIndexEntry &> FIE = FA.getFIEFor(Inst)) { 51 // Blacklist weird stores we don't understand 52 if ((!FIE->IsSimple || FIE->StackOffset >= 0) && FIE->IsStore && 53 FIE->IsStoreFromReg) { 54 BlacklistedRegs.set(FIE->RegOrImm); 55 CalleeSaved.reset(FIE->RegOrImm); 56 Prev = &Inst; 57 continue; 58 } 59 60 if (!FIE->IsStore || !FIE->IsStoreFromReg || 61 BlacklistedRegs[FIE->RegOrImm]) { 62 Prev = &Inst; 63 continue; 64 } 65 66 // If this reg is defined locally, it is not a callee-saved reg 67 if (RD.isReachedBy(FIE->RegOrImm, 68 Prev ? RD.expr_begin(*Prev) : RD.expr_begin(BB))) { 69 BlacklistedRegs.set(FIE->RegOrImm); 70 CalleeSaved.reset(FIE->RegOrImm); 71 Prev = &Inst; 72 continue; 73 } 74 75 // If this stack position is accessed in another function, we are 76 // probably dealing with a parameter passed in a stack -- do not mess 77 // with it 78 if (SRU.isStoreUsed(*FIE, 79 Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB)), 80 /*IncludeLocalAccesses=*/false) { 81 BlacklistedRegs.set(FIE->RegOrImm); 82 CalleeSaved.reset(FIE->RegOrImm); 83 Prev = &Inst; 84 continue; 85 } 86 87 // If this stack position is loaded elsewhere in another reg, we can't 88 // update it, so blacklist it. 89 if (SRU.isLoadedInDifferentReg(*FIE, Prev ? SRU.expr_begin(*Prev) 90 : SRU.expr_begin(BB))) { 91 BlacklistedRegs.set(FIE->RegOrImm); 92 CalleeSaved.reset(FIE->RegOrImm); 93 Prev = &Inst; 94 continue; 95 } 96 97 // Ignore regs with multiple saves 98 if (CalleeSaved[FIE->RegOrImm]) { 99 BlacklistedRegs.set(FIE->RegOrImm); 100 CalleeSaved.reset(FIE->RegOrImm); 101 Prev = &Inst; 102 continue; 103 } 104 105 CalleeSaved.set(FIE->RegOrImm); 106 SaveFIEByReg[FIE->RegOrImm] = &*FIE; 107 SavingCost[FIE->RegOrImm] += InsnToBB[&Inst]->getKnownExecutionCount(); 108 BC.MIB->addAnnotation(Inst, getSaveTag(), FIE->RegOrImm, AllocatorId); 109 OffsetsByReg[FIE->RegOrImm] = FIE->StackOffset; 110 LLVM_DEBUG(dbgs() << "Logging new candidate for Callee-Saved Reg: " 111 << FIE->RegOrImm << "\n"); 112 } 113 Prev = &Inst; 114 } 115 } 116 } 117 118 void CalleeSavedAnalysis::analyzeRestores() { 119 ReachingDefOrUse</*Def=*/false> &RU = Info.getReachingUses(); 120 121 // Now compute all restores of these callee-saved regs 122 for (BinaryBasicBlock &BB : BF) { 123 const MCInst *Prev = nullptr; 124 for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) { 125 MCInst &Inst = *I; 126 if (ErrorOr<const FrameIndexEntry &> FIE = FA.getFIEFor(Inst)) { 127 if (!FIE->IsLoad || !CalleeSaved[FIE->RegOrImm]) { 128 Prev = &Inst; 129 continue; 130 } 131 132 // If this reg is used locally after a restore, then we are probably 133 // not dealing with a callee-saved reg. Except if this use is by 134 // another store, but we don't cover this case yet. 135 // Also not callee-saved if this load accesses caller stack or isn't 136 // simple. 137 if (!FIE->IsSimple || FIE->StackOffset >= 0 || 138 RU.isReachedBy(FIE->RegOrImm, 139 Prev ? RU.expr_begin(*Prev) : RU.expr_begin(BB))) { 140 CalleeSaved.reset(FIE->RegOrImm); 141 Prev = &Inst; 142 continue; 143 } 144 // If stack offsets between saves/store don't agree with each other, 145 // we don't completely understand what's happening here 146 if (FIE->StackOffset != OffsetsByReg[FIE->RegOrImm]) { 147 CalleeSaved.reset(FIE->RegOrImm); 148 LLVM_DEBUG(dbgs() << "Dismissing Callee-Saved Reg because we found a " 149 "mismatching restore: " 150 << FIE->RegOrImm << "\n"); 151 Prev = &Inst; 152 continue; 153 } 154 155 LLVM_DEBUG(dbgs() << "Adding matching restore for: " << FIE->RegOrImm 156 << "\n"); 157 if (LoadFIEByReg[FIE->RegOrImm] == nullptr) 158 LoadFIEByReg[FIE->RegOrImm] = &*FIE; 159 BC.MIB->addAnnotation(Inst, getRestoreTag(), FIE->RegOrImm, 160 AllocatorId); 161 HasRestores.set(FIE->RegOrImm); 162 } 163 Prev = &Inst; 164 } 165 } 166 } 167 168 std::vector<MCInst *> CalleeSavedAnalysis::getSavesByReg(uint16_t Reg) { 169 std::vector<MCInst *> Results; 170 for (BinaryBasicBlock &BB : BF) 171 for (MCInst &Inst : BB) 172 if (getSavedReg(Inst) == Reg) 173 Results.push_back(&Inst); 174 return Results; 175 } 176 177 std::vector<MCInst *> CalleeSavedAnalysis::getRestoresByReg(uint16_t Reg) { 178 std::vector<MCInst *> Results; 179 for (BinaryBasicBlock &BB : BF) 180 for (MCInst &Inst : BB) 181 if (getRestoredReg(Inst) == Reg) 182 Results.push_back(&Inst); 183 return Results; 184 } 185 186 CalleeSavedAnalysis::~CalleeSavedAnalysis() { 187 for (BinaryBasicBlock &BB : BF) { 188 for (MCInst &Inst : BB) { 189 BC.MIB->removeAnnotation(Inst, getSaveTag()); 190 BC.MIB->removeAnnotation(Inst, getRestoreTag()); 191 } 192 } 193 } 194 195 void StackLayoutModifier::blacklistRegion(int64_t Offset, int64_t Size) { 196 if (BlacklistedRegions[Offset] < Size) 197 BlacklistedRegions[Offset] = Size; 198 } 199 200 bool StackLayoutModifier::isRegionBlacklisted(int64_t Offset, int64_t Size) { 201 for (std::pair<const int64_t, int64_t> Elem : BlacklistedRegions) 202 if (Offset + Size > Elem.first && Offset < Elem.first + Elem.second) 203 return true; 204 return false; 205 } 206 207 bool StackLayoutModifier::blacklistAllInConflictWith(int64_t Offset, 208 int64_t Size) { 209 bool HasConflict = false; 210 for (auto Iter = AvailableRegions.begin(); Iter != AvailableRegions.end();) { 211 std::pair<const int64_t, int64_t> &Elem = *Iter; 212 if (Offset + Size > Elem.first && Offset < Elem.first + Elem.second && 213 (Offset != Elem.first || Size != Elem.second)) { 214 Iter = AvailableRegions.erase(Iter); 215 HasConflict = true; 216 continue; 217 } 218 ++Iter; 219 } 220 if (HasConflict) { 221 blacklistRegion(Offset, Size); 222 return true; 223 } 224 return false; 225 } 226 227 void StackLayoutModifier::checkFramePointerInitialization(MCInst &Point) { 228 StackPointerTracking &SPT = Info.getStackPointerTracking(); 229 if (!BC.MII->get(Point.getOpcode()) 230 .hasDefOfPhysReg(Point, BC.MIB->getFramePointer(), *BC.MRI)) 231 return; 232 233 int SPVal, FPVal; 234 std::tie(SPVal, FPVal) = *SPT.getStateBefore(Point); 235 std::pair<MCPhysReg, int64_t> FP; 236 237 if (FPVal != SPT.EMPTY && FPVal != SPT.SUPERPOSITION) 238 FP = std::make_pair(BC.MIB->getFramePointer(), FPVal); 239 else 240 FP = std::make_pair(0, 0); 241 std::pair<MCPhysReg, int64_t> SP; 242 243 if (SPVal != SPT.EMPTY && SPVal != SPT.SUPERPOSITION) 244 SP = std::make_pair(BC.MIB->getStackPointer(), SPVal); 245 else 246 SP = std::make_pair(0, 0); 247 248 int64_t Output; 249 if (!BC.MIB->evaluateStackOffsetExpr(Point, Output, SP, FP)) 250 return; 251 252 // Not your regular frame pointer initialization... bail 253 if (Output != SPVal) 254 blacklistRegion(0, 0); 255 } 256 257 void StackLayoutModifier::checkStackPointerRestore(MCInst &Point) { 258 StackPointerTracking &SPT = Info.getStackPointerTracking(); 259 if (!BC.MII->get(Point.getOpcode()) 260 .hasDefOfPhysReg(Point, BC.MIB->getStackPointer(), *BC.MRI)) 261 return; 262 // Check if the definition of SP comes from FP -- in this case, this 263 // value may need to be updated depending on our stack layout changes 264 const MCInstrDesc &InstInfo = BC.MII->get(Point.getOpcode()); 265 unsigned NumDefs = InstInfo.getNumDefs(); 266 bool UsesFP = false; 267 for (unsigned I = NumDefs, E = MCPlus::getNumPrimeOperands(Point); I < E; 268 ++I) { 269 MCOperand &Operand = Point.getOperand(I); 270 if (!Operand.isReg()) 271 continue; 272 if (Operand.getReg() == BC.MIB->getFramePointer()) { 273 UsesFP = true; 274 break; 275 } 276 } 277 if (!UsesFP) 278 return; 279 280 // Setting up evaluation 281 int SPVal, FPVal; 282 std::tie(SPVal, FPVal) = *SPT.getStateBefore(Point); 283 std::pair<MCPhysReg, int64_t> FP; 284 285 if (FPVal != SPT.EMPTY && FPVal != SPT.SUPERPOSITION) 286 FP = std::make_pair(BC.MIB->getFramePointer(), FPVal); 287 else 288 FP = std::make_pair(0, 0); 289 std::pair<MCPhysReg, int64_t> SP; 290 291 if (SPVal != SPT.EMPTY && SPVal != SPT.SUPERPOSITION) 292 SP = std::make_pair(BC.MIB->getStackPointer(), SPVal); 293 else 294 SP = std::make_pair(0, 0); 295 296 int64_t Output; 297 if (!BC.MIB->evaluateStackOffsetExpr(Point, Output, SP, FP)) 298 return; 299 300 // If the value is the same of FP, no need to adjust it 301 if (Output == FPVal) 302 return; 303 304 // If an allocation happened through FP, bail 305 if (Output <= SPVal) { 306 blacklistRegion(0, 0); 307 return; 308 } 309 310 // We are restoring SP to an old value based on FP. Mark it as a stack 311 // access to be fixed later. 312 BC.MIB->addAnnotation(Point, getSlotTag(), Output, AllocatorId); 313 } 314 315 void StackLayoutModifier::classifyStackAccesses() { 316 // Understand when stack slots are being used non-locally 317 StackReachingUses &SRU = Info.getStackReachingUses(); 318 319 for (BinaryBasicBlock &BB : BF) { 320 const MCInst *Prev = nullptr; 321 for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) { 322 MCInst &Inst = *I; 323 checkFramePointerInitialization(Inst); 324 checkStackPointerRestore(Inst); 325 ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst); 326 if (!FIEX) { 327 Prev = &Inst; 328 continue; 329 } 330 if (!FIEX->IsSimple || (FIEX->IsStore && !FIEX->IsStoreFromReg)) { 331 blacklistRegion(FIEX->StackOffset, FIEX->Size); 332 Prev = &Inst; 333 continue; 334 } 335 // If this stack position is accessed in another function, we are 336 // probably dealing with a parameter passed in a stack -- do not mess 337 // with it 338 if (SRU.isStoreUsed(*FIEX, 339 Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB), 340 /*IncludeLocalAccesses=*/false)) { 341 blacklistRegion(FIEX->StackOffset, FIEX->Size); 342 Prev = &Inst; 343 continue; 344 } 345 // Now we have a clear stack slot access. Check if its blacklisted or if 346 // it conflicts with another chunk. 347 if (isRegionBlacklisted(FIEX->StackOffset, FIEX->Size) || 348 blacklistAllInConflictWith(FIEX->StackOffset, FIEX->Size)) { 349 Prev = &Inst; 350 continue; 351 } 352 // We are free to go. Add it as available stack slot which we know how 353 // to move it. 354 AvailableRegions[FIEX->StackOffset] = FIEX->Size; 355 BC.MIB->addAnnotation(Inst, getSlotTag(), FIEX->StackOffset, AllocatorId); 356 RegionToRegMap[FIEX->StackOffset].insert(FIEX->RegOrImm); 357 RegToRegionMap[FIEX->RegOrImm].insert(FIEX->StackOffset); 358 LLVM_DEBUG(dbgs() << "Adding region " << FIEX->StackOffset << " size " 359 << (int)FIEX->Size << "\n"); 360 } 361 } 362 } 363 364 void StackLayoutModifier::classifyCFIs() { 365 std::stack<std::pair<int64_t, uint16_t>> CFIStack; 366 int64_t CfaOffset = -8; 367 uint16_t CfaReg = 7; 368 369 auto recordAccess = [&](MCInst *Inst, int64_t Offset) { 370 const uint16_t Reg = *BC.MRI->getLLVMRegNum(CfaReg, /*isEH=*/false); 371 if (Reg == BC.MIB->getStackPointer() || Reg == BC.MIB->getFramePointer()) { 372 BC.MIB->addAnnotation(*Inst, getSlotTag(), Offset, AllocatorId); 373 LLVM_DEBUG(dbgs() << "Recording CFI " << Offset << "\n"); 374 } else { 375 IsSimple = false; 376 return; 377 } 378 }; 379 380 for (BinaryBasicBlock *&BB : BF.layout()) { 381 for (MCInst &Inst : *BB) { 382 if (!BC.MIB->isCFI(Inst)) 383 continue; 384 const MCCFIInstruction *CFI = BF.getCFIFor(Inst); 385 switch (CFI->getOperation()) { 386 case MCCFIInstruction::OpDefCfa: 387 CfaOffset = -CFI->getOffset(); 388 recordAccess(&Inst, CfaOffset); 389 LLVM_FALLTHROUGH; 390 case MCCFIInstruction::OpDefCfaRegister: 391 CfaReg = CFI->getRegister(); 392 break; 393 case MCCFIInstruction::OpDefCfaOffset: 394 CfaOffset = -CFI->getOffset(); 395 recordAccess(&Inst, CfaOffset); 396 break; 397 case MCCFIInstruction::OpOffset: 398 recordAccess(&Inst, CFI->getOffset()); 399 BC.MIB->addAnnotation(Inst, getOffsetCFIRegTag(), 400 BC.MRI->getLLVMRegNum(CFI->getRegister(), 401 /*isEH=*/false), 402 AllocatorId); 403 break; 404 case MCCFIInstruction::OpSameValue: 405 BC.MIB->addAnnotation(Inst, getOffsetCFIRegTag(), 406 BC.MRI->getLLVMRegNum(CFI->getRegister(), 407 /*isEH=*/false), 408 AllocatorId); 409 break; 410 case MCCFIInstruction::OpRememberState: 411 CFIStack.push(std::make_pair(CfaOffset, CfaReg)); 412 break; 413 case MCCFIInstruction::OpRestoreState: { 414 assert(!CFIStack.empty() && "Corrupt CFI stack"); 415 std::pair<int64_t, uint16_t> &Elem = CFIStack.top(); 416 CFIStack.pop(); 417 CfaOffset = Elem.first; 418 CfaReg = Elem.second; 419 break; 420 } 421 case MCCFIInstruction::OpRelOffset: 422 case MCCFIInstruction::OpAdjustCfaOffset: 423 llvm_unreachable("Unhandled AdjustCfaOffset"); 424 break; 425 default: 426 break; 427 } 428 } 429 } 430 } 431 432 void StackLayoutModifier::scheduleChange( 433 MCInst &Inst, StackLayoutModifier::WorklistItem Item) { 434 auto &WList = BC.MIB->getOrCreateAnnotationAs<std::vector<WorklistItem>>( 435 Inst, getTodoTag(), AllocatorId); 436 WList.push_back(Item); 437 } 438 439 bool StackLayoutModifier::canCollapseRegion(MCInst *DeletedPush) { 440 if (!IsSimple || !BC.MIB->isPush(*DeletedPush)) 441 return false; 442 443 ErrorOr<const FrameIndexEntry &> FIE = FA.getFIEFor(*DeletedPush); 444 if (!FIE) 445 return false; 446 447 return canCollapseRegion(FIE->StackOffset); 448 } 449 450 bool StackLayoutModifier::canCollapseRegion(int64_t RegionAddr) { 451 if (!IsInitialized) 452 initialize(); 453 if (!IsSimple) 454 return false; 455 456 if (CollapsedRegions.count(RegionAddr)) 457 return true; 458 459 // Check if it is possible to readjust all accesses below RegionAddr 460 if (!BlacklistedRegions.empty()) 461 return false; 462 463 return true; 464 } 465 466 bool StackLayoutModifier::collapseRegion(MCInst *DeletedPush) { 467 ErrorOr<const FrameIndexEntry &> FIE = FA.getFIEFor(*DeletedPush); 468 if (!FIE) 469 return false; 470 int64_t RegionAddr = FIE->StackOffset; 471 int64_t RegionSz = FIE->Size; 472 return collapseRegion(DeletedPush, RegionAddr, RegionSz); 473 } 474 475 bool StackLayoutModifier::collapseRegion(MCInst *Alloc, int64_t RegionAddr, 476 int64_t RegionSz) { 477 if (!canCollapseRegion(RegionAddr)) 478 return false; 479 480 assert(IsInitialized); 481 StackAllocationAnalysis &SAA = Info.getStackAllocationAnalysis(); 482 483 for (BinaryBasicBlock &BB : BF) { 484 for (MCInst &Inst : BB) { 485 if (!BC.MIB->hasAnnotation(Inst, getSlotTag())) 486 continue; 487 auto Slot = 488 BC.MIB->getAnnotationAs<decltype(FrameIndexEntry::StackOffset)>( 489 Inst, getSlotTag()); 490 if (!AvailableRegions.count(Slot)) 491 continue; 492 // We need to ensure this access is affected by the deleted push 493 if (!(*SAA.getStateBefore(Inst))[SAA.ExprToIdx[Alloc]]) 494 continue; 495 496 if (BC.MIB->isCFI(Inst)) { 497 if (Slot > RegionAddr) 498 continue; 499 scheduleChange(Inst, WorklistItem(WorklistItem::AdjustCFI, RegionSz)); 500 continue; 501 } 502 ErrorOr<const FrameIndexEntry &> FIE = FA.getFIEFor(Inst); 503 if (!FIE) { 504 if (Slot > RegionAddr) 505 continue; 506 // SP update based on frame pointer 507 scheduleChange( 508 Inst, WorklistItem(WorklistItem::AdjustLoadStoreOffset, RegionSz)); 509 continue; 510 } 511 512 if (Slot == RegionAddr) { 513 BC.MIB->addAnnotation(Inst, "AccessesDeletedPos", 0U, AllocatorId); 514 continue; 515 } 516 if (BC.MIB->isPush(Inst) || BC.MIB->isPop(Inst)) 517 continue; 518 519 if (FIE->StackPtrReg == BC.MIB->getStackPointer() && Slot < RegionAddr) 520 continue; 521 522 if (FIE->StackPtrReg == BC.MIB->getFramePointer() && Slot > RegionAddr) 523 continue; 524 525 scheduleChange( 526 Inst, WorklistItem(WorklistItem::AdjustLoadStoreOffset, RegionSz)); 527 } 528 } 529 530 CollapsedRegions.insert(RegionAddr); 531 return true; 532 } 533 534 void StackLayoutModifier::setOffsetForCollapsedAccesses(int64_t NewOffset) { 535 for (BinaryBasicBlock &BB : BF) { 536 for (MCInst &Inst : BB) { 537 if (!BC.MIB->hasAnnotation(Inst, "AccessesDeletedPos")) 538 continue; 539 BC.MIB->removeAnnotation(Inst, "AccessesDeletedPos"); 540 scheduleChange( 541 Inst, WorklistItem(WorklistItem::AdjustLoadStoreOffset, NewOffset)); 542 } 543 } 544 } 545 546 bool StackLayoutModifier::canInsertRegion(ProgramPoint P) { 547 if (!IsInitialized) 548 initialize(); 549 if (!IsSimple) 550 return false; 551 552 StackPointerTracking &SPT = Info.getStackPointerTracking(); 553 int64_t RegionAddr = SPT.getStateBefore(P)->first; 554 if (RegionAddr == SPT.SUPERPOSITION || RegionAddr == SPT.EMPTY) 555 return false; 556 557 if (InsertedRegions.count(RegionAddr)) 558 return true; 559 560 // Check if we are going to screw up stack accesses at call sites that 561 // pass parameters via stack 562 if (!BlacklistedRegions.empty()) 563 return false; 564 565 return true; 566 } 567 568 bool StackLayoutModifier::insertRegion(ProgramPoint P, int64_t RegionSz) { 569 if (!canInsertRegion(P)) 570 return false; 571 572 assert(IsInitialized); 573 StackPointerTracking &SPT = Info.getStackPointerTracking(); 574 // This RegionAddr is slightly different from the one seen in collapseRegion 575 // This is the value of SP before the allocation the user wants to make. 576 int64_t RegionAddr = SPT.getStateBefore(P)->first; 577 if (RegionAddr == SPT.SUPERPOSITION || RegionAddr == SPT.EMPTY) 578 return false; 579 580 DominatorAnalysis<false> &DA = Info.getDominatorAnalysis(); 581 582 for (BinaryBasicBlock &BB : BF) { 583 for (MCInst &Inst : BB) { 584 if (!BC.MIB->hasAnnotation(Inst, getSlotTag())) 585 continue; 586 auto Slot = 587 BC.MIB->getAnnotationAs<decltype(FrameIndexEntry::StackOffset)>( 588 Inst, getSlotTag()); 589 if (!AvailableRegions.count(Slot)) 590 continue; 591 592 if (!(DA.doesADominateB(P, Inst))) 593 continue; 594 595 if (BC.MIB->isCFI(Inst)) { 596 if (Slot >= RegionAddr) 597 continue; 598 scheduleChange(Inst, WorklistItem(WorklistItem::AdjustCFI, -RegionSz)); 599 continue; 600 } 601 ErrorOr<const FrameIndexEntry &> FIE = FA.getFIEFor(Inst); 602 if (!FIE) { 603 if (Slot >= RegionAddr) 604 continue; 605 scheduleChange( 606 Inst, WorklistItem(WorklistItem::AdjustLoadStoreOffset, -RegionSz)); 607 continue; 608 } 609 610 if (FIE->StackPtrReg == BC.MIB->getStackPointer() && Slot < RegionAddr) 611 continue; 612 if (FIE->StackPtrReg == BC.MIB->getFramePointer() && Slot >= RegionAddr) 613 continue; 614 if (BC.MIB->isPush(Inst) || BC.MIB->isPop(Inst)) 615 continue; 616 scheduleChange( 617 Inst, WorklistItem(WorklistItem::AdjustLoadStoreOffset, -RegionSz)); 618 } 619 } 620 621 InsertedRegions.insert(RegionAddr); 622 return true; 623 } 624 625 void StackLayoutModifier::performChanges() { 626 std::set<uint32_t> ModifiedCFIIndices; 627 for (BinaryBasicBlock &BB : BF) { 628 for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) { 629 MCInst &Inst = *I; 630 if (BC.MIB->hasAnnotation(Inst, "AccessesDeletedPos")) { 631 assert(BC.MIB->isPop(Inst) || BC.MIB->isPush(Inst)); 632 BC.MIB->removeAnnotation(Inst, "AccessesDeletedPos"); 633 } 634 if (!BC.MIB->hasAnnotation(Inst, getTodoTag())) 635 continue; 636 auto &WList = BC.MIB->getAnnotationAs<std::vector<WorklistItem>>( 637 Inst, getTodoTag()); 638 int64_t Adjustment = 0; 639 WorklistItem::ActionType AdjustmentType = WorklistItem::None; 640 for (WorklistItem &WI : WList) { 641 if (WI.Action == WorklistItem::None) 642 continue; 643 assert(WI.Action == WorklistItem::AdjustLoadStoreOffset || 644 WI.Action == WorklistItem::AdjustCFI); 645 assert((AdjustmentType == WorklistItem::None || 646 AdjustmentType == WI.Action) && 647 "Conflicting actions requested at the same program point"); 648 AdjustmentType = WI.Action; 649 Adjustment += WI.OffsetUpdate; 650 } 651 if (!Adjustment) 652 continue; 653 if (AdjustmentType != WorklistItem::AdjustLoadStoreOffset) { 654 assert(BC.MIB->isCFI(Inst)); 655 uint32_t CFINum = Inst.getOperand(0).getImm(); 656 if (ModifiedCFIIndices.count(CFINum)) 657 continue; 658 ModifiedCFIIndices.insert(CFINum); 659 const MCCFIInstruction *CFI = BF.getCFIFor(Inst); 660 const MCCFIInstruction::OpType Operation = CFI->getOperation(); 661 if (Operation == MCCFIInstruction::OpDefCfa || 662 Operation == MCCFIInstruction::OpDefCfaOffset) 663 Adjustment = 0 - Adjustment; 664 LLVM_DEBUG(dbgs() << "Changing CFI offset from " << CFI->getOffset() 665 << " to " << (CFI->getOffset() + Adjustment) << "\n"); 666 BF.mutateCFIOffsetFor(Inst, CFI->getOffset() + Adjustment); 667 continue; 668 } 669 int32_t SrcImm = 0; 670 MCPhysReg Reg = 0; 671 MCPhysReg StackPtrReg = 0; 672 int64_t StackOffset = 0; 673 bool IsIndexed = false; 674 bool IsLoad = false; 675 bool IsStore = false; 676 bool IsSimple = false; 677 bool IsStoreFromReg = false; 678 uint8_t Size = 0; 679 bool Success = false; 680 Success = BC.MIB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, 681 Reg, SrcImm, StackPtrReg, StackOffset, 682 Size, IsSimple, IsIndexed); 683 if (!Success) { 684 // SP update based on FP value 685 Success = BC.MIB->addToImm(Inst, Adjustment, &*BC.Ctx); 686 assert(Success); 687 continue; 688 } 689 assert(Success && IsSimple && !IsIndexed && (!IsStore || IsStoreFromReg)); 690 if (StackPtrReg != BC.MIB->getFramePointer()) 691 Adjustment = -Adjustment; 692 if (IsLoad) 693 Success = BC.MIB->createRestoreFromStack( 694 Inst, StackPtrReg, StackOffset + Adjustment, Reg, Size); 695 else if (IsStore) 696 Success = BC.MIB->createSaveToStack( 697 Inst, StackPtrReg, StackOffset + Adjustment, Reg, Size); 698 LLVM_DEBUG({ 699 dbgs() << "Adjusted instruction: "; 700 Inst.dump(); 701 }); 702 assert(Success); 703 } 704 } 705 } 706 707 void StackLayoutModifier::initialize() { 708 classifyStackAccesses(); 709 classifyCFIs(); 710 IsInitialized = true; 711 } 712 713 std::atomic_uint64_t ShrinkWrapping::SpillsMovedRegularMode{0}; 714 std::atomic_uint64_t ShrinkWrapping::SpillsMovedPushPopMode{0}; 715 std::atomic_uint64_t ShrinkWrapping::SpillsMovedDynamicCount{0}; 716 std::atomic_uint64_t ShrinkWrapping::SpillsFailedDynamicCount{0}; 717 std::atomic_uint64_t ShrinkWrapping::InstrDynamicCount{0}; 718 std::atomic_uint64_t ShrinkWrapping::StoreDynamicCount{0}; 719 720 using BBIterTy = BinaryBasicBlock::iterator; 721 722 void ShrinkWrapping::classifyCSRUses() { 723 DominatorAnalysis<false> &DA = Info.getDominatorAnalysis(); 724 StackPointerTracking &SPT = Info.getStackPointerTracking(); 725 UsesByReg = std::vector<BitVector>(BC.MRI->getNumRegs(), 726 BitVector(DA.NumInstrs, false)); 727 728 const BitVector &FPAliases = BC.MIB->getAliases(BC.MIB->getFramePointer()); 729 for (BinaryBasicBlock &BB : BF) { 730 for (MCInst &Inst : BB) { 731 if (BC.MIB->isCFI(Inst)) 732 continue; 733 BitVector BV = BitVector(BC.MRI->getNumRegs(), false); 734 BC.MIB->getTouchedRegs(Inst, BV); 735 BV &= CSA.CalleeSaved; 736 for (int I : BV.set_bits()) { 737 if (I == 0) 738 continue; 739 if (CSA.getSavedReg(Inst) != I && CSA.getRestoredReg(Inst) != I) 740 UsesByReg[I].set(DA.ExprToIdx[&Inst]); 741 } 742 if (!SPT.HasFramePointer || !BC.MIB->isCall(Inst)) 743 continue; 744 BV = CSA.CalleeSaved; 745 BV &= FPAliases; 746 for (int I : BV.set_bits()) 747 UsesByReg[I].set(DA.ExprToIdx[&Inst]); 748 } 749 } 750 } 751 752 void ShrinkWrapping::pruneUnwantedCSRs() { 753 BitVector ParamRegs = BC.MIB->getRegsUsedAsParams(); 754 for (unsigned I = 0, E = BC.MRI->getNumRegs(); I != E; ++I) { 755 if (!CSA.CalleeSaved[I]) 756 continue; 757 if (ParamRegs[I]) { 758 CSA.CalleeSaved.reset(I); 759 continue; 760 } 761 if (UsesByReg[I].empty()) { 762 LLVM_DEBUG( 763 dbgs() 764 << "Dismissing Callee-Saved Reg because we found no uses of it:" << I 765 << "\n"); 766 CSA.CalleeSaved.reset(I); 767 continue; 768 } 769 if (!CSA.HasRestores[I]) { 770 LLVM_DEBUG( 771 dbgs() << "Dismissing Callee-Saved Reg because it does not have " 772 "restores:" 773 << I << "\n"); 774 CSA.CalleeSaved.reset(I); 775 } 776 } 777 } 778 779 void ShrinkWrapping::computeSaveLocations() { 780 SavePos = std::vector<SmallSetVector<MCInst *, 4>>(BC.MRI->getNumRegs()); 781 ReachingInsns<true> &RI = Info.getReachingInsnsBackwards(); 782 DominatorAnalysis<false> &DA = Info.getDominatorAnalysis(); 783 StackPointerTracking &SPT = Info.getStackPointerTracking(); 784 785 LLVM_DEBUG(dbgs() << "Checking save/restore possibilities\n"); 786 for (BinaryBasicBlock &BB : BF) { 787 LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n"); 788 789 MCInst *First = BB.begin() != BB.end() ? &*BB.begin() : nullptr; 790 if (!First) 791 continue; 792 793 // Use reaching instructions to detect if we are inside a loop - if we 794 // are, do not consider this BB as valid placement for saves. 795 if (RI.isInLoop(BB)) 796 continue; 797 798 const std::pair<int, int> SPFP = *SPT.getStateBefore(*First); 799 // If we don't know stack state at this point, bail 800 if ((SPFP.first == SPT.SUPERPOSITION || SPFP.first == SPT.EMPTY) && 801 (SPFP.second == SPT.SUPERPOSITION || SPFP.second == SPT.EMPTY)) 802 continue; 803 804 for (unsigned I = 0, E = BC.MRI->getNumRegs(); I != E; ++I) { 805 if (!CSA.CalleeSaved[I]) 806 continue; 807 808 BitVector BBDominatedUses = BitVector(DA.NumInstrs, false); 809 for (int J : UsesByReg[I].set_bits()) 810 if (DA.doesADominateB(*First, J)) 811 BBDominatedUses.set(J); 812 LLVM_DEBUG(dbgs() << "\t\tBB " << BB.getName() << " dominates " 813 << BBDominatedUses.count() << " uses for reg " << I 814 << ". Total uses for reg is " << UsesByReg[I].count() 815 << "\n"); 816 BBDominatedUses &= UsesByReg[I]; 817 if (BBDominatedUses == UsesByReg[I]) { 818 LLVM_DEBUG(dbgs() << "\t\t\tAdded " << BB.getName() 819 << " as a save pos for " << I << "\n"); 820 SavePos[I].insert(First); 821 LLVM_DEBUG({ 822 dbgs() << "Dominated uses are:\n"; 823 for (int J : UsesByReg[I].set_bits()) { 824 dbgs() << "Idx " << J << ": "; 825 DA.Expressions[J]->dump(); 826 } 827 }); 828 } 829 } 830 } 831 832 BestSaveCount = std::vector<uint64_t>(BC.MRI->getNumRegs(), 833 std::numeric_limits<uint64_t>::max()); 834 BestSavePos = std::vector<MCInst *>(BC.MRI->getNumRegs(), nullptr); 835 auto &InsnToBB = Info.getInsnToBBMap(); 836 for (unsigned I = 0, E = BC.MRI->getNumRegs(); I != E; ++I) { 837 if (!CSA.CalleeSaved[I]) 838 continue; 839 840 for (MCInst *Pos : SavePos[I]) { 841 BinaryBasicBlock *BB = InsnToBB[Pos]; 842 uint64_t Count = BB->getExecutionCount(); 843 if (Count != BinaryBasicBlock::COUNT_NO_PROFILE && 844 Count < BestSaveCount[I]) { 845 BestSavePos[I] = Pos; 846 BestSaveCount[I] = Count; 847 } 848 } 849 } 850 } 851 852 void ShrinkWrapping::computeDomOrder() { 853 std::vector<MCPhysReg> Order; 854 for (MCPhysReg I = 0, E = BC.MRI->getNumRegs(); I != E; ++I) { 855 Order.push_back(I); 856 } 857 858 DominatorAnalysis<false> &DA = Info.getDominatorAnalysis(); 859 auto &InsnToBB = Info.getInsnToBBMap(); 860 llvm::sort(Order, [&](const MCPhysReg &A, const MCPhysReg &B) { 861 BinaryBasicBlock *BBA = BestSavePos[A] ? InsnToBB[BestSavePos[A]] : nullptr; 862 BinaryBasicBlock *BBB = BestSavePos[B] ? InsnToBB[BestSavePos[B]] : nullptr; 863 if (BBA == BBB) 864 return A < B; 865 if (!BBA && BBB) 866 return false; 867 if (BBA && !BBB) 868 return true; 869 if (DA.doesADominateB(*BestSavePos[A], *BestSavePos[B])) 870 return true; 871 if (DA.doesADominateB(*BestSavePos[B], *BestSavePos[A])) 872 return false; 873 return A < B; 874 }); 875 876 for (MCPhysReg I = 0, E = BC.MRI->getNumRegs(); I != E; ++I) 877 DomOrder[Order[I]] = I; 878 } 879 880 bool ShrinkWrapping::isBestSavePosCold(unsigned CSR, MCInst *&BestPosSave, 881 uint64_t &TotalEstimatedWin) { 882 const uint64_t CurSavingCost = CSA.SavingCost[CSR]; 883 if (!CSA.CalleeSaved[CSR]) 884 return false; 885 886 uint64_t BestCount = BestSaveCount[CSR]; 887 BestPosSave = BestSavePos[CSR]; 888 bool ShouldMove = false; 889 if (BestCount != std::numeric_limits<uint64_t>::max() && 890 BestCount < (opts::ShrinkWrappingThreshold / 100.0) * CurSavingCost) { 891 LLVM_DEBUG({ 892 auto &InsnToBB = Info.getInsnToBBMap(); 893 dbgs() << "Better position for saves found in func " << BF.getPrintName() 894 << " count << " << BF.getKnownExecutionCount() << "\n"; 895 dbgs() << "Reg: " << CSR 896 << "; New BB: " << InsnToBB[BestPosSave]->getName() 897 << " Freq reduction: " << (CurSavingCost - BestCount) << "\n"; 898 }); 899 TotalEstimatedWin += CurSavingCost - BestCount; 900 ShouldMove = true; 901 } 902 903 if (!ShouldMove) 904 return false; 905 if (!BestPosSave) { 906 LLVM_DEBUG({ 907 dbgs() << "Dropping opportunity because we don't know where to put " 908 "stores -- total est. freq reduc: " 909 << TotalEstimatedWin << "\n"; 910 }); 911 return false; 912 } 913 return true; 914 } 915 916 /// Auxiliar function used to create basic blocks for critical edges and update 917 /// the dominance frontier with these new locations 918 void ShrinkWrapping::splitFrontierCritEdges( 919 BinaryFunction *Func, SmallVector<ProgramPoint, 4> &Frontier, 920 const SmallVector<bool, 4> &IsCritEdge, 921 const SmallVector<BinaryBasicBlock *, 4> &From, 922 const SmallVector<SmallVector<BinaryBasicBlock *, 4>, 4> &To) { 923 LLVM_DEBUG(dbgs() << "splitFrontierCritEdges: Now handling func " 924 << BF.getPrintName() << "\n"); 925 // For every FromBB, there might be one or more critical edges, with 926 // To[I] containing destination BBs. It's important to memorize 927 // the original size of the Frontier as we may append to it while splitting 928 // critical edges originating with blocks with multiple destinations. 929 for (size_t I = 0, IE = Frontier.size(); I < IE; ++I) { 930 if (!IsCritEdge[I]) 931 continue; 932 if (To[I].empty()) 933 continue; 934 BinaryBasicBlock *FromBB = From[I]; 935 LLVM_DEBUG(dbgs() << " - Now handling FrontierBB " << FromBB->getName() 936 << "\n"); 937 // Split edge for every DestinationBBs 938 for (size_t DI = 0, DIE = To[I].size(); DI < DIE; ++DI) { 939 BinaryBasicBlock *DestinationBB = To[I][DI]; 940 LLVM_DEBUG(dbgs() << " - Dest : " << DestinationBB->getName() << "\n"); 941 BinaryBasicBlock *NewBB = Func->splitEdge(FromBB, DestinationBB); 942 // Insert dummy instruction so this BB is never empty (we need this for 943 // PredictiveStackPointerTracking to work, since it annotates instructions 944 // and not BBs). 945 if (NewBB->empty()) { 946 MCInst NewInst; 947 BC.MIB->createNoop(NewInst); 948 NewBB->addInstruction(std::move(NewInst)); 949 scheduleChange(&*NewBB->begin(), WorklistItem(WorklistItem::Erase, 0)); 950 } 951 952 // Update frontier 953 ProgramPoint NewFrontierPP = ProgramPoint::getLastPointAt(*NewBB); 954 if (DI == 0) { 955 // Update frontier inplace 956 Frontier[I] = NewFrontierPP; 957 LLVM_DEBUG(dbgs() << " - Update frontier with " << NewBB->getName() 958 << '\n'); 959 } else { 960 // Append new frontier to the end of the list 961 Frontier.push_back(NewFrontierPP); 962 LLVM_DEBUG(dbgs() << " - Append frontier " << NewBB->getName() 963 << '\n'); 964 } 965 } 966 } 967 } 968 969 SmallVector<ProgramPoint, 4> 970 ShrinkWrapping::doRestorePlacement(MCInst *BestPosSave, unsigned CSR, 971 uint64_t TotalEstimatedWin) { 972 SmallVector<ProgramPoint, 4> Frontier; 973 SmallVector<bool, 4> IsCritEdge; 974 bool CannotPlace = false; 975 DominatorAnalysis<false> &DA = Info.getDominatorAnalysis(); 976 977 SmallVector<BinaryBasicBlock *, 4> CritEdgesFrom; 978 SmallVector<SmallVector<BinaryBasicBlock *, 4>, 4> CritEdgesTo; 979 // In case of a critical edge, we need to create extra BBs to host restores 980 // into edges transitioning to the dominance frontier, otherwise we pull these 981 // restores to inside the dominated area. 982 Frontier = DA.getDominanceFrontierFor(*BestPosSave).takeVector(); 983 LLVM_DEBUG({ 984 dbgs() << "Dumping dominance frontier for "; 985 BC.printInstruction(dbgs(), *BestPosSave); 986 for (ProgramPoint &PP : Frontier) 987 if (PP.isInst()) 988 BC.printInstruction(dbgs(), *PP.getInst()); 989 else 990 dbgs() << PP.getBB()->getName() << "\n"; 991 }); 992 for (ProgramPoint &PP : Frontier) { 993 bool HasCritEdges = false; 994 if (PP.isInst() && BC.MIB->isTerminator(*PP.getInst()) && 995 doesInstUsesCSR(*PP.getInst(), CSR)) 996 CannotPlace = true; 997 BinaryBasicBlock *FrontierBB = Info.getParentBB(PP); 998 CritEdgesFrom.emplace_back(FrontierBB); 999 CritEdgesTo.emplace_back(0); 1000 SmallVector<BinaryBasicBlock *, 4> &Dests = CritEdgesTo.back(); 1001 // Check for invoke instructions at the dominance frontier, which indicates 1002 // the landing pad is not dominated. 1003 if (PP.isInst() && BC.MIB->isInvoke(*PP.getInst())) { 1004 LLVM_DEBUG( 1005 dbgs() << "Bailing on restore placement to avoid LP splitting\n"); 1006 Frontier.clear(); 1007 return Frontier; 1008 } 1009 doForAllSuccs(*FrontierBB, [&](ProgramPoint P) { 1010 if (!DA.doesADominateB(*BestPosSave, P)) { 1011 Dests.emplace_back(Info.getParentBB(P)); 1012 return; 1013 } 1014 HasCritEdges = true; 1015 }); 1016 IsCritEdge.push_back(HasCritEdges); 1017 } 1018 // Restores cannot be placed in empty BBs because we have a dataflow 1019 // analysis that depends on insertions happening before real instructions 1020 // (PredictiveStackPointerTracking). Detect now for empty BBs and add a 1021 // dummy nop that is scheduled to be removed later. 1022 bool InvalidateRequired = false; 1023 for (BinaryBasicBlock *&BB : BF.layout()) { 1024 if (BB->size() != 0) 1025 continue; 1026 MCInst NewInst; 1027 BC.MIB->createNoop(NewInst); 1028 auto II = BB->addInstruction(std::move(NewInst)); 1029 scheduleChange(&*II, WorklistItem(WorklistItem::Erase, 0)); 1030 InvalidateRequired = true; 1031 } 1032 if (std::accumulate(IsCritEdge.begin(), IsCritEdge.end(), 0)) { 1033 LLVM_DEBUG({ 1034 dbgs() << "Now detected critical edges in the following frontier:\n"; 1035 for (ProgramPoint &PP : Frontier) { 1036 if (PP.isBB()) { 1037 dbgs() << " BB: " << PP.getBB()->getName() << "\n"; 1038 } else { 1039 dbgs() << " Inst: "; 1040 PP.getInst()->dump(); 1041 } 1042 } 1043 }); 1044 splitFrontierCritEdges(&BF, Frontier, IsCritEdge, CritEdgesFrom, 1045 CritEdgesTo); 1046 InvalidateRequired = true; 1047 } 1048 if (InvalidateRequired) { 1049 // BitVectors that represent all insns of the function are invalid now 1050 // since we changed BBs/Insts. Re-run steps that depend on pointers being 1051 // valid 1052 Info.invalidateAll(); 1053 classifyCSRUses(); 1054 } 1055 if (CannotPlace) { 1056 LLVM_DEBUG({ 1057 dbgs() << "Dropping opportunity because restore placement failed" 1058 " -- total est. freq reduc: " 1059 << TotalEstimatedWin << "\n"; 1060 }); 1061 Frontier.clear(); 1062 return Frontier; 1063 } 1064 return Frontier; 1065 } 1066 1067 bool ShrinkWrapping::validatePushPopsMode(unsigned CSR, MCInst *BestPosSave, 1068 int64_t SaveOffset) { 1069 if (FA.requiresAlignment(BF)) { 1070 LLVM_DEBUG({ 1071 dbgs() << "Reg " << CSR 1072 << " is not using push/pops due to function " 1073 "alignment requirements.\n"; 1074 }); 1075 return false; 1076 } 1077 for (MCInst *Save : CSA.getSavesByReg(CSR)) { 1078 if (!SLM.canCollapseRegion(Save)) { 1079 LLVM_DEBUG(dbgs() << "Reg " << CSR << " cannot collapse region.\n"); 1080 return false; 1081 } 1082 } 1083 // Abort if one of the restores for this CSR is not a POP. 1084 for (MCInst *Load : CSA.getRestoresByReg(CSR)) { 1085 if (!BC.MIB->isPop(*Load)) { 1086 LLVM_DEBUG(dbgs() << "Reg " << CSR << " has a mismatching restore.\n"); 1087 return false; 1088 } 1089 } 1090 1091 StackPointerTracking &SPT = Info.getStackPointerTracking(); 1092 // Abort if we are inserting a push into an entry BB (offset -8) and this 1093 // func sets up a frame pointer. 1094 if (!SLM.canInsertRegion(BestPosSave) || SaveOffset == SPT.SUPERPOSITION || 1095 SaveOffset == SPT.EMPTY || (SaveOffset == -8 && SPT.HasFramePointer)) { 1096 LLVM_DEBUG({ 1097 dbgs() << "Reg " << CSR 1098 << " cannot insert region or we are " 1099 "trying to insert a push into entry bb.\n"; 1100 }); 1101 return false; 1102 } 1103 return true; 1104 } 1105 1106 SmallVector<ProgramPoint, 4> ShrinkWrapping::fixPopsPlacements( 1107 const SmallVector<ProgramPoint, 4> &RestorePoints, int64_t SaveOffset, 1108 unsigned CSR) { 1109 SmallVector<ProgramPoint, 4> FixedRestorePoints = RestorePoints; 1110 // Moving pop locations to the correct sp offset 1111 ReachingInsns<true> &RI = Info.getReachingInsnsBackwards(); 1112 StackPointerTracking &SPT = Info.getStackPointerTracking(); 1113 for (ProgramPoint &PP : FixedRestorePoints) { 1114 BinaryBasicBlock *BB = Info.getParentBB(PP); 1115 bool Found = false; 1116 if (SPT.getStateAt(ProgramPoint::getLastPointAt(*BB))->first == 1117 SaveOffset) { 1118 BitVector BV = *RI.getStateAt(ProgramPoint::getLastPointAt(*BB)); 1119 BV &= UsesByReg[CSR]; 1120 if (!BV.any()) { 1121 Found = true; 1122 PP = BB; 1123 continue; 1124 } 1125 } 1126 for (auto RIt = BB->rbegin(), End = BB->rend(); RIt != End; ++RIt) { 1127 if (SPT.getStateBefore(*RIt)->first == SaveOffset) { 1128 BitVector BV = *RI.getStateAt(*RIt); 1129 BV &= UsesByReg[CSR]; 1130 if (!BV.any()) { 1131 Found = true; 1132 PP = &*RIt; 1133 break; 1134 } 1135 } 1136 } 1137 if (!Found) { 1138 LLVM_DEBUG({ 1139 dbgs() << "Could not find restore insertion point for " << CSR 1140 << ", falling back to load/store mode\n"; 1141 }); 1142 FixedRestorePoints.clear(); 1143 return FixedRestorePoints; 1144 } 1145 } 1146 return FixedRestorePoints; 1147 } 1148 1149 void ShrinkWrapping::scheduleOldSaveRestoresRemoval(unsigned CSR, 1150 bool UsePushPops) { 1151 1152 for (BinaryBasicBlock *&BB : BF.layout()) { 1153 std::vector<MCInst *> CFIs; 1154 for (auto I = BB->rbegin(), E = BB->rend(); I != E; ++I) { 1155 MCInst &Inst = *I; 1156 if (BC.MIB->isCFI(Inst)) { 1157 // Delete all offset CFIs related to this CSR 1158 if (SLM.getOffsetCFIReg(Inst) == CSR) { 1159 HasDeletedOffsetCFIs[CSR] = true; 1160 scheduleChange(&Inst, WorklistItem(WorklistItem::Erase, CSR)); 1161 continue; 1162 } 1163 CFIs.push_back(&Inst); 1164 continue; 1165 } 1166 1167 uint16_t SavedReg = CSA.getSavedReg(Inst); 1168 uint16_t RestoredReg = CSA.getRestoredReg(Inst); 1169 if (SavedReg != CSR && RestoredReg != CSR) { 1170 CFIs.clear(); 1171 continue; 1172 } 1173 1174 scheduleChange(&Inst, WorklistItem(UsePushPops 1175 ? WorklistItem::Erase 1176 : WorklistItem::ChangeToAdjustment, 1177 CSR)); 1178 1179 // Delete associated CFIs 1180 const bool RecordDeletedPushCFIs = 1181 SavedReg == CSR && DeletedPushCFIs[CSR].empty(); 1182 const bool RecordDeletedPopCFIs = 1183 RestoredReg == CSR && DeletedPopCFIs[CSR].empty(); 1184 for (MCInst *CFI : CFIs) { 1185 const MCCFIInstruction *MCCFI = BF.getCFIFor(*CFI); 1186 // Do not touch these... 1187 if (MCCFI->getOperation() == MCCFIInstruction::OpRestoreState || 1188 MCCFI->getOperation() == MCCFIInstruction::OpRememberState) 1189 continue; 1190 scheduleChange(CFI, WorklistItem(WorklistItem::Erase, CSR)); 1191 if (RecordDeletedPushCFIs) { 1192 // Do not record this to be replayed later because we are going to 1193 // rebuild it. 1194 if (MCCFI->getOperation() == MCCFIInstruction::OpDefCfaOffset) 1195 continue; 1196 DeletedPushCFIs[CSR].push_back(CFI->getOperand(0).getImm()); 1197 } 1198 if (RecordDeletedPopCFIs) { 1199 if (MCCFI->getOperation() == MCCFIInstruction::OpDefCfaOffset) 1200 continue; 1201 DeletedPopCFIs[CSR].push_back(CFI->getOperand(0).getImm()); 1202 } 1203 } 1204 CFIs.clear(); 1205 } 1206 } 1207 } 1208 1209 bool ShrinkWrapping::doesInstUsesCSR(const MCInst &Inst, uint16_t CSR) { 1210 if (BC.MIB->isCFI(Inst) || CSA.getSavedReg(Inst) == CSR || 1211 CSA.getRestoredReg(Inst) == CSR) 1212 return false; 1213 BitVector BV = BitVector(BC.MRI->getNumRegs(), false); 1214 BC.MIB->getTouchedRegs(Inst, BV); 1215 return BV[CSR]; 1216 } 1217 1218 void ShrinkWrapping::scheduleSaveRestoreInsertions( 1219 unsigned CSR, MCInst *BestPosSave, 1220 SmallVector<ProgramPoint, 4> &RestorePoints, bool UsePushPops) { 1221 auto &InsnToBB = Info.getInsnToBBMap(); 1222 const FrameIndexEntry *FIESave = CSA.SaveFIEByReg[CSR]; 1223 const FrameIndexEntry *FIELoad = CSA.LoadFIEByReg[CSR]; 1224 assert(FIESave && FIELoad && "Invalid CSR"); 1225 1226 LLVM_DEBUG({ 1227 dbgs() << "Scheduling save insertion at: "; 1228 BestPosSave->dump(); 1229 }); 1230 1231 scheduleChange(BestPosSave, 1232 UsePushPops ? WorklistItem::InsertPushOrPop 1233 : WorklistItem::InsertLoadOrStore, 1234 *FIESave, CSR); 1235 1236 for (ProgramPoint &PP : RestorePoints) { 1237 BinaryBasicBlock *FrontierBB = Info.getParentBB(PP); 1238 LLVM_DEBUG({ 1239 dbgs() << "Scheduling restore insertion at: "; 1240 if (PP.isInst()) 1241 PP.getInst()->dump(); 1242 else 1243 dbgs() << PP.getBB()->getName() << "\n"; 1244 }); 1245 MCInst *Term = 1246 FrontierBB->getTerminatorBefore(PP.isInst() ? PP.getInst() : nullptr); 1247 if (Term) 1248 PP = Term; 1249 bool PrecededByPrefix = false; 1250 if (PP.isInst()) { 1251 auto Iter = FrontierBB->findInstruction(PP.getInst()); 1252 if (Iter != FrontierBB->end() && Iter != FrontierBB->begin()) { 1253 --Iter; 1254 PrecededByPrefix = BC.MIB->isPrefix(*Iter); 1255 } 1256 } 1257 if (PP.isInst() && 1258 (doesInstUsesCSR(*PP.getInst(), CSR) || PrecededByPrefix)) { 1259 assert(!InsnToBB[PP.getInst()]->hasTerminatorAfter(PP.getInst()) && 1260 "cannot move to end of bb"); 1261 scheduleChange(InsnToBB[PP.getInst()], 1262 UsePushPops ? WorklistItem::InsertPushOrPop 1263 : WorklistItem::InsertLoadOrStore, 1264 *FIELoad, CSR); 1265 continue; 1266 } 1267 scheduleChange(PP, 1268 UsePushPops ? WorklistItem::InsertPushOrPop 1269 : WorklistItem::InsertLoadOrStore, 1270 *FIELoad, CSR); 1271 } 1272 } 1273 1274 void ShrinkWrapping::moveSaveRestores() { 1275 bool DisablePushPopMode = false; 1276 bool UsedPushPopMode = false; 1277 // Keeps info about successfully moved regs: reg index, save position and 1278 // save size 1279 std::vector<std::tuple<unsigned, MCInst *, size_t>> MovedRegs; 1280 uint64_t TotalEstimatedWin = 0; 1281 1282 for (unsigned I = 0, E = BC.MRI->getNumRegs(); I != E; ++I) { 1283 MCInst *BestPosSave = nullptr; 1284 uint64_t EstimatedWin = 0; 1285 if (!isBestSavePosCold(I, BestPosSave, EstimatedWin)) 1286 continue; 1287 SmallVector<ProgramPoint, 4> RestorePoints = 1288 doRestorePlacement(BestPosSave, I, EstimatedWin); 1289 if (RestorePoints.empty()) { 1290 SpillsFailedDynamicCount += EstimatedWin; 1291 continue; 1292 } 1293 1294 const FrameIndexEntry *FIESave = CSA.SaveFIEByReg[I]; 1295 const FrameIndexEntry *FIELoad = CSA.LoadFIEByReg[I]; 1296 (void)FIELoad; 1297 assert(FIESave && FIELoad); 1298 StackPointerTracking &SPT = Info.getStackPointerTracking(); 1299 const std::pair<int, int> SPFP = *SPT.getStateBefore(*BestPosSave); 1300 int SaveOffset = SPFP.first; 1301 uint8_t SaveSize = FIESave->Size; 1302 1303 // If we don't know stack state at this point, bail 1304 if ((SPFP.first == SPT.SUPERPOSITION || SPFP.first == SPT.EMPTY) && 1305 (SPFP.second == SPT.SUPERPOSITION || SPFP.second == SPT.EMPTY)) { 1306 SpillsFailedDynamicCount += EstimatedWin; 1307 continue; 1308 } 1309 1310 // Operation mode: if true, will insert push/pops instead of loads/restores 1311 bool UsePushPops = validatePushPopsMode(I, BestPosSave, SaveOffset); 1312 1313 if (UsePushPops) { 1314 SmallVector<ProgramPoint, 4> FixedRestorePoints = 1315 fixPopsPlacements(RestorePoints, SaveOffset, I); 1316 if (FixedRestorePoints.empty()) 1317 UsePushPops = false; 1318 else 1319 RestorePoints = FixedRestorePoints; 1320 } 1321 1322 // Disable push-pop mode for all CSRs in this function 1323 if (!UsePushPops) 1324 DisablePushPopMode = true; 1325 else 1326 UsedPushPopMode = true; 1327 1328 scheduleOldSaveRestoresRemoval(I, UsePushPops); 1329 scheduleSaveRestoreInsertions(I, BestPosSave, RestorePoints, UsePushPops); 1330 MovedRegs.emplace_back(std::make_tuple(I, BestPosSave, SaveSize)); 1331 TotalEstimatedWin += EstimatedWin; 1332 } 1333 1334 // Revert push-pop mode if it failed for a single CSR 1335 if (DisablePushPopMode && UsedPushPopMode) { 1336 UsedPushPopMode = false; 1337 for (BinaryBasicBlock &BB : BF) { 1338 auto WRI = Todo.find(&BB); 1339 if (WRI != Todo.end()) { 1340 std::vector<WorklistItem> &TodoList = WRI->second; 1341 for (WorklistItem &Item : TodoList) 1342 if (Item.Action == WorklistItem::InsertPushOrPop) 1343 Item.Action = WorklistItem::InsertLoadOrStore; 1344 } 1345 for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) { 1346 MCInst &Inst = *I; 1347 auto TodoList = BC.MIB->tryGetAnnotationAs<std::vector<WorklistItem>>( 1348 Inst, getAnnotationIndex()); 1349 if (!TodoList) 1350 continue; 1351 bool isCFI = BC.MIB->isCFI(Inst); 1352 for (WorklistItem &Item : *TodoList) { 1353 if (Item.Action == WorklistItem::InsertPushOrPop) 1354 Item.Action = WorklistItem::InsertLoadOrStore; 1355 if (!isCFI && Item.Action == WorklistItem::Erase) 1356 Item.Action = WorklistItem::ChangeToAdjustment; 1357 } 1358 } 1359 } 1360 } 1361 SpillsMovedDynamicCount += TotalEstimatedWin; 1362 1363 // Update statistics 1364 if (!UsedPushPopMode) { 1365 SpillsMovedRegularMode += MovedRegs.size(); 1366 return; 1367 } 1368 1369 // Schedule modifications to stack-accessing instructions via 1370 // StackLayoutModifier. 1371 SpillsMovedPushPopMode += MovedRegs.size(); 1372 for (std::tuple<unsigned, MCInst *, size_t> &I : MovedRegs) { 1373 unsigned RegNdx; 1374 MCInst *SavePos; 1375 size_t SaveSize; 1376 std::tie(RegNdx, SavePos, SaveSize) = I; 1377 for (MCInst *Save : CSA.getSavesByReg(RegNdx)) 1378 SLM.collapseRegion(Save); 1379 SLM.insertRegion(SavePos, SaveSize); 1380 } 1381 } 1382 1383 namespace { 1384 /// Helper function to identify whether two basic blocks created by splitting 1385 /// a critical edge have the same contents. 1386 bool isIdenticalSplitEdgeBB(const BinaryContext &BC, const BinaryBasicBlock &A, 1387 const BinaryBasicBlock &B) { 1388 if (A.succ_size() != B.succ_size()) 1389 return false; 1390 if (A.succ_size() != 1) 1391 return false; 1392 1393 if (*A.succ_begin() != *B.succ_begin()) 1394 return false; 1395 1396 if (A.size() != B.size()) 1397 return false; 1398 1399 // Compare instructions 1400 auto I = A.begin(), E = A.end(); 1401 auto OtherI = B.begin(), OtherE = B.end(); 1402 while (I != E && OtherI != OtherE) { 1403 if (I->getOpcode() != OtherI->getOpcode()) 1404 return false; 1405 if (!BC.MIB->equals(*I, *OtherI, [](const MCSymbol *A, const MCSymbol *B) { 1406 return true; 1407 })) 1408 return false; 1409 ++I; 1410 ++OtherI; 1411 } 1412 return true; 1413 } 1414 } // namespace 1415 1416 bool ShrinkWrapping::foldIdenticalSplitEdges() { 1417 bool Changed = false; 1418 for (auto Iter = BF.begin(); Iter != BF.end(); ++Iter) { 1419 BinaryBasicBlock &BB = *Iter; 1420 if (!BB.getName().startswith(".LSplitEdge")) 1421 continue; 1422 for (auto RIter = BF.rbegin(); RIter != BF.rend(); ++RIter) { 1423 BinaryBasicBlock &RBB = *RIter; 1424 if (&RBB == &BB) 1425 break; 1426 if (!RBB.getName().startswith(".LSplitEdge") || !RBB.isValid() || 1427 !isIdenticalSplitEdgeBB(BC, *Iter, RBB)) 1428 continue; 1429 assert(RBB.pred_size() == 1 && "Invalid split edge BB"); 1430 BinaryBasicBlock *Pred = *RBB.pred_begin(); 1431 uint64_t OrigCount = Pred->branch_info_begin()->Count; 1432 uint64_t OrigMispreds = Pred->branch_info_begin()->MispredictedCount; 1433 BF.replaceJumpTableEntryIn(Pred, &RBB, &BB); 1434 Pred->replaceSuccessor(&RBB, &BB, OrigCount, OrigMispreds); 1435 Changed = true; 1436 // Remove the block from CFG 1437 RBB.markValid(false); 1438 } 1439 } 1440 1441 return Changed; 1442 } 1443 1444 namespace { 1445 1446 // A special StackPointerTracking that compensates for our future plans 1447 // in removing/adding insn. 1448 class PredictiveStackPointerTracking 1449 : public StackPointerTrackingBase<PredictiveStackPointerTracking> { 1450 friend class DataflowAnalysis<PredictiveStackPointerTracking, 1451 std::pair<int, int>>; 1452 decltype(ShrinkWrapping::Todo) &TodoMap; 1453 DataflowInfoManager &Info; 1454 1455 Optional<unsigned> AnnotationIndex; 1456 1457 protected: 1458 void compNextAux(const MCInst &Point, 1459 const std::vector<ShrinkWrapping::WorklistItem> &TodoItems, 1460 std::pair<int, int> &Res) { 1461 for (const ShrinkWrapping::WorklistItem &Item : TodoItems) { 1462 if (Item.Action == ShrinkWrapping::WorklistItem::Erase && 1463 BC.MIB->isPush(Point)) { 1464 Res.first += BC.MIB->getPushSize(Point); 1465 continue; 1466 } 1467 if (Item.Action == ShrinkWrapping::WorklistItem::Erase && 1468 BC.MIB->isPop(Point)) { 1469 Res.first -= BC.MIB->getPopSize(Point); 1470 continue; 1471 } 1472 if (Item.Action == ShrinkWrapping::WorklistItem::InsertPushOrPop && 1473 Item.FIEToInsert.IsStore) { 1474 Res.first -= Item.FIEToInsert.Size; 1475 continue; 1476 } 1477 if (Item.Action == ShrinkWrapping::WorklistItem::InsertPushOrPop && 1478 Item.FIEToInsert.IsLoad) { 1479 Res.first += Item.FIEToInsert.Size; 1480 continue; 1481 } 1482 } 1483 } 1484 1485 std::pair<int, int> computeNext(const MCInst &Point, 1486 const std::pair<int, int> &Cur) { 1487 std::pair<int, int> Res = 1488 StackPointerTrackingBase<PredictiveStackPointerTracking>::computeNext( 1489 Point, Cur); 1490 if (Res.first == StackPointerTracking::SUPERPOSITION || 1491 Res.first == StackPointerTracking::EMPTY) 1492 return Res; 1493 auto TodoItems = 1494 BC.MIB->tryGetAnnotationAs<std::vector<ShrinkWrapping::WorklistItem>>( 1495 Point, ShrinkWrapping::getAnnotationName()); 1496 if (TodoItems) 1497 compNextAux(Point, *TodoItems, Res); 1498 auto &InsnToBBMap = Info.getInsnToBBMap(); 1499 if (&*InsnToBBMap[&Point]->rbegin() != &Point) 1500 return Res; 1501 auto WRI = TodoMap.find(InsnToBBMap[&Point]); 1502 if (WRI == TodoMap.end()) 1503 return Res; 1504 compNextAux(Point, WRI->second, Res); 1505 return Res; 1506 } 1507 1508 StringRef getAnnotationName() const { 1509 return StringRef("PredictiveStackPointerTracking"); 1510 } 1511 1512 public: 1513 PredictiveStackPointerTracking(BinaryFunction &BF, 1514 decltype(ShrinkWrapping::Todo) &TodoMap, 1515 DataflowInfoManager &Info, 1516 MCPlusBuilder::AllocatorIdTy AllocatorId = 0) 1517 : StackPointerTrackingBase<PredictiveStackPointerTracking>(BF, 1518 AllocatorId), 1519 TodoMap(TodoMap), Info(Info) {} 1520 1521 void run() { 1522 StackPointerTrackingBase<PredictiveStackPointerTracking>::run(); 1523 } 1524 }; 1525 1526 } // end anonymous namespace 1527 1528 void ShrinkWrapping::insertUpdatedCFI(unsigned CSR, int SPValPush, 1529 int SPValPop) { 1530 MCInst *SavePoint = nullptr; 1531 for (BinaryBasicBlock &BB : BF) { 1532 for (auto InstIter = BB.rbegin(), EndIter = BB.rend(); InstIter != EndIter; 1533 ++InstIter) { 1534 int32_t SrcImm = 0; 1535 MCPhysReg Reg = 0; 1536 MCPhysReg StackPtrReg = 0; 1537 int64_t StackOffset = 0; 1538 bool IsIndexed = false; 1539 bool IsLoad = false; 1540 bool IsStore = false; 1541 bool IsSimple = false; 1542 bool IsStoreFromReg = false; 1543 uint8_t Size = 0; 1544 if (!BC.MIB->isStackAccess(*InstIter, IsLoad, IsStore, IsStoreFromReg, 1545 Reg, SrcImm, StackPtrReg, StackOffset, Size, 1546 IsSimple, IsIndexed)) 1547 continue; 1548 if (Reg != CSR || !IsStore || !IsSimple) 1549 continue; 1550 SavePoint = &*InstIter; 1551 break; 1552 } 1553 if (SavePoint) 1554 break; 1555 } 1556 assert(SavePoint); 1557 LLVM_DEBUG({ 1558 dbgs() << "Now using as save point for reg " << CSR << " :"; 1559 SavePoint->dump(); 1560 }); 1561 bool PrevAffectedZone = false; 1562 BinaryBasicBlock *PrevBB = nullptr; 1563 DominatorAnalysis<false> &DA = Info.getDominatorAnalysis(); 1564 for (BinaryBasicBlock *BB : BF.layout()) { 1565 if (BB->size() == 0) 1566 continue; 1567 const bool InAffectedZoneAtEnd = DA.count(*BB->rbegin(), *SavePoint); 1568 const bool InAffectedZoneAtBegin = 1569 (*DA.getStateBefore(*BB->begin()))[DA.ExprToIdx[SavePoint]]; 1570 bool InAffectedZone = InAffectedZoneAtBegin; 1571 for (auto InstIter = BB->begin(); InstIter != BB->end(); ++InstIter) { 1572 const bool CurZone = DA.count(*InstIter, *SavePoint); 1573 if (InAffectedZone != CurZone) { 1574 auto InsertionIter = InstIter; 1575 ++InsertionIter; 1576 InAffectedZone = CurZone; 1577 if (InAffectedZone) 1578 InstIter = insertCFIsForPushOrPop(*BB, InsertionIter, CSR, true, 0, 1579 SPValPop); 1580 else 1581 InstIter = insertCFIsForPushOrPop(*BB, InsertionIter, CSR, false, 0, 1582 SPValPush); 1583 --InstIter; 1584 } 1585 } 1586 // Are we at the first basic block or hot-cold split point? 1587 if (!PrevBB || (BF.isSplit() && BB->isCold() != PrevBB->isCold())) { 1588 if (InAffectedZoneAtBegin) 1589 insertCFIsForPushOrPop(*BB, BB->begin(), CSR, true, 0, SPValPush); 1590 } else if (InAffectedZoneAtBegin != PrevAffectedZone) { 1591 if (InAffectedZoneAtBegin) 1592 insertCFIsForPushOrPop(*PrevBB, PrevBB->end(), CSR, true, 0, SPValPush); 1593 else 1594 insertCFIsForPushOrPop(*PrevBB, PrevBB->end(), CSR, false, 0, SPValPop); 1595 } 1596 PrevAffectedZone = InAffectedZoneAtEnd; 1597 PrevBB = BB; 1598 } 1599 } 1600 1601 void ShrinkWrapping::rebuildCFIForSP() { 1602 for (BinaryBasicBlock &BB : BF) { 1603 for (MCInst &Inst : BB) { 1604 if (!BC.MIB->isCFI(Inst)) 1605 continue; 1606 const MCCFIInstruction *CFI = BF.getCFIFor(Inst); 1607 if (CFI->getOperation() == MCCFIInstruction::OpDefCfaOffset) 1608 BC.MIB->addAnnotation(Inst, "DeleteMe", 0U, AllocatorId); 1609 } 1610 } 1611 1612 int PrevSPVal = -8; 1613 BinaryBasicBlock *PrevBB = nullptr; 1614 StackPointerTracking &SPT = Info.getStackPointerTracking(); 1615 for (BinaryBasicBlock *BB : BF.layout()) { 1616 if (BB->size() == 0) 1617 continue; 1618 const int SPValAtEnd = SPT.getStateAt(*BB->rbegin())->first; 1619 const int SPValAtBegin = SPT.getStateBefore(*BB->begin())->first; 1620 int SPVal = SPValAtBegin; 1621 for (auto Iter = BB->begin(); Iter != BB->end(); ++Iter) { 1622 const int CurVal = SPT.getStateAt(*Iter)->first; 1623 if (SPVal != CurVal) { 1624 auto InsertionIter = Iter; 1625 ++InsertionIter; 1626 Iter = BF.addCFIInstruction( 1627 BB, InsertionIter, 1628 MCCFIInstruction::cfiDefCfaOffset(nullptr, -CurVal)); 1629 SPVal = CurVal; 1630 } 1631 } 1632 if (BF.isSplit() && PrevBB && BB->isCold() != PrevBB->isCold()) 1633 BF.addCFIInstruction( 1634 BB, BB->begin(), 1635 MCCFIInstruction::cfiDefCfaOffset(nullptr, -SPValAtBegin)); 1636 else if (SPValAtBegin != PrevSPVal) 1637 BF.addCFIInstruction( 1638 PrevBB, PrevBB->end(), 1639 MCCFIInstruction::cfiDefCfaOffset(nullptr, -SPValAtBegin)); 1640 PrevSPVal = SPValAtEnd; 1641 PrevBB = BB; 1642 } 1643 1644 for (BinaryBasicBlock &BB : BF) 1645 for (auto I = BB.begin(); I != BB.end();) 1646 if (BC.MIB->hasAnnotation(*I, "DeleteMe")) 1647 I = BB.eraseInstruction(I); 1648 else 1649 ++I; 1650 } 1651 1652 MCInst ShrinkWrapping::createStackAccess(int SPVal, int FPVal, 1653 const FrameIndexEntry &FIE, 1654 bool CreatePushOrPop) { 1655 MCInst NewInst; 1656 if (SPVal != StackPointerTracking::SUPERPOSITION && 1657 SPVal != StackPointerTracking::EMPTY) { 1658 if (FIE.IsLoad) { 1659 if (!BC.MIB->createRestoreFromStack(NewInst, BC.MIB->getStackPointer(), 1660 FIE.StackOffset - SPVal, FIE.RegOrImm, 1661 FIE.Size)) { 1662 errs() << "createRestoreFromStack: not supported on this platform\n"; 1663 abort(); 1664 } 1665 } else { 1666 if (!BC.MIB->createSaveToStack(NewInst, BC.MIB->getStackPointer(), 1667 FIE.StackOffset - SPVal, FIE.RegOrImm, 1668 FIE.Size)) { 1669 errs() << "createSaveToStack: not supported on this platform\n"; 1670 abort(); 1671 } 1672 } 1673 if (CreatePushOrPop) 1674 BC.MIB->changeToPushOrPop(NewInst); 1675 return NewInst; 1676 } 1677 assert(FPVal != StackPointerTracking::SUPERPOSITION && 1678 FPVal != StackPointerTracking::EMPTY); 1679 1680 if (FIE.IsLoad) { 1681 if (!BC.MIB->createRestoreFromStack(NewInst, BC.MIB->getFramePointer(), 1682 FIE.StackOffset - FPVal, FIE.RegOrImm, 1683 FIE.Size)) { 1684 errs() << "createRestoreFromStack: not supported on this platform\n"; 1685 abort(); 1686 } 1687 } else { 1688 if (!BC.MIB->createSaveToStack(NewInst, BC.MIB->getFramePointer(), 1689 FIE.StackOffset - FPVal, FIE.RegOrImm, 1690 FIE.Size)) { 1691 errs() << "createSaveToStack: not supported on this platform\n"; 1692 abort(); 1693 } 1694 } 1695 return NewInst; 1696 } 1697 1698 void ShrinkWrapping::updateCFIInstOffset(MCInst &Inst, int64_t NewOffset) { 1699 const MCCFIInstruction *CFI = BF.getCFIFor(Inst); 1700 if (UpdatedCFIs.count(CFI)) 1701 return; 1702 1703 switch (CFI->getOperation()) { 1704 case MCCFIInstruction::OpDefCfa: 1705 case MCCFIInstruction::OpDefCfaRegister: 1706 case MCCFIInstruction::OpDefCfaOffset: 1707 CFI = BF.mutateCFIOffsetFor(Inst, -NewOffset); 1708 break; 1709 case MCCFIInstruction::OpOffset: 1710 default: 1711 break; 1712 } 1713 1714 UpdatedCFIs.insert(CFI); 1715 } 1716 1717 BBIterTy ShrinkWrapping::insertCFIsForPushOrPop(BinaryBasicBlock &BB, 1718 BBIterTy Pos, unsigned Reg, 1719 bool isPush, int Sz, 1720 int64_t NewOffset) { 1721 if (isPush) { 1722 for (uint32_t Idx : DeletedPushCFIs[Reg]) { 1723 Pos = BF.addCFIPseudo(&BB, Pos, Idx); 1724 updateCFIInstOffset(*Pos++, NewOffset); 1725 } 1726 if (HasDeletedOffsetCFIs[Reg]) { 1727 Pos = BF.addCFIInstruction( 1728 &BB, Pos, 1729 MCCFIInstruction::createOffset( 1730 nullptr, BC.MRI->getDwarfRegNum(Reg, false), NewOffset)); 1731 ++Pos; 1732 } 1733 } else { 1734 for (uint32_t Idx : DeletedPopCFIs[Reg]) { 1735 Pos = BF.addCFIPseudo(&BB, Pos, Idx); 1736 updateCFIInstOffset(*Pos++, NewOffset); 1737 } 1738 if (HasDeletedOffsetCFIs[Reg]) { 1739 Pos = BF.addCFIInstruction( 1740 &BB, Pos, 1741 MCCFIInstruction::createSameValue( 1742 nullptr, BC.MRI->getDwarfRegNum(Reg, false))); 1743 ++Pos; 1744 } 1745 } 1746 return Pos; 1747 } 1748 1749 BBIterTy ShrinkWrapping::processInsertion(BBIterTy InsertionPoint, 1750 BinaryBasicBlock *CurBB, 1751 const WorklistItem &Item, 1752 int64_t SPVal, int64_t FPVal) { 1753 // Trigger CFI reconstruction for this CSR if necessary - writing to 1754 // PushOffsetByReg/PopOffsetByReg *will* trigger CFI update 1755 if ((Item.FIEToInsert.IsStore && 1756 !DeletedPushCFIs[Item.AffectedReg].empty()) || 1757 (Item.FIEToInsert.IsLoad && !DeletedPopCFIs[Item.AffectedReg].empty()) || 1758 HasDeletedOffsetCFIs[Item.AffectedReg]) { 1759 if (Item.Action == WorklistItem::InsertPushOrPop) { 1760 if (Item.FIEToInsert.IsStore) 1761 PushOffsetByReg[Item.AffectedReg] = SPVal - Item.FIEToInsert.Size; 1762 else 1763 PopOffsetByReg[Item.AffectedReg] = SPVal; 1764 } else { 1765 if (Item.FIEToInsert.IsStore) 1766 PushOffsetByReg[Item.AffectedReg] = Item.FIEToInsert.StackOffset; 1767 else 1768 PopOffsetByReg[Item.AffectedReg] = Item.FIEToInsert.StackOffset; 1769 } 1770 } 1771 1772 LLVM_DEBUG({ 1773 dbgs() << "Creating stack access with SPVal = " << SPVal 1774 << "; stack offset = " << Item.FIEToInsert.StackOffset 1775 << " Is push = " << (Item.Action == WorklistItem::InsertPushOrPop) 1776 << "\n"; 1777 }); 1778 MCInst NewInst = 1779 createStackAccess(SPVal, FPVal, Item.FIEToInsert, 1780 Item.Action == WorklistItem::InsertPushOrPop); 1781 if (InsertionPoint != CurBB->end()) { 1782 LLVM_DEBUG({ 1783 dbgs() << "Adding before Inst: "; 1784 InsertionPoint->dump(); 1785 dbgs() << "the following inst: "; 1786 NewInst.dump(); 1787 }); 1788 BBIterTy Iter = 1789 CurBB->insertInstruction(InsertionPoint, std::move(NewInst)); 1790 return ++Iter; 1791 } 1792 CurBB->addInstruction(std::move(NewInst)); 1793 LLVM_DEBUG(dbgs() << "Adding to BB!\n"); 1794 return CurBB->end(); 1795 } 1796 1797 BBIterTy ShrinkWrapping::processInsertionsList( 1798 BBIterTy InsertionPoint, BinaryBasicBlock *CurBB, 1799 std::vector<WorklistItem> &TodoList, int64_t SPVal, int64_t FPVal) { 1800 bool HasInsertions = false; 1801 for (WorklistItem &Item : TodoList) { 1802 if (Item.Action == WorklistItem::Erase || 1803 Item.Action == WorklistItem::ChangeToAdjustment) 1804 continue; 1805 HasInsertions = true; 1806 break; 1807 } 1808 1809 if (!HasInsertions) 1810 return InsertionPoint; 1811 1812 assert(((SPVal != StackPointerTracking::SUPERPOSITION && 1813 SPVal != StackPointerTracking::EMPTY) || 1814 (FPVal != StackPointerTracking::SUPERPOSITION && 1815 FPVal != StackPointerTracking::EMPTY)) && 1816 "Cannot insert if we have no idea of the stack state here"); 1817 1818 // Revert the effect of PSPT for this location, we want SP Value before 1819 // insertions 1820 if (InsertionPoint == CurBB->end()) { 1821 for (WorklistItem &Item : TodoList) { 1822 if (Item.Action != WorklistItem::InsertPushOrPop) 1823 continue; 1824 if (Item.FIEToInsert.IsStore) 1825 SPVal += Item.FIEToInsert.Size; 1826 if (Item.FIEToInsert.IsLoad) 1827 SPVal -= Item.FIEToInsert.Size; 1828 } 1829 } 1830 1831 // Reorder POPs to obey the correct dominance relation between them 1832 llvm::stable_sort(TodoList, [&](const WorklistItem &A, 1833 const WorklistItem &B) { 1834 if ((A.Action != WorklistItem::InsertPushOrPop || !A.FIEToInsert.IsLoad) && 1835 (B.Action != WorklistItem::InsertPushOrPop || !B.FIEToInsert.IsLoad)) 1836 return false; 1837 if ((A.Action != WorklistItem::InsertPushOrPop || !A.FIEToInsert.IsLoad)) 1838 return true; 1839 if ((B.Action != WorklistItem::InsertPushOrPop || !B.FIEToInsert.IsLoad)) 1840 return false; 1841 return DomOrder[B.AffectedReg] < DomOrder[A.AffectedReg]; 1842 }); 1843 1844 // Process insertions 1845 for (WorklistItem &Item : TodoList) { 1846 if (Item.Action == WorklistItem::Erase || 1847 Item.Action == WorklistItem::ChangeToAdjustment) 1848 continue; 1849 1850 InsertionPoint = 1851 processInsertion(InsertionPoint, CurBB, Item, SPVal, FPVal); 1852 if (Item.Action == WorklistItem::InsertPushOrPop && 1853 Item.FIEToInsert.IsStore) 1854 SPVal -= Item.FIEToInsert.Size; 1855 if (Item.Action == WorklistItem::InsertPushOrPop && 1856 Item.FIEToInsert.IsLoad) 1857 SPVal += Item.FIEToInsert.Size; 1858 } 1859 return InsertionPoint; 1860 } 1861 1862 bool ShrinkWrapping::processInsertions() { 1863 PredictiveStackPointerTracking PSPT(BF, Todo, Info, AllocatorId); 1864 PSPT.run(); 1865 1866 bool Changes = false; 1867 for (BinaryBasicBlock &BB : BF) { 1868 // Process insertions before some inst. 1869 for (auto I = BB.begin(); I != BB.end(); ++I) { 1870 MCInst &Inst = *I; 1871 auto TodoList = BC.MIB->tryGetAnnotationAs<std::vector<WorklistItem>>( 1872 Inst, getAnnotationIndex()); 1873 if (!TodoList) 1874 continue; 1875 Changes = true; 1876 std::vector<WorklistItem> List = *TodoList; 1877 LLVM_DEBUG({ 1878 dbgs() << "Now processing insertions in " << BB.getName() 1879 << " before inst: "; 1880 Inst.dump(); 1881 }); 1882 auto Iter = I; 1883 std::pair<int, int> SPTState = 1884 *PSPT.getStateAt(Iter == BB.begin() ? (ProgramPoint)&BB : &*(--Iter)); 1885 I = processInsertionsList(I, &BB, List, SPTState.first, SPTState.second); 1886 } 1887 // Process insertions at the end of bb 1888 auto WRI = Todo.find(&BB); 1889 if (WRI != Todo.end()) { 1890 std::pair<int, int> SPTState = *PSPT.getStateAt(*BB.rbegin()); 1891 processInsertionsList(BB.end(), &BB, WRI->second, SPTState.first, 1892 SPTState.second); 1893 Changes = true; 1894 } 1895 } 1896 return Changes; 1897 } 1898 1899 void ShrinkWrapping::processDeletions() { 1900 LivenessAnalysis &LA = Info.getLivenessAnalysis(); 1901 for (BinaryBasicBlock &BB : BF) { 1902 for (auto II = BB.begin(); II != BB.end(); ++II) { 1903 MCInst &Inst = *II; 1904 auto TodoList = BC.MIB->tryGetAnnotationAs<std::vector<WorklistItem>>( 1905 Inst, getAnnotationIndex()); 1906 if (!TodoList) 1907 continue; 1908 // Process all deletions 1909 for (WorklistItem &Item : *TodoList) { 1910 if (Item.Action != WorklistItem::Erase && 1911 Item.Action != WorklistItem::ChangeToAdjustment) 1912 continue; 1913 1914 if (Item.Action == WorklistItem::ChangeToAdjustment) { 1915 // Is flag reg alive across this func? 1916 bool DontClobberFlags = LA.isAlive(&Inst, BC.MIB->getFlagsReg()); 1917 if (int Sz = BC.MIB->getPushSize(Inst)) { 1918 BC.MIB->createStackPointerIncrement(Inst, Sz, DontClobberFlags); 1919 continue; 1920 } 1921 if (int Sz = BC.MIB->getPopSize(Inst)) { 1922 BC.MIB->createStackPointerDecrement(Inst, Sz, DontClobberFlags); 1923 continue; 1924 } 1925 } 1926 1927 LLVM_DEBUG({ 1928 dbgs() << "Erasing: "; 1929 BC.printInstruction(dbgs(), Inst); 1930 }); 1931 II = std::prev(BB.eraseInstruction(II)); 1932 break; 1933 } 1934 } 1935 } 1936 } 1937 1938 void ShrinkWrapping::rebuildCFI() { 1939 const bool FP = Info.getStackPointerTracking().HasFramePointer; 1940 Info.invalidateAll(); 1941 if (!FP) { 1942 rebuildCFIForSP(); 1943 Info.invalidateAll(); 1944 } 1945 for (unsigned I = 0, E = BC.MRI->getNumRegs(); I != E; ++I) { 1946 if (PushOffsetByReg[I] == 0 || PopOffsetByReg[I] == 0) 1947 continue; 1948 const int64_t SPValPush = PushOffsetByReg[I]; 1949 const int64_t SPValPop = PopOffsetByReg[I]; 1950 insertUpdatedCFI(I, SPValPush, SPValPop); 1951 Info.invalidateAll(); 1952 } 1953 } 1954 1955 bool ShrinkWrapping::perform(bool HotOnly) { 1956 HasDeletedOffsetCFIs = BitVector(BC.MRI->getNumRegs(), false); 1957 PushOffsetByReg = std::vector<int64_t>(BC.MRI->getNumRegs(), 0LL); 1958 PopOffsetByReg = std::vector<int64_t>(BC.MRI->getNumRegs(), 0LL); 1959 DomOrder = std::vector<MCPhysReg>(BC.MRI->getNumRegs(), 0); 1960 1961 // Update pass statistics 1962 uint64_t TotalInstrs = 0ULL; 1963 uint64_t TotalStoreInstrs = 0ULL; 1964 for (BinaryBasicBlock *BB : BF.layout()) { 1965 uint64_t BBExecCount = BB->getExecutionCount(); 1966 if (!BBExecCount || BBExecCount == BinaryBasicBlock::COUNT_NO_PROFILE) 1967 continue; 1968 for (const auto &Instr : *BB) { 1969 if (BC.MIB->isPseudo(Instr)) 1970 continue; 1971 if (BC.MIB->isStore(Instr)) 1972 TotalStoreInstrs += BBExecCount; 1973 TotalInstrs += BBExecCount; 1974 } 1975 } 1976 InstrDynamicCount += TotalInstrs; 1977 StoreDynamicCount += TotalStoreInstrs; 1978 1979 if (!FA.hasFrameInfo(BF)) 1980 return false; 1981 1982 if (HotOnly && (BF.getKnownExecutionCount() < BC.getHotThreshold())) 1983 return false; 1984 1985 if (BF.checkForAmbiguousJumpTables()) { 1986 LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ambiguous JTs in " << BF.getPrintName() 1987 << ".\n"); 1988 // We could call disambiguateJumpTables here, but it is probably not worth 1989 // the cost (of duplicating potentially large jump tables that could regress 1990 // dcache misses). Moreover, ambiguous JTs are rare and coming from code 1991 // written in assembly language. Just bail. 1992 return false; 1993 } 1994 SLM.initialize(); 1995 CSA.compute(); 1996 classifyCSRUses(); 1997 pruneUnwantedCSRs(); 1998 computeSaveLocations(); 1999 computeDomOrder(); 2000 moveSaveRestores(); 2001 LLVM_DEBUG({ 2002 dbgs() << "Func before shrink-wrapping: \n"; 2003 BF.dump(); 2004 }); 2005 SLM.performChanges(); 2006 // Early exit if processInsertions doesn't detect any todo items 2007 if (!processInsertions()) 2008 return false; 2009 processDeletions(); 2010 if (foldIdenticalSplitEdges()) { 2011 const std::pair<unsigned, uint64_t> Stats = BF.eraseInvalidBBs(); 2012 (void)Stats; 2013 LLVM_DEBUG(dbgs() << "Deleted " << Stats.first 2014 << " redundant split edge BBs (" << Stats.second 2015 << " bytes) for " << BF.getPrintName() << "\n"); 2016 } 2017 rebuildCFI(); 2018 // We may have split edges, creating BBs that need correct branching 2019 BF.fixBranches(); 2020 LLVM_DEBUG({ 2021 dbgs() << "Func after shrink-wrapping: \n"; 2022 BF.dump(); 2023 }); 2024 return true; 2025 } 2026 2027 void ShrinkWrapping::printStats() { 2028 outs() << "BOLT-INFO: Shrink wrapping moved " << SpillsMovedRegularMode 2029 << " spills inserting load/stores and " << SpillsMovedPushPopMode 2030 << " spills inserting push/pops\n"; 2031 if (!InstrDynamicCount || !StoreDynamicCount) 2032 return; 2033 outs() << "BOLT-INFO: Shrink wrapping reduced " << SpillsMovedDynamicCount 2034 << " store executions (" 2035 << format("%.1lf%%", 2036 (100.0 * SpillsMovedDynamicCount / InstrDynamicCount)) 2037 << " total instructions executed, " 2038 << format("%.1lf%%", 2039 (100.0 * SpillsMovedDynamicCount / StoreDynamicCount)) 2040 << " store instructions)\n"; 2041 outs() << "BOLT-INFO: Shrink wrapping failed at reducing " 2042 << SpillsFailedDynamicCount << " store executions (" 2043 << format("%.1lf%%", 2044 (100.0 * SpillsFailedDynamicCount / InstrDynamicCount)) 2045 << " total instructions executed, " 2046 << format("%.1lf%%", 2047 (100.0 * SpillsFailedDynamicCount / StoreDynamicCount)) 2048 << " store instructions)\n"; 2049 } 2050 2051 // Operators necessary as a result of using MCAnnotation 2052 raw_ostream &operator<<(raw_ostream &OS, 2053 const std::vector<ShrinkWrapping::WorklistItem> &Vec) { 2054 OS << "SWTodo["; 2055 const char *Sep = ""; 2056 for (const ShrinkWrapping::WorklistItem &Item : Vec) { 2057 OS << Sep; 2058 switch (Item.Action) { 2059 case ShrinkWrapping::WorklistItem::Erase: 2060 OS << "Erase"; 2061 break; 2062 case ShrinkWrapping::WorklistItem::ChangeToAdjustment: 2063 OS << "ChangeToAdjustment"; 2064 break; 2065 case ShrinkWrapping::WorklistItem::InsertLoadOrStore: 2066 OS << "InsertLoadOrStore"; 2067 break; 2068 case ShrinkWrapping::WorklistItem::InsertPushOrPop: 2069 OS << "InsertPushOrPop"; 2070 break; 2071 } 2072 Sep = ", "; 2073 } 2074 OS << "]"; 2075 return OS; 2076 } 2077 2078 raw_ostream & 2079 operator<<(raw_ostream &OS, 2080 const std::vector<StackLayoutModifier::WorklistItem> &Vec) { 2081 OS << "SLMTodo["; 2082 const char *Sep = ""; 2083 for (const StackLayoutModifier::WorklistItem &Item : Vec) { 2084 OS << Sep; 2085 switch (Item.Action) { 2086 case StackLayoutModifier::WorklistItem::None: 2087 OS << "None"; 2088 break; 2089 case StackLayoutModifier::WorklistItem::AdjustLoadStoreOffset: 2090 OS << "AdjustLoadStoreOffset"; 2091 break; 2092 case StackLayoutModifier::WorklistItem::AdjustCFI: 2093 OS << "AdjustCFI"; 2094 break; 2095 } 2096 Sep = ", "; 2097 } 2098 OS << "]"; 2099 return OS; 2100 } 2101 2102 bool operator==(const ShrinkWrapping::WorklistItem &A, 2103 const ShrinkWrapping::WorklistItem &B) { 2104 return (A.Action == B.Action && A.AffectedReg == B.AffectedReg && 2105 A.Adjustment == B.Adjustment && 2106 A.FIEToInsert.IsLoad == B.FIEToInsert.IsLoad && 2107 A.FIEToInsert.IsStore == B.FIEToInsert.IsStore && 2108 A.FIEToInsert.RegOrImm == B.FIEToInsert.RegOrImm && 2109 A.FIEToInsert.Size == B.FIEToInsert.Size && 2110 A.FIEToInsert.IsSimple == B.FIEToInsert.IsSimple && 2111 A.FIEToInsert.StackOffset == B.FIEToInsert.StackOffset); 2112 } 2113 2114 bool operator==(const StackLayoutModifier::WorklistItem &A, 2115 const StackLayoutModifier::WorklistItem &B) { 2116 return (A.Action == B.Action && A.OffsetUpdate == B.OffsetUpdate); 2117 } 2118 2119 } // end namespace bolt 2120 } // end namespace llvm 2121