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 /// Reg = INST ... // Def (to become the new Insert) 241 /// TeeReg, NewReg = TEE_LOCAL_... Reg 242 /// INST ..., TeeReg, ... // Insert 243 /// INST ..., NewReg, ... 244 /// INST ..., NewReg, ... 245 /// 246 /// with Reg 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 MRI.replaceRegWith(Reg, NewReg); 258 MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(), 259 TII->get(GetTeeLocalOpcode(RegClass)), TeeReg) 260 .addReg(NewReg, RegState::Define) 261 .addReg(Reg); 262 Op.setReg(TeeReg); 263 Def->getOperand(0).setReg(Reg); 264 LIS.InsertMachineInstrInMaps(Tee); 265 LIS.shrinkToUses(&LIS.getInterval(Reg)); 266 LIS.createAndComputeVirtRegInterval(NewReg); 267 LIS.createAndComputeVirtRegInterval(TeeReg); 268 MFI.stackifyVReg(Reg); 269 MFI.stackifyVReg(TeeReg); 270 ImposeStackOrdering(Def); 271 ImposeStackOrdering(Tee); 272 return Def; 273 } 274 275 namespace { 276 /// A stack for walking the tree of instructions being built, visiting the 277 /// MachineOperands in DFS order. 278 class TreeWalkerState { 279 typedef MachineInstr::mop_iterator mop_iterator; 280 typedef std::reverse_iterator<mop_iterator> mop_reverse_iterator; 281 typedef iterator_range<mop_reverse_iterator> RangeTy; 282 SmallVector<RangeTy, 4> Worklist; 283 284 public: 285 explicit TreeWalkerState(MachineInstr *Insert) { 286 const iterator_range<mop_iterator> &Range = Insert->explicit_uses(); 287 if (Range.begin() != Range.end()) 288 Worklist.push_back(reverse(Range)); 289 } 290 291 bool Done() const { return Worklist.empty(); } 292 293 MachineOperand &Pop() { 294 RangeTy &Range = Worklist.back(); 295 MachineOperand &Op = *Range.begin(); 296 Range = drop_begin(Range, 1); 297 if (Range.begin() == Range.end()) 298 Worklist.pop_back(); 299 assert((Worklist.empty() || 300 Worklist.back().begin() != Worklist.back().end()) && 301 "Empty ranges shouldn't remain in the worklist"); 302 return Op; 303 } 304 305 /// Push Instr's operands onto the stack to be visited. 306 void PushOperands(MachineInstr *Instr) { 307 const iterator_range<mop_iterator> &Range(Instr->explicit_uses()); 308 if (Range.begin() != Range.end()) 309 Worklist.push_back(reverse(Range)); 310 } 311 312 /// Some of Instr's operands are on the top of the stack; remove them and 313 /// re-insert them starting from the beginning (because we've commuted them). 314 void ResetTopOperands(MachineInstr *Instr) { 315 assert(HasRemainingOperands(Instr) && 316 "Reseting operands should only be done when the instruction has " 317 "an operand still on the stack"); 318 Worklist.back() = reverse(Instr->explicit_uses()); 319 } 320 321 /// Test whether Instr has operands remaining to be visited at the top of 322 /// the stack. 323 bool HasRemainingOperands(const MachineInstr *Instr) const { 324 if (Worklist.empty()) 325 return false; 326 const RangeTy &Range = Worklist.back(); 327 return Range.begin() != Range.end() && Range.begin()->getParent() == Instr; 328 } 329 330 /// Test whether the given register is present on the stack, indicating an 331 /// operand in the tree that we haven't visited yet. Moving a definition of 332 /// Reg to a point in the tree after that would change its value. 333 bool IsOnStack(unsigned Reg) const { 334 for (const RangeTy &Range : Worklist) 335 for (const MachineOperand &MO : Range) 336 if (MO.isReg() && MO.getReg() == Reg) 337 return true; 338 return false; 339 } 340 }; 341 342 /// State to keep track of whether commuting is in flight or whether it's been 343 /// tried for the current instruction and didn't work. 344 class CommutingState { 345 /// There are effectively three states: the initial state where we haven't 346 /// started commuting anything and we don't know anything yet, the tenative 347 /// state where we've commuted the operands of the current instruction and are 348 /// revisting it, and the declined state where we've reverted the operands 349 /// back to their original order and will no longer commute it further. 350 bool TentativelyCommuting; 351 bool Declined; 352 353 /// During the tentative state, these hold the operand indices of the commuted 354 /// operands. 355 unsigned Operand0, Operand1; 356 357 public: 358 CommutingState() : TentativelyCommuting(false), Declined(false) {} 359 360 /// Stackification for an operand was not successful due to ordering 361 /// constraints. If possible, and if we haven't already tried it and declined 362 /// it, commute Insert's operands and prepare to revisit it. 363 void MaybeCommute(MachineInstr *Insert, TreeWalkerState &TreeWalker, 364 const WebAssemblyInstrInfo *TII) { 365 if (TentativelyCommuting) { 366 assert(!Declined && 367 "Don't decline commuting until you've finished trying it"); 368 // Commuting didn't help. Revert it. 369 TII->commuteInstruction(Insert, /*NewMI=*/false, Operand0, Operand1); 370 TentativelyCommuting = false; 371 Declined = true; 372 } else if (!Declined && TreeWalker.HasRemainingOperands(Insert)) { 373 Operand0 = TargetInstrInfo::CommuteAnyOperandIndex; 374 Operand1 = TargetInstrInfo::CommuteAnyOperandIndex; 375 if (TII->findCommutedOpIndices(Insert, Operand0, Operand1)) { 376 // Tentatively commute the operands and try again. 377 TII->commuteInstruction(Insert, /*NewMI=*/false, Operand0, Operand1); 378 TreeWalker.ResetTopOperands(Insert); 379 TentativelyCommuting = true; 380 Declined = false; 381 } 382 } 383 } 384 385 /// Stackification for some operand was successful. Reset to the default 386 /// state. 387 void Reset() { 388 TentativelyCommuting = false; 389 Declined = false; 390 } 391 }; 392 } // end anonymous namespace 393 394 bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 395 DEBUG(dbgs() << "********** Register Stackifying **********\n" 396 "********** Function: " 397 << MF.getName() << '\n'); 398 399 bool Changed = false; 400 MachineRegisterInfo &MRI = MF.getRegInfo(); 401 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 402 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 403 const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 404 AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 405 MachineDominatorTree &MDT = getAnalysis<MachineDominatorTree>(); 406 LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 407 408 // Walk the instructions from the bottom up. Currently we don't look past 409 // block boundaries, and the blocks aren't ordered so the block visitation 410 // order isn't significant, but we may want to change this in the future. 411 for (MachineBasicBlock &MBB : MF) { 412 // Don't use a range-based for loop, because we modify the list as we're 413 // iterating over it and the end iterator may change. 414 for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) { 415 MachineInstr *Insert = &*MII; 416 // Don't nest anything inside a phi. 417 if (Insert->getOpcode() == TargetOpcode::PHI) 418 break; 419 420 // Don't nest anything inside an inline asm, because we don't have 421 // constraints for $push inputs. 422 if (Insert->getOpcode() == TargetOpcode::INLINEASM) 423 break; 424 425 // Iterate through the inputs in reverse order, since we'll be pulling 426 // operands off the stack in LIFO order. 427 CommutingState Commuting; 428 TreeWalkerState TreeWalker(Insert); 429 while (!TreeWalker.Done()) { 430 MachineOperand &Op = TreeWalker.Pop(); 431 432 // We're only interested in explicit virtual register operands. 433 if (!Op.isReg()) 434 continue; 435 436 unsigned Reg = Op.getReg(); 437 assert(Op.isUse() && "explicit_uses() should only iterate over uses"); 438 assert(!Op.isImplicit() && 439 "explicit_uses() should only iterate over explicit operands"); 440 if (TargetRegisterInfo::isPhysicalRegister(Reg)) 441 continue; 442 443 // Identify the definition for this register at this point. Most 444 // registers are in SSA form here so we try a quick MRI query first. 445 MachineInstr *Def = MRI.getUniqueVRegDef(Reg); 446 if (!Def) { 447 // MRI doesn't know what the Def is. Try asking LIS. 448 const VNInfo *ValNo = LIS.getInterval(Reg).getVNInfoBefore( 449 LIS.getInstructionIndex(Insert)); 450 if (!ValNo) 451 continue; 452 Def = LIS.getInstructionFromIndex(ValNo->def); 453 if (!Def) 454 continue; 455 } 456 457 // Don't nest an INLINE_ASM def into anything, because we don't have 458 // constraints for $pop outputs. 459 if (Def->getOpcode() == TargetOpcode::INLINEASM) 460 continue; 461 462 // Don't nest PHIs inside of anything. 463 if (Def->getOpcode() == TargetOpcode::PHI) 464 continue; 465 466 // Argument instructions represent live-in registers and not real 467 // instructions. 468 if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 469 Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 470 Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 471 Def->getOpcode() == WebAssembly::ARGUMENT_F64) 472 continue; 473 474 // Decide which strategy to take. Prefer to move a single-use value 475 // over cloning it, and prefer cloning over introducing a tee_local. 476 // For moving, we require the def to be in the same block as the use; 477 // this makes things simpler (LiveIntervals' handleMove function only 478 // supports intra-block moves) and it's MachineSink's job to catch all 479 // the sinking opportunities anyway. 480 bool SameBlock = Def->getParent() == &MBB; 481 bool CanMove = SameBlock && IsSafeToMove(Def, Insert, AA, LIS, MRI) && 482 !TreeWalker.IsOnStack(Reg); 483 if (CanMove && MRI.hasOneUse(Reg)) { 484 Insert = MoveForSingleUse(Reg, Def, MBB, Insert, LIS, MFI); 485 } else if (Def->isAsCheapAsAMove() && 486 TII->isTriviallyReMaterializable(Def, &AA)) { 487 Insert = RematerializeCheapDef(Reg, Op, Def, MBB, Insert, LIS, MFI, 488 MRI, TII, TRI); 489 } else if (CanMove && 490 OneUseDominatesOtherUses(Reg, Op, MBB, MRI, MDT)) { 491 Insert = MoveAndTeeForMultiUse(Reg, Op, Def, MBB, Insert, LIS, MFI, 492 MRI, TII); 493 } else { 494 // We failed to stackify the operand. If the problem was ordering 495 // constraints, Commuting may be able to help. 496 if (!CanMove && SameBlock) 497 Commuting.MaybeCommute(Insert, TreeWalker, TII); 498 // Proceed to the next operand. 499 continue; 500 } 501 502 // We stackified an operand. Add the defining instruction's operands to 503 // the worklist stack now to continue to build an ever deeper tree. 504 Commuting.Reset(); 505 TreeWalker.PushOperands(Insert); 506 } 507 508 // If we stackified any operands, skip over the tree to start looking for 509 // the next instruction we can build a tree on. 510 if (Insert != &*MII) { 511 ImposeStackOrdering(&*MII); 512 MII = std::prev( 513 make_reverse_iterator(MachineBasicBlock::iterator(Insert))); 514 Changed = true; 515 } 516 } 517 } 518 519 // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere so 520 // that it never looks like a use-before-def. 521 if (Changed) { 522 MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 523 for (MachineBasicBlock &MBB : MF) 524 MBB.addLiveIn(WebAssembly::EXPR_STACK); 525 } 526 527 #ifndef NDEBUG 528 // Verify that pushes and pops are performed in LIFO order. 529 SmallVector<unsigned, 0> Stack; 530 for (MachineBasicBlock &MBB : MF) { 531 for (MachineInstr &MI : MBB) { 532 for (MachineOperand &MO : reverse(MI.explicit_operands())) { 533 if (!MO.isReg()) 534 continue; 535 unsigned Reg = MO.getReg(); 536 537 // Don't stackify physregs like SP or FP. 538 if (!TargetRegisterInfo::isVirtualRegister(Reg)) 539 continue; 540 541 if (MFI.isVRegStackified(Reg)) { 542 if (MO.isDef()) 543 Stack.push_back(Reg); 544 else 545 assert(Stack.pop_back_val() == Reg && 546 "Register stack pop should be paired with a push"); 547 } 548 } 549 } 550 // TODO: Generalize this code to support keeping values on the stack across 551 // basic block boundaries. 552 assert(Stack.empty() && 553 "Register stack pushes and pops should be balanced"); 554 } 555 #endif 556 557 return Changed; 558 } 559