xref: /src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1dd58ef01SDimitry Andric //===-- WebAssemblyRegStackify.cpp - Register Stackification --------------===//
2dd58ef01SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dd58ef01SDimitry Andric //
7dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
8dd58ef01SDimitry Andric ///
9dd58ef01SDimitry Andric /// \file
10eb11fae6SDimitry Andric /// This file implements a register stacking pass.
11dd58ef01SDimitry Andric ///
12dd58ef01SDimitry Andric /// This pass reorders instructions to put register uses and defs in an order
13dd58ef01SDimitry Andric /// such that they form single-use expression trees. Registers fitting this form
14dd58ef01SDimitry Andric /// are then marked as "stackified", meaning references to them are replaced by
15b915e9e0SDimitry Andric /// "push" and "pop" from the value stack.
16dd58ef01SDimitry Andric ///
17dd58ef01SDimitry Andric /// This is primarily a code size optimization, since temporary values on the
18b915e9e0SDimitry Andric /// value stack don't need to be named.
19dd58ef01SDimitry Andric ///
20dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
21dd58ef01SDimitry Andric 
22dd58ef01SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_*
237ab83427SDimitry Andric #include "WebAssembly.h"
24d8e91e46SDimitry Andric #include "WebAssemblyDebugValueManager.h"
25dd58ef01SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
2601095a5dSDimitry Andric #include "WebAssemblySubtarget.h"
27b1c73532SDimitry Andric #include "WebAssemblyUtilities.h"
28dd58ef01SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
29044eb2f6SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
30dd58ef01SDimitry Andric #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
3101095a5dSDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
3201095a5dSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
3371d5a254SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h"
34dd58ef01SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
35dd58ef01SDimitry Andric #include "llvm/CodeGen/Passes.h"
36ac9a064cSDimitry Andric #include "llvm/IR/GlobalAlias.h"
37dd58ef01SDimitry Andric #include "llvm/Support/Debug.h"
38dd58ef01SDimitry Andric #include "llvm/Support/raw_ostream.h"
39cfca06d7SDimitry Andric #include <iterator>
40dd58ef01SDimitry Andric using namespace llvm;
41dd58ef01SDimitry Andric 
42dd58ef01SDimitry Andric #define DEBUG_TYPE "wasm-reg-stackify"
43dd58ef01SDimitry Andric 
44dd58ef01SDimitry Andric namespace {
45dd58ef01SDimitry Andric class WebAssemblyRegStackify final : public MachineFunctionPass {
getPassName() const46b915e9e0SDimitry Andric   StringRef getPassName() const override {
47dd58ef01SDimitry Andric     return "WebAssembly Register Stackify";
48dd58ef01SDimitry Andric   }
49dd58ef01SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const50dd58ef01SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
51dd58ef01SDimitry Andric     AU.setPreservesCFG();
52ac9a064cSDimitry Andric     AU.addRequired<MachineDominatorTreeWrapperPass>();
53ac9a064cSDimitry Andric     AU.addRequired<LiveIntervalsWrapperPass>();
54ac9a064cSDimitry Andric     AU.addPreserved<MachineBlockFrequencyInfoWrapperPass>();
55ac9a064cSDimitry Andric     AU.addPreserved<SlotIndexesWrapperPass>();
56ac9a064cSDimitry Andric     AU.addPreserved<LiveIntervalsWrapperPass>();
57dd58ef01SDimitry Andric     AU.addPreservedID(LiveVariablesID);
58ac9a064cSDimitry Andric     AU.addPreserved<MachineDominatorTreeWrapperPass>();
59dd58ef01SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
60dd58ef01SDimitry Andric   }
61dd58ef01SDimitry Andric 
62dd58ef01SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
63dd58ef01SDimitry Andric 
64dd58ef01SDimitry Andric public:
65dd58ef01SDimitry Andric   static char ID; // Pass identification, replacement for typeid
WebAssemblyRegStackify()66dd58ef01SDimitry Andric   WebAssemblyRegStackify() : MachineFunctionPass(ID) {}
67dd58ef01SDimitry Andric };
68dd58ef01SDimitry Andric } // end anonymous namespace
69dd58ef01SDimitry Andric 
70dd58ef01SDimitry Andric char WebAssemblyRegStackify::ID = 0;
71eb11fae6SDimitry Andric INITIALIZE_PASS(WebAssemblyRegStackify, DEBUG_TYPE,
72eb11fae6SDimitry Andric                 "Reorder instructions to use the WebAssembly value stack",
73eb11fae6SDimitry Andric                 false, false)
74eb11fae6SDimitry Andric 
createWebAssemblyRegStackify()75dd58ef01SDimitry Andric FunctionPass *llvm::createWebAssemblyRegStackify() {
76dd58ef01SDimitry Andric   return new WebAssemblyRegStackify();
77dd58ef01SDimitry Andric }
78dd58ef01SDimitry Andric 
79dd58ef01SDimitry Andric // Decorate the given instruction with implicit operands that enforce the
80dd58ef01SDimitry Andric // expression stack ordering constraints for an instruction which is on
81dd58ef01SDimitry Andric // the expression stack.
imposeStackOrdering(MachineInstr * MI)82e6d15924SDimitry Andric static void imposeStackOrdering(MachineInstr *MI) {
83b915e9e0SDimitry Andric   // Write the opaque VALUE_STACK register.
84ac9a064cSDimitry Andric   if (!MI->definesRegister(WebAssembly::VALUE_STACK, /*TRI=*/nullptr))
85b915e9e0SDimitry Andric     MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK,
86dd58ef01SDimitry Andric                                              /*isDef=*/true,
87dd58ef01SDimitry Andric                                              /*isImp=*/true));
88dd58ef01SDimitry Andric 
89b915e9e0SDimitry Andric   // Also read the opaque VALUE_STACK register.
90ac9a064cSDimitry Andric   if (!MI->readsRegister(WebAssembly::VALUE_STACK, /*TRI=*/nullptr))
91b915e9e0SDimitry Andric     MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK,
92dd58ef01SDimitry Andric                                              /*isDef=*/false,
93dd58ef01SDimitry Andric                                              /*isImp=*/true));
94dd58ef01SDimitry Andric }
95dd58ef01SDimitry Andric 
96b915e9e0SDimitry Andric // Convert an IMPLICIT_DEF instruction into an instruction which defines
97b915e9e0SDimitry Andric // a constant zero value.
convertImplicitDefToConstZero(MachineInstr * MI,MachineRegisterInfo & MRI,const TargetInstrInfo * TII,MachineFunction & MF,LiveIntervals & LIS)98e6d15924SDimitry Andric static void convertImplicitDefToConstZero(MachineInstr *MI,
99b915e9e0SDimitry Andric                                           MachineRegisterInfo &MRI,
100b915e9e0SDimitry Andric                                           const TargetInstrInfo *TII,
101d8e91e46SDimitry Andric                                           MachineFunction &MF,
102d8e91e46SDimitry Andric                                           LiveIntervals &LIS) {
103b915e9e0SDimitry Andric   assert(MI->getOpcode() == TargetOpcode::IMPLICIT_DEF);
104b915e9e0SDimitry Andric 
105d8e91e46SDimitry Andric   const auto *RegClass = MRI.getRegClass(MI->getOperand(0).getReg());
106b915e9e0SDimitry Andric   if (RegClass == &WebAssembly::I32RegClass) {
107b915e9e0SDimitry Andric     MI->setDesc(TII->get(WebAssembly::CONST_I32));
108b915e9e0SDimitry Andric     MI->addOperand(MachineOperand::CreateImm(0));
109b915e9e0SDimitry Andric   } else if (RegClass == &WebAssembly::I64RegClass) {
110b915e9e0SDimitry Andric     MI->setDesc(TII->get(WebAssembly::CONST_I64));
111b915e9e0SDimitry Andric     MI->addOperand(MachineOperand::CreateImm(0));
112b915e9e0SDimitry Andric   } else if (RegClass == &WebAssembly::F32RegClass) {
113b915e9e0SDimitry Andric     MI->setDesc(TII->get(WebAssembly::CONST_F32));
114e6d15924SDimitry Andric     auto *Val = cast<ConstantFP>(Constant::getNullValue(
115044eb2f6SDimitry Andric         Type::getFloatTy(MF.getFunction().getContext())));
116b915e9e0SDimitry Andric     MI->addOperand(MachineOperand::CreateFPImm(Val));
117b915e9e0SDimitry Andric   } else if (RegClass == &WebAssembly::F64RegClass) {
118b915e9e0SDimitry Andric     MI->setDesc(TII->get(WebAssembly::CONST_F64));
119e6d15924SDimitry Andric     auto *Val = cast<ConstantFP>(Constant::getNullValue(
120044eb2f6SDimitry Andric         Type::getDoubleTy(MF.getFunction().getContext())));
121b915e9e0SDimitry Andric     MI->addOperand(MachineOperand::CreateFPImm(Val));
122d8e91e46SDimitry Andric   } else if (RegClass == &WebAssembly::V128RegClass) {
123344a3780SDimitry Andric     MI->setDesc(TII->get(WebAssembly::CONST_V128_I64x2));
124344a3780SDimitry Andric     MI->addOperand(MachineOperand::CreateImm(0));
125344a3780SDimitry Andric     MI->addOperand(MachineOperand::CreateImm(0));
126b915e9e0SDimitry Andric   } else {
127b915e9e0SDimitry Andric     llvm_unreachable("Unexpected reg class");
128b915e9e0SDimitry Andric   }
129b915e9e0SDimitry Andric }
130b915e9e0SDimitry Andric 
13101095a5dSDimitry Andric // Determine whether a call to the callee referenced by
13201095a5dSDimitry Andric // MI->getOperand(CalleeOpNo) reads memory, writes memory, and/or has side
13301095a5dSDimitry Andric // effects.
queryCallee(const MachineInstr & MI,bool & Read,bool & Write,bool & Effects,bool & StackPointer)134cfca06d7SDimitry Andric static void queryCallee(const MachineInstr &MI, bool &Read, bool &Write,
135cfca06d7SDimitry Andric                         bool &Effects, bool &StackPointer) {
13601095a5dSDimitry Andric   // All calls can use the stack pointer.
13701095a5dSDimitry Andric   StackPointer = true;
13801095a5dSDimitry Andric 
139cfca06d7SDimitry Andric   const MachineOperand &MO = WebAssembly::getCalleeOp(MI);
14001095a5dSDimitry Andric   if (MO.isGlobal()) {
14101095a5dSDimitry Andric     const Constant *GV = MO.getGlobal();
142e6d15924SDimitry Andric     if (const auto *GA = dyn_cast<GlobalAlias>(GV))
14301095a5dSDimitry Andric       if (!GA->isInterposable())
14401095a5dSDimitry Andric         GV = GA->getAliasee();
14501095a5dSDimitry Andric 
146e6d15924SDimitry Andric     if (const auto *F = dyn_cast<Function>(GV)) {
14701095a5dSDimitry Andric       if (!F->doesNotThrow())
14801095a5dSDimitry Andric         Effects = true;
14901095a5dSDimitry Andric       if (F->doesNotAccessMemory())
15001095a5dSDimitry Andric         return;
15101095a5dSDimitry Andric       if (F->onlyReadsMemory()) {
15201095a5dSDimitry Andric         Read = true;
15301095a5dSDimitry Andric         return;
15401095a5dSDimitry Andric       }
15501095a5dSDimitry Andric     }
15601095a5dSDimitry Andric   }
15701095a5dSDimitry Andric 
15801095a5dSDimitry Andric   // Assume the worst.
15901095a5dSDimitry Andric   Write = true;
16001095a5dSDimitry Andric   Read = true;
16101095a5dSDimitry Andric   Effects = true;
16201095a5dSDimitry Andric }
16301095a5dSDimitry Andric 
16401095a5dSDimitry Andric // Determine whether MI reads memory, writes memory, has side effects,
16571d5a254SDimitry Andric // and/or uses the stack pointer value.
query(const MachineInstr & MI,bool & Read,bool & Write,bool & Effects,bool & StackPointer)1664b4fe385SDimitry Andric static void query(const MachineInstr &MI, bool &Read, bool &Write,
1674b4fe385SDimitry Andric                   bool &Effects, bool &StackPointer) {
16801095a5dSDimitry Andric   assert(!MI.isTerminator());
16901095a5dSDimitry Andric 
170eb11fae6SDimitry Andric   if (MI.isDebugInstr() || MI.isPosition())
17101095a5dSDimitry Andric     return;
17201095a5dSDimitry Andric 
17301095a5dSDimitry Andric   // Check for loads.
1744b4fe385SDimitry Andric   if (MI.mayLoad() && !MI.isDereferenceableInvariantLoad())
17501095a5dSDimitry Andric     Read = true;
17601095a5dSDimitry Andric 
17701095a5dSDimitry Andric   // Check for stores.
17801095a5dSDimitry Andric   if (MI.mayStore()) {
17901095a5dSDimitry Andric     Write = true;
18001095a5dSDimitry Andric   } else if (MI.hasOrderedMemoryRef()) {
18101095a5dSDimitry Andric     switch (MI.getOpcode()) {
182d8e91e46SDimitry Andric     case WebAssembly::DIV_S_I32:
183d8e91e46SDimitry Andric     case WebAssembly::DIV_S_I64:
184d8e91e46SDimitry Andric     case WebAssembly::REM_S_I32:
185d8e91e46SDimitry Andric     case WebAssembly::REM_S_I64:
186d8e91e46SDimitry Andric     case WebAssembly::DIV_U_I32:
187d8e91e46SDimitry Andric     case WebAssembly::DIV_U_I64:
188d8e91e46SDimitry Andric     case WebAssembly::REM_U_I32:
189d8e91e46SDimitry Andric     case WebAssembly::REM_U_I64:
190d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_S_F32:
191d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_S_F32:
192d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_S_F64:
193d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_S_F64:
194d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_U_F32:
195d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_U_F32:
196d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_U_F64:
197d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_U_F64:
19801095a5dSDimitry Andric       // These instruction have hasUnmodeledSideEffects() returning true
19901095a5dSDimitry Andric       // because they trap on overflow and invalid so they can't be arbitrarily
20001095a5dSDimitry Andric       // moved, however hasOrderedMemoryRef() interprets this plus their lack
20101095a5dSDimitry Andric       // of memoperands as having a potential unknown memory reference.
20201095a5dSDimitry Andric       break;
20301095a5dSDimitry Andric     default:
20401095a5dSDimitry Andric       // Record volatile accesses, unless it's a call, as calls are handled
20501095a5dSDimitry Andric       // specially below.
20601095a5dSDimitry Andric       if (!MI.isCall()) {
20701095a5dSDimitry Andric         Write = true;
20801095a5dSDimitry Andric         Effects = true;
20901095a5dSDimitry Andric       }
21001095a5dSDimitry Andric       break;
21101095a5dSDimitry Andric     }
21201095a5dSDimitry Andric   }
21301095a5dSDimitry Andric 
21401095a5dSDimitry Andric   // Check for side effects.
21501095a5dSDimitry Andric   if (MI.hasUnmodeledSideEffects()) {
21601095a5dSDimitry Andric     switch (MI.getOpcode()) {
217d8e91e46SDimitry Andric     case WebAssembly::DIV_S_I32:
218d8e91e46SDimitry Andric     case WebAssembly::DIV_S_I64:
219d8e91e46SDimitry Andric     case WebAssembly::REM_S_I32:
220d8e91e46SDimitry Andric     case WebAssembly::REM_S_I64:
221d8e91e46SDimitry Andric     case WebAssembly::DIV_U_I32:
222d8e91e46SDimitry Andric     case WebAssembly::DIV_U_I64:
223d8e91e46SDimitry Andric     case WebAssembly::REM_U_I32:
224d8e91e46SDimitry Andric     case WebAssembly::REM_U_I64:
225d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_S_F32:
226d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_S_F32:
227d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_S_F64:
228d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_S_F64:
229d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_U_F32:
230d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_U_F32:
231d8e91e46SDimitry Andric     case WebAssembly::I32_TRUNC_U_F64:
232d8e91e46SDimitry Andric     case WebAssembly::I64_TRUNC_U_F64:
23301095a5dSDimitry Andric       // These instructions have hasUnmodeledSideEffects() returning true
23401095a5dSDimitry Andric       // because they trap on overflow and invalid so they can't be arbitrarily
23501095a5dSDimitry Andric       // moved, however in the specific case of register stackifying, it is safe
23601095a5dSDimitry Andric       // to move them because overflow and invalid are Undefined Behavior.
23701095a5dSDimitry Andric       break;
23801095a5dSDimitry Andric     default:
23901095a5dSDimitry Andric       Effects = true;
24001095a5dSDimitry Andric       break;
24101095a5dSDimitry Andric     }
24201095a5dSDimitry Andric   }
24301095a5dSDimitry Andric 
244d8e91e46SDimitry Andric   // Check for writes to __stack_pointer global.
245cfca06d7SDimitry Andric   if ((MI.getOpcode() == WebAssembly::GLOBAL_SET_I32 ||
246cfca06d7SDimitry Andric        MI.getOpcode() == WebAssembly::GLOBAL_SET_I64) &&
247d8e91e46SDimitry Andric       strcmp(MI.getOperand(0).getSymbolName(), "__stack_pointer") == 0)
248d8e91e46SDimitry Andric     StackPointer = true;
249d8e91e46SDimitry Andric 
25001095a5dSDimitry Andric   // Analyze calls.
25101095a5dSDimitry Andric   if (MI.isCall()) {
252cfca06d7SDimitry Andric     queryCallee(MI, Read, Write, Effects, StackPointer);
25301095a5dSDimitry Andric   }
25401095a5dSDimitry Andric }
25501095a5dSDimitry Andric 
25601095a5dSDimitry Andric // Test whether Def is safe and profitable to rematerialize.
shouldRematerialize(const MachineInstr & Def,const WebAssemblyInstrInfo * TII)2574b4fe385SDimitry Andric static bool shouldRematerialize(const MachineInstr &Def,
25801095a5dSDimitry Andric                                 const WebAssemblyInstrInfo *TII) {
2594b4fe385SDimitry Andric   return Def.isAsCheapAsAMove() && TII->isTriviallyReMaterializable(Def);
26001095a5dSDimitry Andric }
26101095a5dSDimitry Andric 
26201095a5dSDimitry Andric // Identify the definition for this register at this point. This is a
26301095a5dSDimitry Andric // generalization of MachineRegisterInfo::getUniqueVRegDef that uses
26401095a5dSDimitry Andric // LiveIntervals to handle complex cases.
getVRegDef(unsigned Reg,const MachineInstr * Insert,const MachineRegisterInfo & MRI,const LiveIntervals & LIS)265e6d15924SDimitry Andric static MachineInstr *getVRegDef(unsigned Reg, const MachineInstr *Insert,
26601095a5dSDimitry Andric                                 const MachineRegisterInfo &MRI,
267d8e91e46SDimitry Andric                                 const LiveIntervals &LIS) {
26801095a5dSDimitry Andric   // Most registers are in SSA form here so we try a quick MRI query first.
26901095a5dSDimitry Andric   if (MachineInstr *Def = MRI.getUniqueVRegDef(Reg))
27001095a5dSDimitry Andric     return Def;
27101095a5dSDimitry Andric 
27201095a5dSDimitry Andric   // MRI doesn't know what the Def is. Try asking LIS.
27301095a5dSDimitry Andric   if (const VNInfo *ValNo = LIS.getInterval(Reg).getVNInfoBefore(
27401095a5dSDimitry Andric           LIS.getInstructionIndex(*Insert)))
27501095a5dSDimitry Andric     return LIS.getInstructionFromIndex(ValNo->def);
27601095a5dSDimitry Andric 
27701095a5dSDimitry Andric   return nullptr;
27801095a5dSDimitry Andric }
27901095a5dSDimitry Andric 
28001095a5dSDimitry Andric // Test whether Reg, as defined at Def, has exactly one use. This is a
2817fa27ce4SDimitry Andric // generalization of MachineRegisterInfo::hasOneNonDBGUse that uses
2827fa27ce4SDimitry Andric // LiveIntervals to handle complex cases.
hasOneNonDBGUse(unsigned Reg,MachineInstr * Def,MachineRegisterInfo & MRI,MachineDominatorTree & MDT,LiveIntervals & LIS)2837fa27ce4SDimitry Andric static bool hasOneNonDBGUse(unsigned Reg, MachineInstr *Def,
2847fa27ce4SDimitry Andric                             MachineRegisterInfo &MRI, MachineDominatorTree &MDT,
2857fa27ce4SDimitry Andric                             LiveIntervals &LIS) {
28601095a5dSDimitry Andric   // Most registers are in SSA form here so we try a quick MRI query first.
2877fa27ce4SDimitry Andric   if (MRI.hasOneNonDBGUse(Reg))
28801095a5dSDimitry Andric     return true;
28901095a5dSDimitry Andric 
29001095a5dSDimitry Andric   bool HasOne = false;
29101095a5dSDimitry Andric   const LiveInterval &LI = LIS.getInterval(Reg);
292d8e91e46SDimitry Andric   const VNInfo *DefVNI =
293d8e91e46SDimitry Andric       LI.getVNInfoAt(LIS.getInstructionIndex(*Def).getRegSlot());
29401095a5dSDimitry Andric   assert(DefVNI);
295b915e9e0SDimitry Andric   for (auto &I : MRI.use_nodbg_operands(Reg)) {
29601095a5dSDimitry Andric     const auto &Result = LI.Query(LIS.getInstructionIndex(*I.getParent()));
29701095a5dSDimitry Andric     if (Result.valueIn() == DefVNI) {
29801095a5dSDimitry Andric       if (!Result.isKill())
29901095a5dSDimitry Andric         return false;
30001095a5dSDimitry Andric       if (HasOne)
30101095a5dSDimitry Andric         return false;
30201095a5dSDimitry Andric       HasOne = true;
30301095a5dSDimitry Andric     }
30401095a5dSDimitry Andric   }
30501095a5dSDimitry Andric   return HasOne;
30601095a5dSDimitry Andric }
30701095a5dSDimitry Andric 
308dd58ef01SDimitry Andric // Test whether it's safe to move Def to just before Insert.
309dd58ef01SDimitry Andric // TODO: Compute memory dependencies in a way that doesn't require always
310dd58ef01SDimitry Andric // walking the block.
311dd58ef01SDimitry Andric // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
312dd58ef01SDimitry Andric // more precise.
isSafeToMove(const MachineOperand * Def,const MachineOperand * Use,const MachineInstr * Insert,const WebAssemblyFunctionInfo & MFI,const MachineRegisterInfo & MRI)313cfca06d7SDimitry Andric static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use,
3144b4fe385SDimitry Andric                          const MachineInstr *Insert,
315cfca06d7SDimitry Andric                          const WebAssemblyFunctionInfo &MFI,
316cfca06d7SDimitry Andric                          const MachineRegisterInfo &MRI) {
317cfca06d7SDimitry Andric   const MachineInstr *DefI = Def->getParent();
318cfca06d7SDimitry Andric   const MachineInstr *UseI = Use->getParent();
319cfca06d7SDimitry Andric   assert(DefI->getParent() == Insert->getParent());
320cfca06d7SDimitry Andric   assert(UseI->getParent() == Insert->getParent());
321cfca06d7SDimitry Andric 
322cfca06d7SDimitry Andric   // The first def of a multivalue instruction can be stackified by moving,
323cfca06d7SDimitry Andric   // since the later defs can always be placed into locals if necessary. Later
324cfca06d7SDimitry Andric   // defs can only be stackified if all previous defs are already stackified
325cfca06d7SDimitry Andric   // since ExplicitLocals will not know how to place a def in a local if a
326cfca06d7SDimitry Andric   // subsequent def is stackified. But only one def can be stackified by moving
327cfca06d7SDimitry Andric   // the instruction, so it must be the first one.
328cfca06d7SDimitry Andric   //
329cfca06d7SDimitry Andric   // TODO: This could be loosened to be the first *live* def, but care would
330cfca06d7SDimitry Andric   // have to be taken to ensure the drops of the initial dead defs can be
331cfca06d7SDimitry Andric   // placed. This would require checking that no previous defs are used in the
332cfca06d7SDimitry Andric   // same instruction as subsequent defs.
333cfca06d7SDimitry Andric   if (Def != DefI->defs().begin())
334cfca06d7SDimitry Andric     return false;
335cfca06d7SDimitry Andric 
336cfca06d7SDimitry Andric   // If any subsequent def is used prior to the current value by the same
337cfca06d7SDimitry Andric   // instruction in which the current value is used, we cannot
338cfca06d7SDimitry Andric   // stackify. Stackifying in this case would require that def moving below the
339cfca06d7SDimitry Andric   // current def in the stack, which cannot be achieved, even with locals.
340e3b55780SDimitry Andric   // Also ensure we don't sink the def past any other prior uses.
341b60736ecSDimitry Andric   for (const auto &SubsequentDef : drop_begin(DefI->defs())) {
342e3b55780SDimitry Andric     auto I = std::next(MachineBasicBlock::const_iterator(DefI));
343e3b55780SDimitry Andric     auto E = std::next(MachineBasicBlock::const_iterator(UseI));
344e3b55780SDimitry Andric     for (; I != E; ++I) {
345e3b55780SDimitry Andric       for (const auto &PriorUse : I->uses()) {
346cfca06d7SDimitry Andric         if (&PriorUse == Use)
347cfca06d7SDimitry Andric           break;
348cfca06d7SDimitry Andric         if (PriorUse.isReg() && SubsequentDef.getReg() == PriorUse.getReg())
349cfca06d7SDimitry Andric           return false;
350cfca06d7SDimitry Andric       }
351cfca06d7SDimitry Andric     }
352e3b55780SDimitry Andric   }
353cfca06d7SDimitry Andric 
354cfca06d7SDimitry Andric   // If moving is a semantic nop, it is always allowed
355cfca06d7SDimitry Andric   const MachineBasicBlock *MBB = DefI->getParent();
356cfca06d7SDimitry Andric   auto NextI = std::next(MachineBasicBlock::const_iterator(DefI));
357cfca06d7SDimitry Andric   for (auto E = MBB->end(); NextI != E && NextI->isDebugInstr(); ++NextI)
358cfca06d7SDimitry Andric     ;
359cfca06d7SDimitry Andric   if (NextI == Insert)
360cfca06d7SDimitry Andric     return true;
361dd58ef01SDimitry Andric 
362b60736ecSDimitry Andric   // 'catch' and 'catch_all' should be the first instruction of a BB and cannot
363b60736ecSDimitry Andric   // move.
364b60736ecSDimitry Andric   if (WebAssembly::isCatch(DefI->getOpcode()))
365e6d15924SDimitry Andric     return false;
366e6d15924SDimitry Andric 
367dd58ef01SDimitry Andric   // Check for register dependencies.
368b915e9e0SDimitry Andric   SmallVector<unsigned, 4> MutableRegisters;
369cfca06d7SDimitry Andric   for (const MachineOperand &MO : DefI->operands()) {
370dd58ef01SDimitry Andric     if (!MO.isReg() || MO.isUndef())
371dd58ef01SDimitry Andric       continue;
3721d5ae102SDimitry Andric     Register Reg = MO.getReg();
373dd58ef01SDimitry Andric 
374dd58ef01SDimitry Andric     // If the register is dead here and at Insert, ignore it.
375ac9a064cSDimitry Andric     if (MO.isDead() && Insert->definesRegister(Reg, /*TRI=*/nullptr) &&
376ac9a064cSDimitry Andric         !Insert->readsRegister(Reg, /*TRI=*/nullptr))
377dd58ef01SDimitry Andric       continue;
378dd58ef01SDimitry Andric 
379e3b55780SDimitry Andric     if (Reg.isPhysical()) {
38001095a5dSDimitry Andric       // Ignore ARGUMENTS; it's just used to keep the ARGUMENT_* instructions
38101095a5dSDimitry Andric       // from moving down, and we've already checked for that.
38201095a5dSDimitry Andric       if (Reg == WebAssembly::ARGUMENTS)
38301095a5dSDimitry Andric         continue;
384dd58ef01SDimitry Andric       // If the physical register is never modified, ignore it.
385dd58ef01SDimitry Andric       if (!MRI.isPhysRegModified(Reg))
386dd58ef01SDimitry Andric         continue;
387dd58ef01SDimitry Andric       // Otherwise, it's a physical register with unknown liveness.
388dd58ef01SDimitry Andric       return false;
389dd58ef01SDimitry Andric     }
390dd58ef01SDimitry Andric 
391b915e9e0SDimitry Andric     // If one of the operands isn't in SSA form, it has different values at
392b915e9e0SDimitry Andric     // different times, and we need to make sure we don't move our use across
393b915e9e0SDimitry Andric     // a different def.
394b915e9e0SDimitry Andric     if (!MO.isDef() && !MRI.hasOneDef(Reg))
395b915e9e0SDimitry Andric       MutableRegisters.push_back(Reg);
396dd58ef01SDimitry Andric   }
397dd58ef01SDimitry Andric 
39801095a5dSDimitry Andric   bool Read = false, Write = false, Effects = false, StackPointer = false;
3994b4fe385SDimitry Andric   query(*DefI, Read, Write, Effects, StackPointer);
40001095a5dSDimitry Andric 
40101095a5dSDimitry Andric   // If the instruction does not access memory and has no side effects, it has
40201095a5dSDimitry Andric   // no additional dependencies.
403b915e9e0SDimitry Andric   bool HasMutableRegisters = !MutableRegisters.empty();
404b915e9e0SDimitry Andric   if (!Read && !Write && !Effects && !StackPointer && !HasMutableRegisters)
40501095a5dSDimitry Andric     return true;
40601095a5dSDimitry Andric 
407cfca06d7SDimitry Andric   // Scan through the intervening instructions between DefI and Insert.
408cfca06d7SDimitry Andric   MachineBasicBlock::const_iterator D(DefI), I(Insert);
40901095a5dSDimitry Andric   for (--I; I != D; --I) {
41001095a5dSDimitry Andric     bool InterveningRead = false;
41101095a5dSDimitry Andric     bool InterveningWrite = false;
41201095a5dSDimitry Andric     bool InterveningEffects = false;
41301095a5dSDimitry Andric     bool InterveningStackPointer = false;
4144b4fe385SDimitry Andric     query(*I, InterveningRead, InterveningWrite, InterveningEffects,
41501095a5dSDimitry Andric           InterveningStackPointer);
41601095a5dSDimitry Andric     if (Effects && InterveningEffects)
41701095a5dSDimitry Andric       return false;
41801095a5dSDimitry Andric     if (Read && InterveningWrite)
41901095a5dSDimitry Andric       return false;
42001095a5dSDimitry Andric     if (Write && (InterveningRead || InterveningWrite))
42101095a5dSDimitry Andric       return false;
42201095a5dSDimitry Andric     if (StackPointer && InterveningStackPointer)
42301095a5dSDimitry Andric       return false;
424b915e9e0SDimitry Andric 
425b915e9e0SDimitry Andric     for (unsigned Reg : MutableRegisters)
426b915e9e0SDimitry Andric       for (const MachineOperand &MO : I->operands())
427b915e9e0SDimitry Andric         if (MO.isReg() && MO.isDef() && MO.getReg() == Reg)
428b915e9e0SDimitry Andric           return false;
429dd58ef01SDimitry Andric   }
430dd58ef01SDimitry Andric 
43101095a5dSDimitry Andric   return true;
43201095a5dSDimitry Andric }
43301095a5dSDimitry Andric 
43401095a5dSDimitry Andric /// Test whether OneUse, a use of Reg, dominates all of Reg's other uses.
oneUseDominatesOtherUses(unsigned Reg,const MachineOperand & OneUse,const MachineBasicBlock & MBB,const MachineRegisterInfo & MRI,const MachineDominatorTree & MDT,LiveIntervals & LIS,WebAssemblyFunctionInfo & MFI)435e6d15924SDimitry Andric static bool oneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse,
43601095a5dSDimitry Andric                                      const MachineBasicBlock &MBB,
43701095a5dSDimitry Andric                                      const MachineRegisterInfo &MRI,
43801095a5dSDimitry Andric                                      const MachineDominatorTree &MDT,
43901095a5dSDimitry Andric                                      LiveIntervals &LIS,
44001095a5dSDimitry Andric                                      WebAssemblyFunctionInfo &MFI) {
44101095a5dSDimitry Andric   const LiveInterval &LI = LIS.getInterval(Reg);
44201095a5dSDimitry Andric 
44301095a5dSDimitry Andric   const MachineInstr *OneUseInst = OneUse.getParent();
44401095a5dSDimitry Andric   VNInfo *OneUseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*OneUseInst));
44501095a5dSDimitry Andric 
446b915e9e0SDimitry Andric   for (const MachineOperand &Use : MRI.use_nodbg_operands(Reg)) {
44701095a5dSDimitry Andric     if (&Use == &OneUse)
44801095a5dSDimitry Andric       continue;
44901095a5dSDimitry Andric 
45001095a5dSDimitry Andric     const MachineInstr *UseInst = Use.getParent();
45101095a5dSDimitry Andric     VNInfo *UseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*UseInst));
45201095a5dSDimitry Andric 
45301095a5dSDimitry Andric     if (UseVNI != OneUseVNI)
45401095a5dSDimitry Andric       continue;
45501095a5dSDimitry Andric 
45601095a5dSDimitry Andric     if (UseInst == OneUseInst) {
45701095a5dSDimitry Andric       // Another use in the same instruction. We need to ensure that the one
45801095a5dSDimitry Andric       // selected use happens "before" it.
45901095a5dSDimitry Andric       if (&OneUse > &Use)
46001095a5dSDimitry Andric         return false;
46101095a5dSDimitry Andric     } else {
46201095a5dSDimitry Andric       // Test that the use is dominated by the one selected use.
46301095a5dSDimitry Andric       while (!MDT.dominates(OneUseInst, UseInst)) {
46401095a5dSDimitry Andric         // Actually, dominating is over-conservative. Test that the use would
46501095a5dSDimitry Andric         // happen after the one selected use in the stack evaluation order.
46601095a5dSDimitry Andric         //
467d8e91e46SDimitry Andric         // This is needed as a consequence of using implicit local.gets for
468d8e91e46SDimitry Andric         // uses and implicit local.sets for defs.
46901095a5dSDimitry Andric         if (UseInst->getDesc().getNumDefs() == 0)
47001095a5dSDimitry Andric           return false;
47101095a5dSDimitry Andric         const MachineOperand &MO = UseInst->getOperand(0);
47201095a5dSDimitry Andric         if (!MO.isReg())
47301095a5dSDimitry Andric           return false;
4741d5ae102SDimitry Andric         Register DefReg = MO.getReg();
475e3b55780SDimitry Andric         if (!DefReg.isVirtual() || !MFI.isVRegStackified(DefReg))
47601095a5dSDimitry Andric           return false;
477d8e91e46SDimitry Andric         assert(MRI.hasOneNonDBGUse(DefReg));
478d8e91e46SDimitry Andric         const MachineOperand &NewUse = *MRI.use_nodbg_begin(DefReg);
47901095a5dSDimitry Andric         const MachineInstr *NewUseInst = NewUse.getParent();
48001095a5dSDimitry Andric         if (NewUseInst == OneUseInst) {
48101095a5dSDimitry Andric           if (&OneUse > &NewUse)
48201095a5dSDimitry Andric             return false;
48301095a5dSDimitry Andric           break;
48401095a5dSDimitry Andric         }
48501095a5dSDimitry Andric         UseInst = NewUseInst;
48601095a5dSDimitry Andric       }
48701095a5dSDimitry Andric     }
48801095a5dSDimitry Andric   }
48901095a5dSDimitry Andric   return true;
49001095a5dSDimitry Andric }
49101095a5dSDimitry Andric 
492b915e9e0SDimitry Andric /// Get the appropriate tee opcode for the given register class.
getTeeOpcode(const TargetRegisterClass * RC)493e6d15924SDimitry Andric static unsigned getTeeOpcode(const TargetRegisterClass *RC) {
49401095a5dSDimitry Andric   if (RC == &WebAssembly::I32RegClass)
495b915e9e0SDimitry Andric     return WebAssembly::TEE_I32;
49601095a5dSDimitry Andric   if (RC == &WebAssembly::I64RegClass)
497b915e9e0SDimitry Andric     return WebAssembly::TEE_I64;
49801095a5dSDimitry Andric   if (RC == &WebAssembly::F32RegClass)
499b915e9e0SDimitry Andric     return WebAssembly::TEE_F32;
50001095a5dSDimitry Andric   if (RC == &WebAssembly::F64RegClass)
501b915e9e0SDimitry Andric     return WebAssembly::TEE_F64;
502b915e9e0SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
503b915e9e0SDimitry Andric     return WebAssembly::TEE_V128;
504c0981da4SDimitry Andric   if (RC == &WebAssembly::EXTERNREFRegClass)
505c0981da4SDimitry Andric     return WebAssembly::TEE_EXTERNREF;
506c0981da4SDimitry Andric   if (RC == &WebAssembly::FUNCREFRegClass)
507c0981da4SDimitry Andric     return WebAssembly::TEE_FUNCREF;
508ac9a064cSDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
509ac9a064cSDimitry Andric     return WebAssembly::TEE_EXNREF;
51001095a5dSDimitry Andric   llvm_unreachable("Unexpected register class");
51101095a5dSDimitry Andric }
51201095a5dSDimitry Andric 
51301095a5dSDimitry Andric // Shrink LI to its uses, cleaning up LI.
shrinkToUses(LiveInterval & LI,LiveIntervals & LIS)514e6d15924SDimitry Andric static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) {
51501095a5dSDimitry Andric   if (LIS.shrinkToUses(&LI)) {
51601095a5dSDimitry Andric     SmallVector<LiveInterval *, 4> SplitLIs;
51701095a5dSDimitry Andric     LIS.splitSeparateComponents(LI, SplitLIs);
51801095a5dSDimitry Andric   }
51901095a5dSDimitry Andric }
52001095a5dSDimitry Andric 
52101095a5dSDimitry Andric /// A single-use def in the same block with no intervening memory or register
52201095a5dSDimitry Andric /// dependencies; move the def down and nest it with the current instruction.
moveForSingleUse(unsigned Reg,MachineOperand & Op,MachineInstr * Def,MachineBasicBlock & MBB,MachineInstr * Insert,LiveIntervals & LIS,WebAssemblyFunctionInfo & MFI,MachineRegisterInfo & MRI)523e6d15924SDimitry Andric static MachineInstr *moveForSingleUse(unsigned Reg, MachineOperand &Op,
524d8e91e46SDimitry Andric                                       MachineInstr *Def, MachineBasicBlock &MBB,
52501095a5dSDimitry Andric                                       MachineInstr *Insert, LiveIntervals &LIS,
52601095a5dSDimitry Andric                                       WebAssemblyFunctionInfo &MFI,
52701095a5dSDimitry Andric                                       MachineRegisterInfo &MRI) {
528eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Move for single use: "; Def->dump());
52901095a5dSDimitry Andric 
530d8e91e46SDimitry Andric   WebAssemblyDebugValueManager DefDIs(Def);
5317fa27ce4SDimitry Andric   DefDIs.sink(Insert);
53201095a5dSDimitry Andric   LIS.handleMove(*Def);
53301095a5dSDimitry Andric 
5347fa27ce4SDimitry Andric   if (MRI.hasOneDef(Reg) && MRI.hasOneNonDBGUse(Reg)) {
53501095a5dSDimitry Andric     // No one else is using this register for anything so we can just stackify
53601095a5dSDimitry Andric     // it in place.
537cfca06d7SDimitry Andric     MFI.stackifyVReg(MRI, Reg);
53801095a5dSDimitry Andric   } else {
53901095a5dSDimitry Andric     // The register may have unrelated uses or defs; create a new register for
54001095a5dSDimitry Andric     // just our one def and use so that we can stackify it.
5411d5ae102SDimitry Andric     Register NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg));
54201095a5dSDimitry Andric     Op.setReg(NewReg);
5437fa27ce4SDimitry Andric     DefDIs.updateReg(NewReg);
54401095a5dSDimitry Andric 
54501095a5dSDimitry Andric     // Tell LiveIntervals about the new register.
54601095a5dSDimitry Andric     LIS.createAndComputeVirtRegInterval(NewReg);
54701095a5dSDimitry Andric 
54801095a5dSDimitry Andric     // Tell LiveIntervals about the changes to the old register.
54901095a5dSDimitry Andric     LiveInterval &LI = LIS.getInterval(Reg);
55001095a5dSDimitry Andric     LI.removeSegment(LIS.getInstructionIndex(*Def).getRegSlot(),
55101095a5dSDimitry Andric                      LIS.getInstructionIndex(*Op.getParent()).getRegSlot(),
55201095a5dSDimitry Andric                      /*RemoveDeadValNo=*/true);
55301095a5dSDimitry Andric 
554cfca06d7SDimitry Andric     MFI.stackifyVReg(MRI, NewReg);
55501095a5dSDimitry Andric 
556eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump());
55701095a5dSDimitry Andric   }
55801095a5dSDimitry Andric 
559e6d15924SDimitry Andric   imposeStackOrdering(Def);
56001095a5dSDimitry Andric   return Def;
56101095a5dSDimitry Andric }
56201095a5dSDimitry Andric 
getPrevNonDebugInst(MachineInstr * MI)5637fa27ce4SDimitry Andric static MachineInstr *getPrevNonDebugInst(MachineInstr *MI) {
5647fa27ce4SDimitry Andric   for (auto *I = MI->getPrevNode(); I; I = I->getPrevNode())
5657fa27ce4SDimitry Andric     if (!I->isDebugInstr())
5667fa27ce4SDimitry Andric       return I;
5677fa27ce4SDimitry Andric   return nullptr;
5687fa27ce4SDimitry Andric }
5697fa27ce4SDimitry Andric 
57001095a5dSDimitry Andric /// A trivially cloneable instruction; clone it and nest the new copy with the
57101095a5dSDimitry Andric /// current instruction.
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)572e6d15924SDimitry Andric static MachineInstr *rematerializeCheapDef(
57301095a5dSDimitry Andric     unsigned Reg, MachineOperand &Op, MachineInstr &Def, MachineBasicBlock &MBB,
57401095a5dSDimitry Andric     MachineBasicBlock::instr_iterator Insert, LiveIntervals &LIS,
57501095a5dSDimitry Andric     WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI,
57601095a5dSDimitry Andric     const WebAssemblyInstrInfo *TII, const WebAssemblyRegisterInfo *TRI) {
577eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Rematerializing cheap def: "; Def.dump());
578eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << " - for use in "; Op.getParent()->dump());
57901095a5dSDimitry Andric 
580d8e91e46SDimitry Andric   WebAssemblyDebugValueManager DefDIs(&Def);
581d8e91e46SDimitry Andric 
5821d5ae102SDimitry Andric   Register NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg));
5837fa27ce4SDimitry Andric   DefDIs.cloneSink(&*Insert, NewReg);
58401095a5dSDimitry Andric   Op.setReg(NewReg);
5857fa27ce4SDimitry Andric   MachineInstr *Clone = getPrevNonDebugInst(&*Insert);
5867fa27ce4SDimitry Andric   assert(Clone);
58701095a5dSDimitry Andric   LIS.InsertMachineInstrInMaps(*Clone);
58801095a5dSDimitry Andric   LIS.createAndComputeVirtRegInterval(NewReg);
589cfca06d7SDimitry Andric   MFI.stackifyVReg(MRI, NewReg);
590e6d15924SDimitry Andric   imposeStackOrdering(Clone);
59101095a5dSDimitry Andric 
592eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << " - Cloned to "; Clone->dump());
59301095a5dSDimitry Andric 
59401095a5dSDimitry Andric   // Shrink the interval.
59501095a5dSDimitry Andric   bool IsDead = MRI.use_empty(Reg);
59601095a5dSDimitry Andric   if (!IsDead) {
59701095a5dSDimitry Andric     LiveInterval &LI = LIS.getInterval(Reg);
598e6d15924SDimitry Andric     shrinkToUses(LI, LIS);
59901095a5dSDimitry Andric     IsDead = !LI.liveAt(LIS.getInstructionIndex(Def).getDeadSlot());
60001095a5dSDimitry Andric   }
60101095a5dSDimitry Andric 
60201095a5dSDimitry Andric   // If that was the last use of the original, delete the original.
60301095a5dSDimitry Andric   if (IsDead) {
604eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << " - Deleting original\n");
60501095a5dSDimitry Andric     SlotIndex Idx = LIS.getInstructionIndex(Def).getRegSlot();
606b60736ecSDimitry Andric     LIS.removePhysRegDefAt(MCRegister::from(WebAssembly::ARGUMENTS), Idx);
60701095a5dSDimitry Andric     LIS.removeInterval(Reg);
60801095a5dSDimitry Andric     LIS.RemoveMachineInstrFromMaps(Def);
6097fa27ce4SDimitry Andric     DefDIs.removeDef();
61001095a5dSDimitry Andric   }
61101095a5dSDimitry Andric 
61201095a5dSDimitry Andric   return Clone;
61301095a5dSDimitry Andric }
61401095a5dSDimitry Andric 
61501095a5dSDimitry Andric /// A multiple-use def in the same block with no intervening memory or register
61601095a5dSDimitry Andric /// dependencies; move the def down, nest it with the current instruction, and
617b915e9e0SDimitry Andric /// insert a tee to satisfy the rest of the uses. As an illustration, rewrite
618b915e9e0SDimitry Andric /// this:
61901095a5dSDimitry Andric ///
62001095a5dSDimitry Andric ///    Reg = INST ...        // Def
62101095a5dSDimitry Andric ///    INST ..., Reg, ...    // Insert
62201095a5dSDimitry Andric ///    INST ..., Reg, ...
62301095a5dSDimitry Andric ///    INST ..., Reg, ...
62401095a5dSDimitry Andric ///
62501095a5dSDimitry Andric /// to this:
62601095a5dSDimitry Andric ///
62701095a5dSDimitry Andric ///    DefReg = INST ...     // Def (to become the new Insert)
628b915e9e0SDimitry Andric ///    TeeReg, Reg = TEE_... DefReg
62901095a5dSDimitry Andric ///    INST ..., TeeReg, ... // Insert
63001095a5dSDimitry Andric ///    INST ..., Reg, ...
63101095a5dSDimitry Andric ///    INST ..., Reg, ...
63201095a5dSDimitry Andric ///
633d8e91e46SDimitry Andric /// with DefReg and TeeReg stackified. This eliminates a local.get from the
63401095a5dSDimitry Andric /// resulting code.
moveAndTeeForMultiUse(unsigned Reg,MachineOperand & Op,MachineInstr * Def,MachineBasicBlock & MBB,MachineInstr * Insert,LiveIntervals & LIS,WebAssemblyFunctionInfo & MFI,MachineRegisterInfo & MRI,const WebAssemblyInstrInfo * TII)635e6d15924SDimitry Andric static MachineInstr *moveAndTeeForMultiUse(
63601095a5dSDimitry Andric     unsigned Reg, MachineOperand &Op, MachineInstr *Def, MachineBasicBlock &MBB,
63701095a5dSDimitry Andric     MachineInstr *Insert, LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI,
63801095a5dSDimitry Andric     MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) {
639eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Move and tee for multi-use:"; Def->dump());
64001095a5dSDimitry Andric 
64101095a5dSDimitry Andric   const auto *RegClass = MRI.getRegClass(Reg);
6421d5ae102SDimitry Andric   Register TeeReg = MRI.createVirtualRegister(RegClass);
6431d5ae102SDimitry Andric   Register DefReg = MRI.createVirtualRegister(RegClass);
6447fa27ce4SDimitry Andric 
6457fa27ce4SDimitry Andric   // Move Def into place.
6467fa27ce4SDimitry Andric   WebAssemblyDebugValueManager DefDIs(Def);
6477fa27ce4SDimitry Andric   DefDIs.sink(Insert);
6487fa27ce4SDimitry Andric   LIS.handleMove(*Def);
6497fa27ce4SDimitry Andric 
6507fa27ce4SDimitry Andric   // Create the Tee and attach the registers.
65101095a5dSDimitry Andric   MachineOperand &DefMO = Def->getOperand(0);
65201095a5dSDimitry Andric   MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(),
653e6d15924SDimitry Andric                               TII->get(getTeeOpcode(RegClass)), TeeReg)
65401095a5dSDimitry Andric                           .addReg(Reg, RegState::Define)
65501095a5dSDimitry Andric                           .addReg(DefReg, getUndefRegState(DefMO.isDead()));
65601095a5dSDimitry Andric   Op.setReg(TeeReg);
6577fa27ce4SDimitry Andric   DefDIs.updateReg(DefReg);
65801095a5dSDimitry Andric   SlotIndex TeeIdx = LIS.InsertMachineInstrInMaps(*Tee).getRegSlot();
65901095a5dSDimitry Andric   SlotIndex DefIdx = LIS.getInstructionIndex(*Def).getRegSlot();
66001095a5dSDimitry Andric 
66101095a5dSDimitry Andric   // Tell LiveIntervals we moved the original vreg def from Def to Tee.
66201095a5dSDimitry Andric   LiveInterval &LI = LIS.getInterval(Reg);
66301095a5dSDimitry Andric   LiveInterval::iterator I = LI.FindSegmentContaining(DefIdx);
66401095a5dSDimitry Andric   VNInfo *ValNo = LI.getVNInfoAt(DefIdx);
66501095a5dSDimitry Andric   I->start = TeeIdx;
66601095a5dSDimitry Andric   ValNo->def = TeeIdx;
667e6d15924SDimitry Andric   shrinkToUses(LI, LIS);
66801095a5dSDimitry Andric 
66901095a5dSDimitry Andric   // Finish stackifying the new regs.
67001095a5dSDimitry Andric   LIS.createAndComputeVirtRegInterval(TeeReg);
67101095a5dSDimitry Andric   LIS.createAndComputeVirtRegInterval(DefReg);
672cfca06d7SDimitry Andric   MFI.stackifyVReg(MRI, DefReg);
673cfca06d7SDimitry Andric   MFI.stackifyVReg(MRI, TeeReg);
674e6d15924SDimitry Andric   imposeStackOrdering(Def);
675e6d15924SDimitry Andric   imposeStackOrdering(Tee);
67601095a5dSDimitry Andric 
6777fa27ce4SDimitry Andric   // Even though 'TeeReg, Reg = TEE ...', has two defs, we don't need to clone
6787fa27ce4SDimitry Andric   // DBG_VALUEs for both of them, given that the latter will cancel the former
6797fa27ce4SDimitry Andric   // anyway. Here we only clone DBG_VALUEs for TeeReg, which will be converted
6807fa27ce4SDimitry Andric   // to a local index in ExplicitLocals pass.
6817fa27ce4SDimitry Andric   DefDIs.cloneSink(Insert, TeeReg, /* CloneDef */ false);
682d8e91e46SDimitry Andric 
683eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump());
684eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << " - Tee instruction: "; Tee->dump());
68501095a5dSDimitry Andric   return Def;
68601095a5dSDimitry Andric }
68701095a5dSDimitry Andric 
68801095a5dSDimitry Andric namespace {
68901095a5dSDimitry Andric /// A stack for walking the tree of instructions being built, visiting the
69001095a5dSDimitry Andric /// MachineOperands in DFS order.
69101095a5dSDimitry Andric class TreeWalkerState {
692e6d15924SDimitry Andric   using mop_iterator = MachineInstr::mop_iterator;
693e6d15924SDimitry Andric   using mop_reverse_iterator = std::reverse_iterator<mop_iterator>;
694e6d15924SDimitry Andric   using RangeTy = iterator_range<mop_reverse_iterator>;
69501095a5dSDimitry Andric   SmallVector<RangeTy, 4> Worklist;
69601095a5dSDimitry Andric 
69701095a5dSDimitry Andric public:
TreeWalkerState(MachineInstr * Insert)69801095a5dSDimitry Andric   explicit TreeWalkerState(MachineInstr *Insert) {
69901095a5dSDimitry Andric     const iterator_range<mop_iterator> &Range = Insert->explicit_uses();
700b60736ecSDimitry Andric     if (!Range.empty())
70101095a5dSDimitry Andric       Worklist.push_back(reverse(Range));
70201095a5dSDimitry Andric   }
70301095a5dSDimitry Andric 
done() const704e6d15924SDimitry Andric   bool done() const { return Worklist.empty(); }
70501095a5dSDimitry Andric 
pop()706e6d15924SDimitry Andric   MachineOperand &pop() {
70701095a5dSDimitry Andric     RangeTy &Range = Worklist.back();
70801095a5dSDimitry Andric     MachineOperand &Op = *Range.begin();
709b60736ecSDimitry Andric     Range = drop_begin(Range);
710b60736ecSDimitry Andric     if (Range.empty())
71101095a5dSDimitry Andric       Worklist.pop_back();
712b60736ecSDimitry Andric     assert((Worklist.empty() || !Worklist.back().empty()) &&
71301095a5dSDimitry Andric            "Empty ranges shouldn't remain in the worklist");
71401095a5dSDimitry Andric     return Op;
71501095a5dSDimitry Andric   }
71601095a5dSDimitry Andric 
71701095a5dSDimitry Andric   /// Push Instr's operands onto the stack to be visited.
pushOperands(MachineInstr * Instr)718e6d15924SDimitry Andric   void pushOperands(MachineInstr *Instr) {
71901095a5dSDimitry Andric     const iterator_range<mop_iterator> &Range(Instr->explicit_uses());
720b60736ecSDimitry Andric     if (!Range.empty())
72101095a5dSDimitry Andric       Worklist.push_back(reverse(Range));
72201095a5dSDimitry Andric   }
72301095a5dSDimitry Andric 
72401095a5dSDimitry Andric   /// Some of Instr's operands are on the top of the stack; remove them and
72501095a5dSDimitry Andric   /// re-insert them starting from the beginning (because we've commuted them).
resetTopOperands(MachineInstr * Instr)726e6d15924SDimitry Andric   void resetTopOperands(MachineInstr *Instr) {
727e6d15924SDimitry Andric     assert(hasRemainingOperands(Instr) &&
72801095a5dSDimitry Andric            "Reseting operands should only be done when the instruction has "
72901095a5dSDimitry Andric            "an operand still on the stack");
73001095a5dSDimitry Andric     Worklist.back() = reverse(Instr->explicit_uses());
73101095a5dSDimitry Andric   }
73201095a5dSDimitry Andric 
73301095a5dSDimitry Andric   /// Test whether Instr has operands remaining to be visited at the top of
73401095a5dSDimitry Andric   /// the stack.
hasRemainingOperands(const MachineInstr * Instr) const735e6d15924SDimitry Andric   bool hasRemainingOperands(const MachineInstr *Instr) const {
73601095a5dSDimitry Andric     if (Worklist.empty())
73701095a5dSDimitry Andric       return false;
73801095a5dSDimitry Andric     const RangeTy &Range = Worklist.back();
739b60736ecSDimitry Andric     return !Range.empty() && Range.begin()->getParent() == Instr;
74001095a5dSDimitry Andric   }
74101095a5dSDimitry Andric 
74201095a5dSDimitry Andric   /// Test whether the given register is present on the stack, indicating an
74301095a5dSDimitry Andric   /// operand in the tree that we haven't visited yet. Moving a definition of
74401095a5dSDimitry Andric   /// Reg to a point in the tree after that would change its value.
74501095a5dSDimitry Andric   ///
746d8e91e46SDimitry Andric   /// This is needed as a consequence of using implicit local.gets for
747d8e91e46SDimitry Andric   /// uses and implicit local.sets for defs.
isOnStack(unsigned Reg) const748e6d15924SDimitry Andric   bool isOnStack(unsigned Reg) const {
74901095a5dSDimitry Andric     for (const RangeTy &Range : Worklist)
75001095a5dSDimitry Andric       for (const MachineOperand &MO : Range)
75101095a5dSDimitry Andric         if (MO.isReg() && MO.getReg() == Reg)
75201095a5dSDimitry Andric           return true;
75301095a5dSDimitry Andric     return false;
75401095a5dSDimitry Andric   }
75501095a5dSDimitry Andric };
75601095a5dSDimitry Andric 
75701095a5dSDimitry Andric /// State to keep track of whether commuting is in flight or whether it's been
75801095a5dSDimitry Andric /// tried for the current instruction and didn't work.
75901095a5dSDimitry Andric class CommutingState {
76001095a5dSDimitry Andric   /// There are effectively three states: the initial state where we haven't
761d8e91e46SDimitry Andric   /// started commuting anything and we don't know anything yet, the tentative
76201095a5dSDimitry Andric   /// state where we've commuted the operands of the current instruction and are
763d8e91e46SDimitry Andric   /// revisiting it, and the declined state where we've reverted the operands
76401095a5dSDimitry Andric   /// back to their original order and will no longer commute it further.
765e6d15924SDimitry Andric   bool TentativelyCommuting = false;
766e6d15924SDimitry Andric   bool Declined = false;
76701095a5dSDimitry Andric 
76801095a5dSDimitry Andric   /// During the tentative state, these hold the operand indices of the commuted
76901095a5dSDimitry Andric   /// operands.
77001095a5dSDimitry Andric   unsigned Operand0, Operand1;
77101095a5dSDimitry Andric 
77201095a5dSDimitry Andric public:
77301095a5dSDimitry Andric   /// Stackification for an operand was not successful due to ordering
77401095a5dSDimitry Andric   /// constraints. If possible, and if we haven't already tried it and declined
77501095a5dSDimitry Andric   /// it, commute Insert's operands and prepare to revisit it.
maybeCommute(MachineInstr * Insert,TreeWalkerState & TreeWalker,const WebAssemblyInstrInfo * TII)776e6d15924SDimitry Andric   void maybeCommute(MachineInstr *Insert, TreeWalkerState &TreeWalker,
77701095a5dSDimitry Andric                     const WebAssemblyInstrInfo *TII) {
77801095a5dSDimitry Andric     if (TentativelyCommuting) {
77901095a5dSDimitry Andric       assert(!Declined &&
78001095a5dSDimitry Andric              "Don't decline commuting until you've finished trying it");
78101095a5dSDimitry Andric       // Commuting didn't help. Revert it.
78201095a5dSDimitry Andric       TII->commuteInstruction(*Insert, /*NewMI=*/false, Operand0, Operand1);
78301095a5dSDimitry Andric       TentativelyCommuting = false;
78401095a5dSDimitry Andric       Declined = true;
785e6d15924SDimitry Andric     } else if (!Declined && TreeWalker.hasRemainingOperands(Insert)) {
78601095a5dSDimitry Andric       Operand0 = TargetInstrInfo::CommuteAnyOperandIndex;
78701095a5dSDimitry Andric       Operand1 = TargetInstrInfo::CommuteAnyOperandIndex;
78801095a5dSDimitry Andric       if (TII->findCommutedOpIndices(*Insert, Operand0, Operand1)) {
78901095a5dSDimitry Andric         // Tentatively commute the operands and try again.
79001095a5dSDimitry Andric         TII->commuteInstruction(*Insert, /*NewMI=*/false, Operand0, Operand1);
791e6d15924SDimitry Andric         TreeWalker.resetTopOperands(Insert);
79201095a5dSDimitry Andric         TentativelyCommuting = true;
79301095a5dSDimitry Andric         Declined = false;
79401095a5dSDimitry Andric       }
79501095a5dSDimitry Andric     }
79601095a5dSDimitry Andric   }
79701095a5dSDimitry Andric 
79801095a5dSDimitry Andric   /// Stackification for some operand was successful. Reset to the default
79901095a5dSDimitry Andric   /// state.
reset()800e6d15924SDimitry Andric   void reset() {
80101095a5dSDimitry Andric     TentativelyCommuting = false;
80201095a5dSDimitry Andric     Declined = false;
80301095a5dSDimitry Andric   }
80401095a5dSDimitry Andric };
80501095a5dSDimitry Andric } // end anonymous namespace
80601095a5dSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)807dd58ef01SDimitry Andric bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
808eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Register Stackifying **********\n"
809dd58ef01SDimitry Andric                        "********** Function: "
810dd58ef01SDimitry Andric                     << MF.getName() << '\n');
811dd58ef01SDimitry Andric 
812dd58ef01SDimitry Andric   bool Changed = false;
813dd58ef01SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
814dd58ef01SDimitry Andric   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
81501095a5dSDimitry Andric   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
81601095a5dSDimitry Andric   const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
817ac9a064cSDimitry Andric   auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
818ac9a064cSDimitry Andric   auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS();
819dd58ef01SDimitry Andric 
820dd58ef01SDimitry Andric   // Walk the instructions from the bottom up. Currently we don't look past
821dd58ef01SDimitry Andric   // block boundaries, and the blocks aren't ordered so the block visitation
822dd58ef01SDimitry Andric   // order isn't significant, but we may want to change this in the future.
823dd58ef01SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
824050e163aSDimitry Andric     // Don't use a range-based for loop, because we modify the list as we're
825050e163aSDimitry Andric     // iterating over it and the end iterator may change.
826050e163aSDimitry Andric     for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) {
827050e163aSDimitry Andric       MachineInstr *Insert = &*MII;
828dd58ef01SDimitry Andric       // Don't nest anything inside an inline asm, because we don't have
829dd58ef01SDimitry Andric       // constraints for $push inputs.
830e6d15924SDimitry Andric       if (Insert->isInlineAsm())
83101095a5dSDimitry Andric         continue;
83201095a5dSDimitry Andric 
83301095a5dSDimitry Andric       // Ignore debugging intrinsics.
834e6d15924SDimitry Andric       if (Insert->isDebugValue())
83501095a5dSDimitry Andric         continue;
836dd58ef01SDimitry Andric 
837dd58ef01SDimitry Andric       // Iterate through the inputs in reverse order, since we'll be pulling
838dd58ef01SDimitry Andric       // operands off the stack in LIFO order.
83901095a5dSDimitry Andric       CommutingState Commuting;
84001095a5dSDimitry Andric       TreeWalkerState TreeWalker(Insert);
841e6d15924SDimitry Andric       while (!TreeWalker.done()) {
842cfca06d7SDimitry Andric         MachineOperand &Use = TreeWalker.pop();
84301095a5dSDimitry Andric 
844dd58ef01SDimitry Andric         // We're only interested in explicit virtual register operands.
845cfca06d7SDimitry Andric         if (!Use.isReg())
846dd58ef01SDimitry Andric           continue;
847dd58ef01SDimitry Andric 
848cfca06d7SDimitry Andric         Register Reg = Use.getReg();
849cfca06d7SDimitry Andric         assert(Use.isUse() && "explicit_uses() should only iterate over uses");
850cfca06d7SDimitry Andric         assert(!Use.isImplicit() &&
85101095a5dSDimitry Andric                "explicit_uses() should only iterate over explicit operands");
852e3b55780SDimitry Andric         if (Reg.isPhysical())
853dd58ef01SDimitry Andric           continue;
854dd58ef01SDimitry Andric 
855b915e9e0SDimitry Andric         // Identify the definition for this register at this point.
856cfca06d7SDimitry Andric         MachineInstr *DefI = getVRegDef(Reg, Insert, MRI, LIS);
857cfca06d7SDimitry Andric         if (!DefI)
858dd58ef01SDimitry Andric           continue;
859dd58ef01SDimitry Andric 
860dd58ef01SDimitry Andric         // Don't nest an INLINE_ASM def into anything, because we don't have
861dd58ef01SDimitry Andric         // constraints for $pop outputs.
862cfca06d7SDimitry Andric         if (DefI->isInlineAsm())
863dd58ef01SDimitry Andric           continue;
864dd58ef01SDimitry Andric 
865dd58ef01SDimitry Andric         // Argument instructions represent live-in registers and not real
866dd58ef01SDimitry Andric         // instructions.
867cfca06d7SDimitry Andric         if (WebAssembly::isArgument(DefI->getOpcode()))
868e6d15924SDimitry Andric           continue;
869e6d15924SDimitry Andric 
870ac9a064cSDimitry Andric         MachineOperand *Def =
871ac9a064cSDimitry Andric             DefI->findRegisterDefOperand(Reg, /*TRI=*/nullptr);
872cfca06d7SDimitry Andric         assert(Def != nullptr);
873cfca06d7SDimitry Andric 
87401095a5dSDimitry Andric         // Decide which strategy to take. Prefer to move a single-use value
875b915e9e0SDimitry Andric         // over cloning it, and prefer cloning over introducing a tee.
87601095a5dSDimitry Andric         // For moving, we require the def to be in the same block as the use;
87701095a5dSDimitry Andric         // this makes things simpler (LiveIntervals' handleMove function only
87801095a5dSDimitry Andric         // supports intra-block moves) and it's MachineSink's job to catch all
87901095a5dSDimitry Andric         // the sinking opportunities anyway.
880cfca06d7SDimitry Andric         bool SameBlock = DefI->getParent() == &MBB;
8814b4fe385SDimitry Andric         bool CanMove = SameBlock && isSafeToMove(Def, &Use, Insert, MFI, MRI) &&
882e6d15924SDimitry Andric                        !TreeWalker.isOnStack(Reg);
8837fa27ce4SDimitry Andric         if (CanMove && hasOneNonDBGUse(Reg, DefI, MRI, MDT, LIS)) {
884cfca06d7SDimitry Andric           Insert = moveForSingleUse(Reg, Use, DefI, MBB, Insert, LIS, MFI, MRI);
885cfca06d7SDimitry Andric 
886cfca06d7SDimitry Andric           // If we are removing the frame base reg completely, remove the debug
887cfca06d7SDimitry Andric           // info as well.
888cfca06d7SDimitry Andric           // TODO: Encode this properly as a stackified value.
889cfca06d7SDimitry Andric           if (MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Reg)
890cfca06d7SDimitry Andric             MFI.clearFrameBaseVreg();
8914b4fe385SDimitry Andric         } else if (shouldRematerialize(*DefI, TII)) {
89201095a5dSDimitry Andric           Insert =
893cfca06d7SDimitry Andric               rematerializeCheapDef(Reg, Use, *DefI, MBB, Insert->getIterator(),
89401095a5dSDimitry Andric                                     LIS, MFI, MRI, TII, TRI);
895cfca06d7SDimitry Andric         } else if (CanMove && oneUseDominatesOtherUses(Reg, Use, MBB, MRI, MDT,
896cfca06d7SDimitry Andric                                                        LIS, MFI)) {
897cfca06d7SDimitry Andric           Insert = moveAndTeeForMultiUse(Reg, Use, DefI, MBB, Insert, LIS, MFI,
89801095a5dSDimitry Andric                                          MRI, TII);
89901095a5dSDimitry Andric         } else {
90001095a5dSDimitry Andric           // We failed to stackify the operand. If the problem was ordering
90101095a5dSDimitry Andric           // constraints, Commuting may be able to help.
90201095a5dSDimitry Andric           if (!CanMove && SameBlock)
903e6d15924SDimitry Andric             Commuting.maybeCommute(Insert, TreeWalker, TII);
90401095a5dSDimitry Andric           // Proceed to the next operand.
905dd58ef01SDimitry Andric           continue;
906dd58ef01SDimitry Andric         }
90701095a5dSDimitry Andric 
908cfca06d7SDimitry Andric         // Stackifying a multivalue def may unlock in-place stackification of
909cfca06d7SDimitry Andric         // subsequent defs. TODO: Handle the case where the consecutive uses are
910cfca06d7SDimitry Andric         // not all in the same instruction.
911cfca06d7SDimitry Andric         auto *SubsequentDef = Insert->defs().begin();
912cfca06d7SDimitry Andric         auto *SubsequentUse = &Use;
913cfca06d7SDimitry Andric         while (SubsequentDef != Insert->defs().end() &&
914cfca06d7SDimitry Andric                SubsequentUse != Use.getParent()->uses().end()) {
915cfca06d7SDimitry Andric           if (!SubsequentDef->isReg() || !SubsequentUse->isReg())
916cfca06d7SDimitry Andric             break;
9176f8fc217SDimitry Andric           Register DefReg = SubsequentDef->getReg();
9186f8fc217SDimitry Andric           Register UseReg = SubsequentUse->getReg();
919cfca06d7SDimitry Andric           // TODO: This single-use restriction could be relaxed by using tees
9207fa27ce4SDimitry Andric           if (DefReg != UseReg || !MRI.hasOneNonDBGUse(DefReg))
921cfca06d7SDimitry Andric             break;
922cfca06d7SDimitry Andric           MFI.stackifyVReg(MRI, DefReg);
923cfca06d7SDimitry Andric           ++SubsequentDef;
924cfca06d7SDimitry Andric           ++SubsequentUse;
925cfca06d7SDimitry Andric         }
926cfca06d7SDimitry Andric 
927b915e9e0SDimitry Andric         // If the instruction we just stackified is an IMPLICIT_DEF, convert it
928b915e9e0SDimitry Andric         // to a constant 0 so that the def is explicit, and the push/pop
929b915e9e0SDimitry Andric         // correspondence is maintained.
930b915e9e0SDimitry Andric         if (Insert->getOpcode() == TargetOpcode::IMPLICIT_DEF)
931e6d15924SDimitry Andric           convertImplicitDefToConstZero(Insert, MRI, TII, MF, LIS);
932b915e9e0SDimitry Andric 
93301095a5dSDimitry Andric         // We stackified an operand. Add the defining instruction's operands to
93401095a5dSDimitry Andric         // the worklist stack now to continue to build an ever deeper tree.
935e6d15924SDimitry Andric         Commuting.reset();
936e6d15924SDimitry Andric         TreeWalker.pushOperands(Insert);
93701095a5dSDimitry Andric       }
93801095a5dSDimitry Andric 
93901095a5dSDimitry Andric       // If we stackified any operands, skip over the tree to start looking for
94001095a5dSDimitry Andric       // the next instruction we can build a tree on.
94101095a5dSDimitry Andric       if (Insert != &*MII) {
942e6d15924SDimitry Andric         imposeStackOrdering(&*MII);
943b915e9e0SDimitry Andric         MII = MachineBasicBlock::iterator(Insert).getReverse();
94401095a5dSDimitry Andric         Changed = true;
94501095a5dSDimitry Andric       }
946dd58ef01SDimitry Andric     }
947dd58ef01SDimitry Andric   }
948dd58ef01SDimitry Andric 
949b915e9e0SDimitry Andric   // If we used VALUE_STACK anywhere, add it to the live-in sets everywhere so
95001095a5dSDimitry Andric   // that it never looks like a use-before-def.
951dd58ef01SDimitry Andric   if (Changed) {
952b915e9e0SDimitry Andric     MF.getRegInfo().addLiveIn(WebAssembly::VALUE_STACK);
953dd58ef01SDimitry Andric     for (MachineBasicBlock &MBB : MF)
954b915e9e0SDimitry Andric       MBB.addLiveIn(WebAssembly::VALUE_STACK);
955dd58ef01SDimitry Andric   }
956dd58ef01SDimitry Andric 
957dd58ef01SDimitry Andric #ifndef NDEBUG
95801095a5dSDimitry Andric   // Verify that pushes and pops are performed in LIFO order.
959dd58ef01SDimitry Andric   SmallVector<unsigned, 0> Stack;
960dd58ef01SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
961dd58ef01SDimitry Andric     for (MachineInstr &MI : MBB) {
962eb11fae6SDimitry Andric       if (MI.isDebugInstr())
96301095a5dSDimitry Andric         continue;
964cfca06d7SDimitry Andric       for (MachineOperand &MO : reverse(MI.explicit_uses())) {
965dd58ef01SDimitry Andric         if (!MO.isReg())
966dd58ef01SDimitry Andric           continue;
9671d5ae102SDimitry Andric         Register Reg = MO.getReg();
968cfca06d7SDimitry Andric         if (MFI.isVRegStackified(Reg))
96901095a5dSDimitry Andric           assert(Stack.pop_back_val() == Reg &&
97001095a5dSDimitry Andric                  "Register stack pop should be paired with a push");
971dd58ef01SDimitry Andric       }
972cfca06d7SDimitry Andric       for (MachineOperand &MO : MI.defs()) {
973cfca06d7SDimitry Andric         if (!MO.isReg())
974cfca06d7SDimitry Andric           continue;
975cfca06d7SDimitry Andric         Register Reg = MO.getReg();
976cfca06d7SDimitry Andric         if (MFI.isVRegStackified(Reg))
977cfca06d7SDimitry Andric           Stack.push_back(MO.getReg());
978dd58ef01SDimitry Andric       }
979dd58ef01SDimitry Andric     }
980dd58ef01SDimitry Andric     // TODO: Generalize this code to support keeping values on the stack across
981dd58ef01SDimitry Andric     // basic block boundaries.
98201095a5dSDimitry Andric     assert(Stack.empty() &&
98301095a5dSDimitry Andric            "Register stack pushes and pops should be balanced");
984dd58ef01SDimitry Andric   }
985dd58ef01SDimitry Andric #endif
986dd58ef01SDimitry Andric 
987dd58ef01SDimitry Andric   return Changed;
988dd58ef01SDimitry Andric }
989