diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp')
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp | 138 |
1 files changed, 89 insertions, 49 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 428d573..bc91c64 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -41,14 +41,18 @@ using namespace llvm; namespace { class WebAssemblyRegStackify final : public MachineFunctionPass { + bool Optimize; + StringRef getPassName() const override { return "WebAssembly Register Stackify"; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); - AU.addRequired<MachineDominatorTreeWrapperPass>(); - AU.addRequired<LiveIntervalsWrapperPass>(); + if (Optimize) { + AU.addRequired<LiveIntervalsWrapperPass>(); + AU.addRequired<MachineDominatorTreeWrapperPass>(); + } AU.addPreserved<MachineBlockFrequencyInfoWrapperPass>(); AU.addPreserved<SlotIndexesWrapperPass>(); AU.addPreserved<LiveIntervalsWrapperPass>(); @@ -61,7 +65,9 @@ class WebAssemblyRegStackify final : public MachineFunctionPass { public: static char ID; // Pass identification, replacement for typeid - WebAssemblyRegStackify() : MachineFunctionPass(ID) {} + WebAssemblyRegStackify(CodeGenOptLevel OptLevel) + : MachineFunctionPass(ID), Optimize(OptLevel != CodeGenOptLevel::None) {} + WebAssemblyRegStackify() : WebAssemblyRegStackify(CodeGenOptLevel::Default) {} }; } // end anonymous namespace @@ -70,8 +76,8 @@ INITIALIZE_PASS(WebAssemblyRegStackify, DEBUG_TYPE, "Reorder instructions to use the WebAssembly value stack", false, false) -FunctionPass *llvm::createWebAssemblyRegStackify() { - return new WebAssemblyRegStackify(); +FunctionPass *llvm::createWebAssemblyRegStackify(CodeGenOptLevel OptLevel) { + return new WebAssemblyRegStackify(OptLevel); } // Decorate the given instruction with implicit operands that enforce the @@ -96,8 +102,7 @@ static void imposeStackOrdering(MachineInstr *MI) { static void convertImplicitDefToConstZero(MachineInstr *MI, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, - MachineFunction &MF, - LiveIntervals &LIS) { + MachineFunction &MF) { assert(MI->getOpcode() == TargetOpcode::IMPLICIT_DEF); const auto *RegClass = MRI.getRegClass(MI->getOperand(0).getReg()); @@ -262,36 +267,53 @@ static bool shouldRematerialize(const MachineInstr &Def, // LiveIntervals to handle complex cases. static MachineInstr *getVRegDef(unsigned Reg, const MachineInstr *Insert, const MachineRegisterInfo &MRI, - const LiveIntervals &LIS) { + const LiveIntervals *LIS) { // Most registers are in SSA form here so we try a quick MRI query first. if (MachineInstr *Def = MRI.getUniqueVRegDef(Reg)) return Def; // MRI doesn't know what the Def is. Try asking LIS. - if (const VNInfo *ValNo = LIS.getInterval(Reg).getVNInfoBefore( - LIS.getInstructionIndex(*Insert))) - return LIS.getInstructionFromIndex(ValNo->def); + if (LIS != nullptr) { + SlotIndex InstIndex = LIS->getInstructionIndex(*Insert); + if (const VNInfo *ValNo = LIS->getInterval(Reg).getVNInfoBefore(InstIndex)) + return LIS->getInstructionFromIndex(ValNo->def); + } return nullptr; } // Test whether Reg, as defined at Def, has exactly one use. This is a // generalization of MachineRegisterInfo::hasOneNonDBGUse that uses -// LiveIntervals to handle complex cases. -static bool hasOneNonDBGUse(unsigned Reg, MachineInstr *Def, - MachineRegisterInfo &MRI, MachineDominatorTree &MDT, - LiveIntervals &LIS) { +// LiveIntervals to handle complex cases in optimized code. +static bool hasSingleUse(unsigned Reg, MachineRegisterInfo &MRI, + WebAssemblyFunctionInfo &MFI, bool Optimize, + MachineInstr *Def, LiveIntervals *LIS) { + if (!Optimize) { + // Using "hasOneUse" instead of "hasOneNonDBGUse" here because we don't + // want to stackify DBG_VALUE operands - WASM stack locations are less + // useful and less widely supported than WASM local locations. + if (!MRI.hasOneUse(Reg)) + return false; + // The frame base always has an implicit DBG use as DW_AT_frame_base. + if (MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Reg) + return false; + return true; + } + // Most registers are in SSA form here so we try a quick MRI query first. if (MRI.hasOneNonDBGUse(Reg)) return true; + if (LIS == nullptr) + return false; + bool HasOne = false; - const LiveInterval &LI = LIS.getInterval(Reg); + const LiveInterval &LI = LIS->getInterval(Reg); const VNInfo *DefVNI = - LI.getVNInfoAt(LIS.getInstructionIndex(*Def).getRegSlot()); + LI.getVNInfoAt(LIS->getInstructionIndex(*Def).getRegSlot()); assert(DefVNI); for (auto &I : MRI.use_nodbg_operands(Reg)) { - const auto &Result = LI.Query(LIS.getInstructionIndex(*I.getParent())); + const auto &Result = LI.Query(LIS->getInstructionIndex(*I.getParent())); if (Result.valueIn() == DefVNI) { if (!Result.isKill()) return false; @@ -311,7 +333,7 @@ static bool hasOneNonDBGUse(unsigned Reg, MachineInstr *Def, static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, const MachineInstr *Insert, const WebAssemblyFunctionInfo &MFI, - const MachineRegisterInfo &MRI) { + const MachineRegisterInfo &MRI, bool Optimize) { const MachineInstr *DefI = Def->getParent(); const MachineInstr *UseI = Use->getParent(); assert(DefI->getParent() == Insert->getParent()); @@ -357,6 +379,12 @@ static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, if (NextI == Insert) return true; + // When not optimizing, we only handle the trivial case above + // to guarantee no impact to debugging and to avoid spending + // compile time. + if (!Optimize) + return false; + // 'catch' and 'catch_all' should be the first instruction of a BB and cannot // move. if (WebAssembly::isCatch(DefI->getOpcode())) @@ -520,14 +548,15 @@ static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) { /// dependencies; move the def down and nest it with the current instruction. static MachineInstr *moveForSingleUse(unsigned Reg, MachineOperand &Op, MachineInstr *Def, MachineBasicBlock &MBB, - MachineInstr *Insert, LiveIntervals &LIS, + MachineInstr *Insert, LiveIntervals *LIS, WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI) { LLVM_DEBUG(dbgs() << "Move for single use: "; Def->dump()); WebAssemblyDebugValueManager DefDIs(Def); DefDIs.sink(Insert); - LIS.handleMove(*Def); + if (LIS != nullptr) + LIS->handleMove(*Def); if (MRI.hasOneDef(Reg) && MRI.hasOneNonDBGUse(Reg)) { // No one else is using this register for anything so we can just stackify @@ -540,17 +569,18 @@ static MachineInstr *moveForSingleUse(unsigned Reg, MachineOperand &Op, Op.setReg(NewReg); DefDIs.updateReg(NewReg); - // Tell LiveIntervals about the new register. - LIS.createAndComputeVirtRegInterval(NewReg); + if (LIS != nullptr) { + // Tell LiveIntervals about the new register. + LIS->createAndComputeVirtRegInterval(NewReg); - // Tell LiveIntervals about the changes to the old register. - LiveInterval &LI = LIS.getInterval(Reg); - LI.removeSegment(LIS.getInstructionIndex(*Def).getRegSlot(), - LIS.getInstructionIndex(*Op.getParent()).getRegSlot(), - /*RemoveDeadValNo=*/true); + // Tell LiveIntervals about the changes to the old register. + LiveInterval &LI = LIS->getInterval(Reg); + LI.removeSegment(LIS->getInstructionIndex(*Def).getRegSlot(), + LIS->getInstructionIndex(*Op.getParent()).getRegSlot(), + /*RemoveDeadValNo=*/true); + } MFI.stackifyVReg(MRI, NewReg); - LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); } @@ -567,11 +597,12 @@ static MachineInstr *getPrevNonDebugInst(MachineInstr *MI) { /// A trivially cloneable instruction; clone it and nest the new copy with the /// current instruction. -static MachineInstr *rematerializeCheapDef( - unsigned Reg, MachineOperand &Op, MachineInstr &Def, MachineBasicBlock &MBB, - MachineBasicBlock::instr_iterator Insert, LiveIntervals &LIS, - WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI, - const WebAssemblyInstrInfo *TII, const WebAssemblyRegisterInfo *TRI) { +static MachineInstr * +rematerializeCheapDef(unsigned Reg, MachineOperand &Op, MachineInstr &Def, + MachineBasicBlock::instr_iterator Insert, + LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI, + MachineRegisterInfo &MRI, + const WebAssemblyInstrInfo *TII) { LLVM_DEBUG(dbgs() << "Rematerializing cheap def: "; Def.dump()); LLVM_DEBUG(dbgs() << " - for use in "; Op.getParent()->dump()); @@ -811,9 +842,12 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { MachineRegisterInfo &MRI = MF.getRegInfo(); WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); - const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); - auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); - auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS(); + MachineDominatorTree *MDT = nullptr; + LiveIntervals *LIS = nullptr; + if (Optimize) { + MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); + LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS(); + } // Walk the instructions from the bottom up. Currently we don't look past // block boundaries, and the blocks aren't ordered so the block visitation @@ -876,23 +910,28 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { // supports intra-block moves) and it's MachineSink's job to catch all // the sinking opportunities anyway. bool SameBlock = DefI->getParent() == &MBB; - bool CanMove = SameBlock && isSafeToMove(Def, &Use, Insert, MFI, MRI) && + bool CanMove = SameBlock && + isSafeToMove(Def, &Use, Insert, MFI, MRI, Optimize) && !TreeWalker.isOnStack(Reg); - if (CanMove && hasOneNonDBGUse(Reg, DefI, MRI, MDT, LIS)) { + if (CanMove && hasSingleUse(Reg, MRI, MFI, Optimize, DefI, LIS)) { Insert = moveForSingleUse(Reg, Use, DefI, MBB, Insert, LIS, MFI, MRI); // If we are removing the frame base reg completely, remove the debug // info as well. // TODO: Encode this properly as a stackified value. - if (MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Reg) + if (MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Reg) { + assert( + Optimize && + "Stackifying away frame base in unoptimized code not expected"); MFI.clearFrameBaseVreg(); - } else if (shouldRematerialize(*DefI, TII)) { - Insert = - rematerializeCheapDef(Reg, Use, *DefI, MBB, Insert->getIterator(), - LIS, MFI, MRI, TII, TRI); - } else if (CanMove && oneUseDominatesOtherUses(Reg, Use, MBB, MRI, MDT, - LIS, MFI)) { - Insert = moveAndTeeForMultiUse(Reg, Use, DefI, MBB, Insert, LIS, MFI, + } + } else if (Optimize && shouldRematerialize(*DefI, TII)) { + Insert = rematerializeCheapDef(Reg, Use, *DefI, Insert->getIterator(), + *LIS, MFI, MRI, TII); + } else if (Optimize && CanMove && + oneUseDominatesOtherUses(Reg, Use, MBB, MRI, *MDT, *LIS, + MFI)) { + Insert = moveAndTeeForMultiUse(Reg, Use, DefI, MBB, Insert, *LIS, MFI, MRI, TII); } else { // We failed to stackify the operand. If the problem was ordering @@ -915,7 +954,8 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { Register DefReg = SubsequentDef->getReg(); Register UseReg = SubsequentUse->getReg(); // TODO: This single-use restriction could be relaxed by using tees - if (DefReg != UseReg || !MRI.hasOneNonDBGUse(DefReg)) + if (DefReg != UseReg || + !hasSingleUse(DefReg, MRI, MFI, Optimize, nullptr, nullptr)) break; MFI.stackifyVReg(MRI, DefReg); ++SubsequentDef; @@ -926,7 +966,7 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { // to a constant 0 so that the def is explicit, and the push/pop // correspondence is maintained. if (Insert->getOpcode() == TargetOpcode::IMPLICIT_DEF) - convertImplicitDefToConstZero(Insert, MRI, TII, MF, LIS); + convertImplicitDefToConstZero(Insert, MRI, TII, MF); // We stackified an operand. Add the defining instruction's operands to // the worklist stack now to continue to build an ever deeper tree. |