// Branch analysis. bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl<MachineOperand> &Cond, bool /*AllowModify*/) const { bool HaveCond = false; for (MachineInstr &MI : MBB.terminators()) { switch (MI.getOpcode()) { default: // Unhandled instruction; bail out. return true; case WebAssembly::BR_IF: if (HaveCond) return true; // If we're running after CFGStackify, we can't optimize further. if (!MI.getOperand(0).isMBB()) return true; Cond.push_back(MachineOperand::CreateImm(true)); Cond.push_back(MI.getOperand(1)); TBB = MI.getOperand(0).getMBB(); HaveCond = true; break; case WebAssembly::BR_UNLESS: if (HaveCond) return true; // If we're running after CFGStackify, we can't optimize further. if (!MI.getOperand(0).isMBB()) return true; Cond.push_back(MachineOperand::CreateImm(false)); Cond.push_back(MI.getOperand(1)); TBB = MI.getOperand(0).getMBB(); HaveCond = true; break; case WebAssembly::BR: // If we're running after CFGStackify, we can't optimize further. if (!MI.getOperand(0).isMBB()) return true; if (!HaveCond) TBB = MI.getOperand(0).getMBB(); else FBB = MI.getOperand(0).getMBB(); break; } if (MI.isBarrier()) break; } return false; }
void ShrinkWrap::updateSaveRestorePoints(MachineBasicBlock &MBB, RegScavenger *RS) { // Get rid of the easy cases first. if (!Save) Save = &MBB; else Save = MDT->findNearestCommonDominator(Save, &MBB); if (!Save) { LLVM_DEBUG(dbgs() << "Found a block that is not reachable from Entry\n"); return; } if (!Restore) Restore = &MBB; else if (MPDT->getNode(&MBB)) // If the block is not in the post dom tree, it // means the block never returns. If that's the // case, we don't want to call // `findNearestCommonDominator`, which will // return `Restore`. Restore = MPDT->findNearestCommonDominator(Restore, &MBB); else Restore = nullptr; // Abort, we can't find a restore point in this case. // Make sure we would be able to insert the restore code before the // terminator. if (Restore == &MBB) { for (const MachineInstr &Terminator : MBB.terminators()) { if (!useOrDefCSROrFI(Terminator, RS)) continue; // One of the terminator needs to happen before the restore point. if (MBB.succ_empty()) { Restore = nullptr; // Abort, we can't find a restore point in this case. break; } // Look for a restore point that post-dominates all the successors. // The immediate post-dominator is what we are looking for. Restore = FindIDom<>(*Restore, Restore->successors(), *MPDT); break; } } if (!Restore) { LLVM_DEBUG( dbgs() << "Restore point needs to be spanned on several blocks\n"); return; } // Make sure Save and Restore are suitable for shrink-wrapping: // 1. all path from Save needs to lead to Restore before exiting. // 2. all path to Restore needs to go through Save from Entry. // We achieve that by making sure that: // A. Save dominates Restore. // B. Restore post-dominates Save. // C. Save and Restore are in the same loop. bool SaveDominatesRestore = false; bool RestorePostDominatesSave = false; while (Save && Restore && (!(SaveDominatesRestore = MDT->dominates(Save, Restore)) || !(RestorePostDominatesSave = MPDT->dominates(Restore, Save)) || // Post-dominance is not enough in loops to ensure that all uses/defs // are after the prologue and before the epilogue at runtime. // E.g., // while(1) { // Save // Restore // if (...) // break; // use/def CSRs // } // All the uses/defs of CSRs are dominated by Save and post-dominated // by Restore. However, the CSRs uses are still reachable after // Restore and before Save are executed. // // For now, just push the restore/save points outside of loops. // FIXME: Refine the criteria to still find interesting cases // for loops. MLI->getLoopFor(Save) || MLI->getLoopFor(Restore))) { // Fix (A). if (!SaveDominatesRestore) { Save = MDT->findNearestCommonDominator(Save, Restore); continue; } // Fix (B). if (!RestorePostDominatesSave) Restore = MPDT->findNearestCommonDominator(Restore, Save); // Fix (C). if (Save && Restore && (MLI->getLoopFor(Save) || MLI->getLoopFor(Restore))) { if (MLI->getLoopDepth(Save) > MLI->getLoopDepth(Restore)) { // Push Save outside of this loop if immediate dominator is different // from save block. If immediate dominator is not different, bail out. Save = FindIDom<>(*Save, Save->predecessors(), *MDT); if (!Save) break; } else { // If the loop does not exit, there is no point in looking // for a post-dominator outside the loop. SmallVector<MachineBasicBlock*, 4> ExitBlocks; MLI->getLoopFor(Restore)->getExitingBlocks(ExitBlocks); // Push Restore outside of this loop. // Look for the immediate post-dominator of the loop exits. MachineBasicBlock *IPdom = Restore; for (MachineBasicBlock *LoopExitBB: ExitBlocks) { IPdom = FindIDom<>(*IPdom, LoopExitBB->successors(), *MPDT); if (!IPdom) break; } // If the immediate post-dominator is not in a less nested loop, // then we are stuck in a program with an infinite loop. // In that case, we will not find a safe point, hence, bail out. if (IPdom && MLI->getLoopDepth(IPdom) < MLI->getLoopDepth(Restore)) Restore = IPdom; else { Restore = nullptr; break; } } } } }
void ShrinkWrap::updateSaveRestorePoints(MachineBasicBlock &MBB) { // Get rid of the easy cases first. if (!Save) Save = &MBB; else Save = MDT->findNearestCommonDominator(Save, &MBB); if (!Save) { DEBUG(dbgs() << "Found a block that is not reachable from Entry\n"); return; } if (!Restore) Restore = &MBB; else Restore = MPDT->findNearestCommonDominator(Restore, &MBB); // Make sure we would be able to insert the restore code before the // terminator. if (Restore == &MBB) { for (const MachineInstr &Terminator : MBB.terminators()) { if (!useOrDefCSROrFI(Terminator)) continue; // One of the terminator needs to happen before the restore point. if (MBB.succ_empty()) { Restore = nullptr; break; } // Look for a restore point that post-dominates all the successors. // The immediate post-dominator is what we are looking for. Restore = FindIDom<>(*Restore, Restore->successors(), *MPDT); break; } } if (!Restore) { DEBUG(dbgs() << "Restore point needs to be spanned on several blocks\n"); return; } // Make sure Save and Restore are suitable for shrink-wrapping: // 1. all path from Save needs to lead to Restore before exiting. // 2. all path to Restore needs to go through Save from Entry. // We achieve that by making sure that: // A. Save dominates Restore. // B. Restore post-dominates Save. // C. Save and Restore are in the same loop. bool SaveDominatesRestore = false; bool RestorePostDominatesSave = false; while (Save && Restore && (!(SaveDominatesRestore = MDT->dominates(Save, Restore)) || !(RestorePostDominatesSave = MPDT->dominates(Restore, Save)) || MLI->getLoopFor(Save) != MLI->getLoopFor(Restore))) { // Fix (A). if (!SaveDominatesRestore) { Save = MDT->findNearestCommonDominator(Save, Restore); continue; } // Fix (B). if (!RestorePostDominatesSave) Restore = MPDT->findNearestCommonDominator(Restore, Save); // Fix (C). if (Save && Restore && Save != Restore && MLI->getLoopFor(Save) != MLI->getLoopFor(Restore)) { if (MLI->getLoopDepth(Save) > MLI->getLoopDepth(Restore)) // Push Save outside of this loop. Save = FindIDom<>(*Save, Save->predecessors(), *MDT); else // Push Restore outside of this loop. Restore = FindIDom<>(*Restore, Restore->successors(), *MPDT); } } }