1 //===-- WebAssemblyRegStackify.cpp - Register Stackification --------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief This file implements a register stacking pass. 12 /// 13 /// This pass reorders instructions to put register uses and defs in an order 14 /// such that they form single-use expression trees. Registers fitting this form 15 /// are then marked as "stackified", meaning references to them are replaced by 16 /// "push" and "pop" from the stack. 17 /// 18 /// This is primarily a code size optimization, since temporary values on the 19 /// expression don't need to be named. 20 /// 21 //===----------------------------------------------------------------------===// 22 23 #include "WebAssembly.h" 24 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* 25 #include "WebAssemblyMachineFunctionInfo.h" 26 #include "WebAssemblySubtarget.h" 27 #include "llvm/Analysis/AliasAnalysis.h" 28 #include "llvm/CodeGen/LiveIntervalAnalysis.h" 29 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 30 #include "llvm/CodeGen/MachineDominators.h" 31 #include "llvm/CodeGen/MachineInstrBuilder.h" 32 #include "llvm/CodeGen/MachineRegisterInfo.h" 33 #include "llvm/CodeGen/Passes.h" 34 #include "llvm/Support/Debug.h" 35 #include "llvm/Support/raw_ostream.h" 36 using namespace llvm; 37 38 #define DEBUG_TYPE "wasm-reg-stackify" 39 40 namespace { 41 class WebAssemblyRegStackify final : public MachineFunctionPass { 42 const char *getPassName() const override { 43 return "WebAssembly Register Stackify"; 44 } 45 46 void getAnalysisUsage(AnalysisUsage &AU) const override { 47 AU.setPreservesCFG(); 48 AU.addRequired<AAResultsWrapperPass>(); 49 AU.addRequired<MachineDominatorTree>(); 50 AU.addRequired<LiveIntervals>(); 51 AU.addPreserved<MachineBlockFrequencyInfo>(); 52 AU.addPreserved<SlotIndexes>(); 53 AU.addPreserved<LiveIntervals>(); 54 AU.addPreservedID(LiveVariablesID); 55 AU.addPreserved<MachineDominatorTree>(); 56 MachineFunctionPass::getAnalysisUsage(AU); 57 } 58 59 bool runOnMachineFunction(MachineFunction &MF) override; 60 61 public: 62 static char ID; // Pass identification, replacement for typeid 63 WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 64 }; 65 } // end anonymous namespace 66 67 char WebAssemblyRegStackify::ID = 0; 68 FunctionPass *llvm::createWebAssemblyRegStackify() { 69 return new WebAssemblyRegStackify(); 70 } 71 72 // Decorate the given instruction with implicit operands that enforce the 73 // expression stack ordering constraints for an instruction which is on 74 // the expression stack. 75 static void ImposeStackOrdering(MachineInstr *MI) { 76 // Write the opaque EXPR_STACK register. 77 if (!MI->definesRegister(WebAssembly::EXPR_STACK)) 78 MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 79 /*isDef=*/true, 80 /*isImp=*/true)); 81 82 // Also read the opaque EXPR_STACK register. 83 if (!MI->readsRegister(WebAssembly::EXPR_STACK)) 84 MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 85 /*isDef=*/false, 86 /*isImp=*/true)); 87 } 88 89 // Test whether it's safe to move Def to just before Insert. 90 // TODO: Compute memory dependencies in a way that doesn't require always 91 // walking the block. 92 // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 93 // more precise. 94 static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 95 AliasAnalysis &AA, const LiveIntervals &LIS, 96 const MachineRegisterInfo &MRI) { 97 assert(Def->getParent() == Insert->getParent()); 98 bool SawStore = false, SawSideEffects = false; 99 MachineBasicBlock::const_iterator D(Def), I(Insert); 100 101 // Check for register dependencies. 102 for (const MachineOperand &MO : Def->operands()) { 103 if (!MO.isReg() || MO.isUndef()) 104 continue; 105 unsigned Reg = MO.getReg(); 106 107 // If the register is dead here and at Insert, ignore it. 108 if (MO.isDead() && Insert->definesRegister(Reg) && 109 !Insert->readsRegister(Reg)) 110 continue; 111 112 if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 113 // If the physical register is never modified, ignore it. 114 if (!MRI.isPhysRegModified(Reg)) 115 continue; 116 // Otherwise, it's a physical register with unknown liveness. 117 return false; 118 } 119 120 // Ask LiveIntervals whether moving this virtual register use or def to 121 // Insert will change value numbers are seen. 122 const LiveInterval &LI = LIS.getInterval(Reg); 123 VNInfo *DefVNI = 124 MO.isDef() ? LI.getVNInfoAt(LIS.getInstructionIndex(Def).getRegSlot()) 125 : LI.getVNInfoBefore(LIS.getInstructionIndex(Def)); 126 assert(DefVNI && "Instruction input missing value number"); 127 VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(Insert)); 128 if (InsVNI && DefVNI != InsVNI) 129 return false; 130 } 131 132 // Check for memory dependencies and side effects. 133 for (--I; I != D; --I) 134 SawSideEffects |= !I->isSafeToMove(&AA, SawStore); 135 return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) && 136 !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore)); 137 } 138 139 /// Test whether OneUse, a use of Reg, dominates all of Reg's other uses. 140 static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse, 141 const MachineBasicBlock &MBB, 142 const MachineRegisterInfo &MRI, 143 const MachineDominatorTree &MDT) { 144 for (const MachineOperand &Use : MRI.use_operands(Reg)) { 145 if (&Use == &OneUse) 146 continue; 147 const MachineInstr *UseInst = Use.getParent(); 148 const MachineInstr *OneUseInst = OneUse.getParent(); 149 if (UseInst->getOpcode() == TargetOpcode::PHI) { 150 // Test that the PHI use, which happens on the CFG edge rather than 151 // within the PHI's own block, is dominated by the one selected use. 152 const MachineBasicBlock *Pred = 153 UseInst->getOperand(&Use - &UseInst->getOperand(0) + 1).getMBB(); 154 if (!MDT.dominates(&MBB, Pred)) 155 return false; 156 } else if (UseInst == OneUseInst) { 157 // Another use in the same instruction. We need to ensure that the one 158 // selected use happens "before" it. 159 if (&OneUse > &Use) 160 return false; 161 } else { 162 // Test that the use is dominated by the one selected use. 163 if (!MDT.dominates(OneUseInst, UseInst)) 164 return false; 165 } 166 } 167 return true; 168 } 169 170 /// Get the appropriate tee_local opcode for the given register class. 171 static unsigned GetTeeLocalOpcode(const TargetRegisterClass *RC) { 172 if (RC == &WebAssembly::I32RegClass) 173 return WebAssembly::TEE_LOCAL_I32; 174 if (RC == &WebAssembly::I64RegClass) 175 return WebAssembly::TEE_LOCAL_I64; 176 if (RC == &WebAssembly::F32RegClass) 177 return WebAssembly::TEE_LOCAL_F32; 178 if (RC == &WebAssembly::F64RegClass) 179 return WebAssembly::TEE_LOCAL_F64; 180 llvm_unreachable("Unexpected register class"); 181 } 182 183 /// A single-use def in the same block with no intervening memory or register 184 /// dependencies; move the def down and nest it with the current instruction. 185 static MachineInstr *MoveForSingleUse(unsigned Reg, MachineInstr *Def, 186 MachineBasicBlock &MBB, 187 MachineInstr *Insert, LiveIntervals &LIS, 188 WebAssemblyFunctionInfo &MFI) { 189 MBB.splice(Insert, &MBB, Def); 190 LIS.handleMove(Def); 191 MFI.stackifyVReg(Reg); 192 ImposeStackOrdering(Def); 193 return Def; 194 } 195 196 /// A trivially cloneable instruction; clone it and nest the new copy with the 197 /// current instruction. 198 static MachineInstr * 199 RematerializeCheapDef(unsigned Reg, MachineOperand &Op, MachineInstr *Def, 200 MachineBasicBlock &MBB, MachineInstr *Insert, 201 LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI, 202 MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII, 203 const WebAssemblyRegisterInfo *TRI) { 204 unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); 205 TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); 206 Op.setReg(NewReg); 207 MachineInstr *Clone = &*std::prev(MachineBasicBlock::instr_iterator(Insert)); 208 LIS.InsertMachineInstrInMaps(Clone); 209 LIS.createAndComputeVirtRegInterval(NewReg); 210 MFI.stackifyVReg(NewReg); 211 ImposeStackOrdering(Clone); 212 213 // If that was the last use of the original, delete the original. 214 // Otherwise shrink the LiveInterval. 215 if (MRI.use_empty(Reg)) { 216 SlotIndex Idx = LIS.getInstructionIndex(Def).getRegSlot(); 217 LIS.removePhysRegDefAt(WebAssembly::ARGUMENTS, Idx); 218 LIS.removeVRegDefAt(LIS.getInterval(Reg), Idx); 219 LIS.removeInterval(Reg); 220 LIS.RemoveMachineInstrFromMaps(Def); 221 Def->eraseFromParent(); 222 } else { 223 LIS.shrinkToUses(&LIS.getInterval(Reg)); 224 } 225 return Clone; 226 } 227 228 /// A multiple-use def in the same block with no intervening memory or register 229 /// dependencies; move the def down, nest it with the current instruction, and 230 /// insert a tee_local to satisfy the rest of the uses. As an illustration, 231 /// rewrite this: 232 /// 233 /// Reg = INST ... // Def 234 /// INST ..., Reg, ... // Insert 235 /// INST ..., Reg, ... 236 /// INST ..., Reg, ... 237 /// 238 /// to this: 239 /// 240 /// DefReg = INST ... // Def (to become the new Insert) 241 /// TeeReg, NewReg = TEE_LOCAL_... DefReg 242 /// INST ..., TeeReg, ... // Insert 243 /// INST ..., NewReg, ... 244 /// INST ..., NewReg, ... 245 /// 246 /// with DefReg and TeeReg stackified. This eliminates a get_local from the 247 /// resulting code. 248 static MachineInstr *MoveAndTeeForMultiUse( 249 unsigned Reg, MachineOperand &Op, MachineInstr *Def, MachineBasicBlock &MBB, 250 MachineInstr *Insert, LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI, 251 MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) { 252 MBB.splice(Insert, &MBB, Def); 253 LIS.handleMove(Def); 254 const auto *RegClass = MRI.getRegClass(Reg); 255 unsigned NewReg = MRI.createVirtualRegister(RegClass); 256 unsigned TeeReg = MRI.createVirtualRegister(RegClass); 257 unsigned DefReg = MRI.createVirtualRegister(RegClass); 258 MRI.replaceRegWith(Reg, NewReg); 259 MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(), 260 TII->get(GetTeeLocalOpcode(RegClass)), TeeReg) 261 .addReg(NewReg, RegState::Define) 262 .addReg(DefReg); 263 Op.setReg(TeeReg); 264 Def->getOperand(0).setReg(DefReg); 265 LIS.InsertMachineInstrInMaps(Tee); 266 LIS.removeInterval(Reg); 267 LIS.createAndComputeVirtRegInterval(NewReg); 268 LIS.createAndComputeVirtRegInterval(TeeReg); 269 LIS.createAndComputeVirtRegInterval(DefReg); 270 MFI.stackifyVReg(DefReg); 271 MFI.stackifyVReg(TeeReg); 272 ImposeStackOrdering(Def); 273 ImposeStackOrdering(Tee); 274 return Def; 275 } 276 277 namespace { 278 /// A stack for walking the tree of instructions being built, visiting the 279 /// MachineOperands in DFS order. 280 class TreeWalkerState { 281 typedef MachineInstr::mop_iterator mop_iterator; 282 typedef std::reverse_iterator<mop_iterator> mop_reverse_iterator; 283 typedef iterator_range<mop_reverse_iterator> RangeTy; 284 SmallVector<RangeTy, 4> Worklist; 285 286 public: 287 explicit TreeWalkerState(MachineInstr *Insert) { 288 const iterator_range<mop_iterator> &Range = Insert->explicit_uses(); 289 if (Range.begin() != Range.end()) 290 Worklist.push_back(reverse(Range)); 291 } 292 293 bool Done() const { return Worklist.empty(); } 294 295 MachineOperand &Pop() { 296 RangeTy &Range = Worklist.back(); 297 MachineOperand &Op = *Range.begin(); 298 Range = drop_begin(Range, 1); 299 if (Range.begin() == Range.end()) 300 Worklist.pop_back(); 301 assert((Worklist.empty() || 302 Worklist.back().begin() != Worklist.back().end()) && 303 "Empty ranges shouldn't remain in the worklist"); 304 return Op; 305 } 306 307 /// Push Instr's operands onto the stack to be visited. 308 void PushOperands(MachineInstr *Instr) { 309 const iterator_range<mop_iterator> &Range(Instr->explicit_uses()); 310 if (Range.begin() != Range.end()) 311 Worklist.push_back(reverse(Range)); 312 } 313 314 /// Some of Instr's operands are on the top of the stack; remove them and 315 /// re-insert them starting from the beginning (because we've commuted them). 316 void ResetTopOperands(MachineInstr *Instr) { 317 assert(HasRemainingOperands(Instr) && 318 "Reseting operands should only be done when the instruction has " 319 "an operand still on the stack"); 320 Worklist.back() = reverse(Instr->explicit_uses()); 321 } 322 323 /// Test whether Instr has operands remaining to be visited at the top of 324 /// the stack. 325 bool HasRemainingOperands(const MachineInstr *Instr) const { 326 if (Worklist.empty()) 327 return false; 328 const RangeTy &Range = Worklist.back(); 329 return Range.begin() != Range.end() && Range.begin()->getParent() == Instr; 330 } 331 332 /// Test whether the given register is present on the stack, indicating an 333 /// operand in the tree that we haven't visited yet. Moving a definition of 334 /// Reg to a point in the tree after that would change its value. 335 bool IsOnStack(unsigned Reg) const { 336 for (const RangeTy &Range : Worklist) 337 for (const MachineOperand &MO : Range) 338 if (MO.isReg() && MO.getReg() == Reg) 339 return true; 340 return false; 341 } 342 }; 343 344 /// State to keep track of whether commuting is in flight or whether it's been 345 /// tried for the current instruction and didn't work. 346 class CommutingState { 347 /// There are effectively three states: the initial state where we haven't 348 /// started commuting anything and we don't know anything yet, the tenative 349 /// state where we've commuted the operands of the current instruction and are 350 /// revisting it, and the declined state where we've reverted the operands 351 /// back to their original order and will no longer commute it further. 352 bool TentativelyCommuting; 353 bool Declined; 354 355 /// During the tentative state, these hold the operand indices of the commuted 356 /// operands. 357 unsigned Operand0, Operand1; 358 359 public: 360 CommutingState() : TentativelyCommuting(false), Declined(false) {} 361 362 /// Stackification for an operand was not successful due to ordering 363 /// constraints. If possible, and if we haven't already tried it and declined 364 /// it, commute Insert's operands and prepare to revisit it. 365 void MaybeCommute(MachineInstr *Insert, TreeWalkerState &TreeWalker, 366 const WebAssemblyInstrInfo *TII) { 367 if (TentativelyCommuting) { 368 assert(!Declined && 369 "Don't decline commuting until you've finished trying it"); 370 // Commuting didn't help. Revert it. 371 TII->commuteInstruction(Insert, /*NewMI=*/false, Operand0, Operand1); 372 TentativelyCommuting = false; 373 Declined = true; 374 } else if (!Declined && TreeWalker.HasRemainingOperands(Insert)) { 375 Operand0 = TargetInstrInfo::CommuteAnyOperandIndex; 376 Operand1 = TargetInstrInfo::CommuteAnyOperandIndex; 377 if (TII->findCommutedOpIndices(Insert, Operand0, Operand1)) { 378 // Tentatively commute the operands and try again. 379 TII->commuteInstruction(Insert, /*NewMI=*/false, Operand0, Operand1); 380 TreeWalker.ResetTopOperands(Insert); 381 TentativelyCommuting = true; 382 Declined = false; 383 } 384 } 385 } 386 387 /// Stackification for some operand was successful. Reset to the default 388 /// state. 389 void Reset() { 390 TentativelyCommuting = false; 391 Declined = false; 392 } 393 }; 394 } // end anonymous namespace 395 396 bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 397 DEBUG(dbgs() << "********** Register Stackifying **********\n" 398 "********** Function: " 399 << MF.getName() << '\n'); 400 401 bool Changed = false; 402 MachineRegisterInfo &MRI = MF.getRegInfo(); 403 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 404 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 405 const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 406 AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 407 MachineDominatorTree &MDT = getAnalysis<MachineDominatorTree>(); 408 LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 409 410 // Walk the instructions from the bottom up. Currently we don't look past 411 // block boundaries, and the blocks aren't ordered so the block visitation 412 // order isn't significant, but we may want to change this in the future. 413 for (MachineBasicBlock &MBB : MF) { 414 // Don't use a range-based for loop, because we modify the list as we're 415 // iterating over it and the end iterator may change. 416 for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) { 417 MachineInstr *Insert = &*MII; 418 // Don't nest anything inside a phi. 419 if (Insert->getOpcode() == TargetOpcode::PHI) 420 break; 421 422 // Don't nest anything inside an inline asm, because we don't have 423 // constraints for $push inputs. 424 if (Insert->getOpcode() == TargetOpcode::INLINEASM) 425 break; 426 427 // Iterate through the inputs in reverse order, since we'll be pulling 428 // operands off the stack in LIFO order. 429 CommutingState Commuting; 430 TreeWalkerState TreeWalker(Insert); 431 while (!TreeWalker.Done()) { 432 MachineOperand &Op = TreeWalker.Pop(); 433 434 // We're only interested in explicit virtual register operands. 435 if (!Op.isReg()) 436 continue; 437 438 unsigned Reg = Op.getReg(); 439 assert(Op.isUse() && "explicit_uses() should only iterate over uses"); 440 assert(!Op.isImplicit() && 441 "explicit_uses() should only iterate over explicit operands"); 442 if (TargetRegisterInfo::isPhysicalRegister(Reg)) 443 continue; 444 445 // Identify the definition for this register at this point. Most 446 // registers are in SSA form here so we try a quick MRI query first. 447 MachineInstr *Def = MRI.getUniqueVRegDef(Reg); 448 if (!Def) { 449 // MRI doesn't know what the Def is. Try asking LIS. 450 const VNInfo *ValNo = LIS.getInterval(Reg).getVNInfoBefore( 451 LIS.getInstructionIndex(Insert)); 452 if (!ValNo) 453 continue; 454 Def = LIS.getInstructionFromIndex(ValNo->def); 455 if (!Def) 456 continue; 457 } 458 459 // Don't nest an INLINE_ASM def into anything, because we don't have 460 // constraints for $pop outputs. 461 if (Def->getOpcode() == TargetOpcode::INLINEASM) 462 continue; 463 464 // Don't nest PHIs inside of anything. 465 if (Def->getOpcode() == TargetOpcode::PHI) 466 continue; 467 468 // Argument instructions represent live-in registers and not real 469 // instructions. 470 if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 471 Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 472 Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 473 Def->getOpcode() == WebAssembly::ARGUMENT_F64) 474 continue; 475 476 // Decide which strategy to take. Prefer to move a single-use value 477 // over cloning it, and prefer cloning over introducing a tee_local. 478 // For moving, we require the def to be in the same block as the use; 479 // this makes things simpler (LiveIntervals' handleMove function only 480 // supports intra-block moves) and it's MachineSink's job to catch all 481 // the sinking opportunities anyway. 482 bool SameBlock = Def->getParent() == &MBB; 483 bool CanMove = SameBlock && IsSafeToMove(Def, Insert, AA, LIS, MRI) && 484 !TreeWalker.IsOnStack(Reg); 485 if (CanMove && MRI.hasOneUse(Reg)) { 486 Insert = MoveForSingleUse(Reg, Def, MBB, Insert, LIS, MFI); 487 } else if (Def->isAsCheapAsAMove() && 488 TII->isTriviallyReMaterializable(Def, &AA)) { 489 Insert = RematerializeCheapDef(Reg, Op, Def, MBB, Insert, LIS, MFI, 490 MRI, TII, TRI); 491 } else if (CanMove && 492 OneUseDominatesOtherUses(Reg, Op, MBB, MRI, MDT)) { 493 Insert = MoveAndTeeForMultiUse(Reg, Op, Def, MBB, Insert, LIS, MFI, 494 MRI, TII); 495 } else { 496 // We failed to stackify the operand. If the problem was ordering 497 // constraints, Commuting may be able to help. 498 if (!CanMove && SameBlock) 499 Commuting.MaybeCommute(Insert, TreeWalker, TII); 500 // Proceed to the next operand. 501 continue; 502 } 503 504 // We stackified an operand. Add the defining instruction's operands to 505 // the worklist stack now to continue to build an ever deeper tree. 506 Commuting.Reset(); 507 TreeWalker.PushOperands(Insert); 508 } 509 510 // If we stackified any operands, skip over the tree to start looking for 511 // the next instruction we can build a tree on. 512 if (Insert != &*MII) { 513 ImposeStackOrdering(&*MII); 514 MII = std::prev( 515 make_reverse_iterator(MachineBasicBlock::iterator(Insert))); 516 Changed = true; 517 } 518 } 519 } 520 521 // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere so 522 // that it never looks like a use-before-def. 523 if (Changed) { 524 MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 525 for (MachineBasicBlock &MBB : MF) 526 MBB.addLiveIn(WebAssembly::EXPR_STACK); 527 } 528 529 #ifndef NDEBUG 530 // Verify that pushes and pops are performed in LIFO order. 531 SmallVector<unsigned, 0> Stack; 532 for (MachineBasicBlock &MBB : MF) { 533 for (MachineInstr &MI : MBB) { 534 for (MachineOperand &MO : reverse(MI.explicit_operands())) { 535 if (!MO.isReg()) 536 continue; 537 unsigned Reg = MO.getReg(); 538 539 // Don't stackify physregs like SP or FP. 540 if (!TargetRegisterInfo::isVirtualRegister(Reg)) 541 continue; 542 543 if (MFI.isVRegStackified(Reg)) { 544 if (MO.isDef()) 545 Stack.push_back(Reg); 546 else 547 assert(Stack.pop_back_val() == Reg && 548 "Register stack pop should be paired with a push"); 549 } 550 } 551 } 552 // TODO: Generalize this code to support keeping values on the stack across 553 // basic block boundaries. 554 assert(Stack.empty() && 555 "Register stack pushes and pops should be balanced"); 556 } 557 #endif 558 559 return Changed; 560 } 561