static bool MaybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB, const MachineFunction &MF, WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI, const WebAssemblyInstrInfo &TII, unsigned FallthroughOpc, unsigned CopyLocalOpc) { if (DisableWebAssemblyFallthroughReturnOpt) return false; if (&MBB != &MF.back()) return false; if (&MI != &MBB.back()) return false; // If the operand isn't stackified, insert a COPY to read the operand and // stackify it. MachineOperand &MO = MI.getOperand(0); unsigned Reg = MO.getReg(); if (!MFI.isVRegStackified(Reg)) { unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg) .addReg(Reg); MO.setReg(NewReg); MFI.stackifyVReg(NewReg); } // Rewrite the return. MI.setDesc(TII.get(FallthroughOpc)); return true; }
/// If desirable, rewrite NewReg to a drop register. static bool MaybeRewriteToDrop(unsigned OldReg, unsigned NewReg, MachineOperand &MO, WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI) { bool Changed = false; if (OldReg == NewReg) { Changed = true; unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); MO.setReg(NewReg); MO.setIsDead(); MFI.stackifyVReg(NewReg); MFI.addWAReg(NewReg, WebAssemblyFunctionInfo::UnusedReg); } return Changed; }
/// Test whether OneUse, a use of Reg, dominates all of Reg's other uses. static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse, const MachineBasicBlock &MBB, const MachineRegisterInfo &MRI, const MachineDominatorTree &MDT, LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI) { const LiveInterval &LI = LIS.getInterval(Reg); const MachineInstr *OneUseInst = OneUse.getParent(); VNInfo *OneUseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*OneUseInst)); for (const MachineOperand &Use : MRI.use_nodbg_operands(Reg)) { if (&Use == &OneUse) continue; const MachineInstr *UseInst = Use.getParent(); VNInfo *UseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*UseInst)); if (UseVNI != OneUseVNI) continue; const MachineInstr *OneUseInst = OneUse.getParent(); if (UseInst == OneUseInst) { // Another use in the same instruction. We need to ensure that the one // selected use happens "before" it. if (&OneUse > &Use) return false; } else { // Test that the use is dominated by the one selected use. while (!MDT.dominates(OneUseInst, UseInst)) { // Actually, dominating is over-conservative. Test that the use would // happen after the one selected use in the stack evaluation order. // // This is needed as a consequence of using implicit get_locals for // uses and implicit set_locals for defs. if (UseInst->getDesc().getNumDefs() == 0) return false; const MachineOperand &MO = UseInst->getOperand(0); if (!MO.isReg()) return false; unsigned DefReg = MO.getReg(); if (!TargetRegisterInfo::isVirtualRegister(DefReg) || !MFI.isVRegStackified(DefReg)) return false; assert(MRI.hasOneUse(DefReg)); const MachineOperand &NewUse = *MRI.use_begin(DefReg); const MachineInstr *NewUseInst = NewUse.getParent(); if (NewUseInst == OneUseInst) { if (&OneUse > &NewUse) return false; break; } UseInst = NewUseInst; } } } return true; }
/// Test whether MI is a child of some other node in an expression tree. static bool IsChild(const MachineInstr *MI, const WebAssemblyFunctionInfo &MFI) { if (MI->getNumOperands() == 0) return false; const MachineOperand &MO = MI->getOperand(0); if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) return false; unsigned Reg = MO.getReg(); return TargetRegisterInfo::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg); }