/// Insert a BLOCK marker for branches to MBB (if needed). static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF, SmallVectorImpl<MachineBasicBlock *> &ScopeTops, const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI, MachineDominatorTree &MDT, WebAssemblyFunctionInfo &MFI) { // First compute the nearest common dominator of all forward non-fallthrough // predecessors so that we minimize the time that the BLOCK is on the stack, // which reduces overall stack height. MachineBasicBlock *Header = nullptr; bool IsBranchedTo = false; int MBBNumber = MBB.getNumber(); for (MachineBasicBlock *Pred : MBB.predecessors()) if (Pred->getNumber() < MBBNumber) { Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; if (ExplicitlyBranchesTo(Pred, &MBB)) IsBranchedTo = true; } if (!Header) return; if (!IsBranchedTo) return; assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); MachineBasicBlock *LayoutPred = &*prev(MachineFunction::iterator(&MBB)); // If the nearest common dominator is inside a more deeply nested context, // walk out to the nearest scope which isn't more deeply nested. for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { if (ScopeTop->getNumber() > Header->getNumber()) { // Skip over an intervening scope. I = next(MachineFunction::iterator(ScopeTop)); } else { // We found a scope level at an appropriate depth. Header = ScopeTop; break; } } } // If there's a loop which ends just before MBB which contains Header, we can // reuse its label instead of inserting a new BLOCK. for (MachineLoop *Loop = MLI.getLoopFor(LayoutPred); Loop && Loop->contains(LayoutPred); Loop = Loop->getParentLoop()) if (Loop && LoopBottom(Loop) == LayoutPred && Loop->contains(Header)) return; // Decide where in Header to put the BLOCK. MachineBasicBlock::iterator InsertPos; MachineLoop *HeaderLoop = MLI.getLoopFor(Header); if (HeaderLoop && MBB.getNumber() > LoopBottom(HeaderLoop)->getNumber()) { // Header is the header of a loop that does not lexically contain MBB, so // the BLOCK needs to be above the LOOP, after any END constructs. InsertPos = Header->begin(); while (InsertPos->getOpcode() != WebAssembly::LOOP) ++InsertPos; } else { // Otherwise, insert the BLOCK as late in Header as we can, but before the // beginning of the local expression tree and any nested BLOCKs. InsertPos = Header->getFirstTerminator(); while (InsertPos != Header->begin() && IsChild(prev(InsertPos), MFI) && prev(InsertPos)->getOpcode() != WebAssembly::LOOP && prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK && prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP) --InsertPos; } // Add the BLOCK. BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK)); // Mark the end of the block. InsertPos = MBB.begin(); while (InsertPos != MBB.end() && InsertPos->getOpcode() == WebAssembly::END_LOOP) ++InsertPos; BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::END_BLOCK)); // Track the farthest-spanning scope that ends at this point. int Number = MBB.getNumber(); if (!ScopeTops[Number] || ScopeTops[Number]->getNumber() > Header->getNumber()) ScopeTops[Number] = Header; }
// Hoist and merge identical SGPR initializations into a common predecessor. // This is intended to combine M0 initializations, but can work with any // SGPR. A VGPR cannot be processed since we cannot guarantee vector // executioon. static bool hoistAndMergeSGPRInits(unsigned Reg, const MachineRegisterInfo &MRI, MachineDominatorTree &MDT) { // List of inits by immediate value. typedef std::map<unsigned, std::list<MachineInstr*>> InitListMap; InitListMap Inits; // List of clobbering instructions. SmallVector<MachineInstr*, 8> Clobbers; bool Changed = false; for (auto &MI : MRI.def_instructions(Reg)) { MachineOperand *Imm = nullptr; for (auto &MO: MI.operands()) { if ((MO.isReg() && ((MO.isDef() && MO.getReg() != Reg) || !MO.isDef())) || (!MO.isImm() && !MO.isReg()) || (MO.isImm() && Imm)) { Imm = nullptr; break; } else if (MO.isImm()) Imm = &MO; } if (Imm) Inits[Imm->getImm()].push_front(&MI); else Clobbers.push_back(&MI); } for (auto &Init : Inits) { auto &Defs = Init.second; for (auto I1 = Defs.begin(), E = Defs.end(); I1 != E; ) { MachineInstr *MI1 = *I1; for (auto I2 = std::next(I1); I2 != E; ) { MachineInstr *MI2 = *I2; // Check any possible interference auto intereferes = [&](MachineBasicBlock::iterator From, MachineBasicBlock::iterator To) -> bool { assert(MDT.dominates(&*To, &*From)); auto interferes = [&MDT, From, To](MachineInstr* &Clobber) -> bool { const MachineBasicBlock *MBBFrom = From->getParent(); const MachineBasicBlock *MBBTo = To->getParent(); bool MayClobberFrom = isReachable(Clobber, &*From, MBBTo, MDT); bool MayClobberTo = isReachable(Clobber, &*To, MBBTo, MDT); if (!MayClobberFrom && !MayClobberTo) return false; if ((MayClobberFrom && !MayClobberTo) || (!MayClobberFrom && MayClobberTo)) return true; // Both can clobber, this is not an interference only if both are // dominated by Clobber and belong to the same block or if Clobber // properly dominates To, given that To >> From, so it dominates // both and located in a common dominator. return !((MBBFrom == MBBTo && MDT.dominates(Clobber, &*From) && MDT.dominates(Clobber, &*To)) || MDT.properlyDominates(Clobber->getParent(), MBBTo)); }; return (any_of(Clobbers, interferes)) || (any_of(Inits, [&](InitListMap::value_type &C) { return C.first != Init.first && any_of(C.second, interferes); })); }; if (MDT.dominates(MI1, MI2)) { if (!intereferes(MI2, MI1)) { DEBUG(dbgs() << "Erasing from BB#" << MI2->getParent()->getNumber() << " " << *MI2); MI2->eraseFromParent(); Defs.erase(I2++); Changed = true; continue; } } else if (MDT.dominates(MI2, MI1)) { if (!intereferes(MI1, MI2)) { DEBUG(dbgs() << "Erasing from BB#" << MI1->getParent()->getNumber() << " " << *MI1); MI1->eraseFromParent(); Defs.erase(I1++); Changed = true; break; } } else { auto *MBB = MDT.findNearestCommonDominator(MI1->getParent(), MI2->getParent()); if (!MBB) { ++I2; continue; } MachineBasicBlock::iterator I = MBB->getFirstNonPHI(); if (!intereferes(MI1, I) && !intereferes(MI2, I)) { DEBUG(dbgs() << "Erasing from BB#" << MI1->getParent()->getNumber() << " " << *MI1 << "and moving from BB#" << MI2->getParent()->getNumber() << " to BB#" << I->getParent()->getNumber() << " " << *MI2); I->getParent()->splice(I, MI2->getParent(), MI2); MI1->eraseFromParent(); Defs.erase(I1++); Changed = true; break; } } ++I2; } ++I1; } } if (Changed) MRI.clearKillFlags(Reg); return Changed; }