//===-- WebAssemblyRegStackify.cpp - Register Stackification --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file implements a register stacking pass. /// /// This pass reorders instructions to put register uses and defs in an order /// such that they form single-use expression trees. Registers fitting this form /// are then marked as "stackified", meaning references to them are replaced by /// "push" and "pop" from the value stack. /// /// This is primarily a code size optimization, since temporary values on the /// value stack don't need to be named. /// //===----------------------------------------------------------------------===// #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* #include "WebAssembly.h" #include "WebAssemblyDebugValueManager.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyUtilities.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/LiveIntervals.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include <iterator> usingnamespacellvm; #define DEBUG_TYPE … namespace { class WebAssemblyRegStackify final : public MachineFunctionPass { … }; } // end anonymous namespace char WebAssemblyRegStackify::ID = …; INITIALIZE_PASS(…) FunctionPass *llvm::createWebAssemblyRegStackify() { … } // Decorate the given instruction with implicit operands that enforce the // expression stack ordering constraints for an instruction which is on // the expression stack. static void imposeStackOrdering(MachineInstr *MI) { … } // Convert an IMPLICIT_DEF instruction into an instruction which defines // a constant zero value. static void convertImplicitDefToConstZero(MachineInstr *MI, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineFunction &MF, LiveIntervals &LIS) { … } // Determine whether a call to the callee referenced by // MI->getOperand(CalleeOpNo) reads memory, writes memory, and/or has side // effects. static void queryCallee(const MachineInstr &MI, bool &Read, bool &Write, bool &Effects, bool &StackPointer) { … } // Determine whether MI reads memory, writes memory, has side effects, // and/or uses the stack pointer value. static void query(const MachineInstr &MI, bool &Read, bool &Write, bool &Effects, bool &StackPointer) { … } // Test whether Def is safe and profitable to rematerialize. static bool shouldRematerialize(const MachineInstr &Def, const WebAssemblyInstrInfo *TII) { … } // Identify the definition for this register at this point. This is a // generalization of MachineRegisterInfo::getUniqueVRegDef that uses // LiveIntervals to handle complex cases. static MachineInstr *getVRegDef(unsigned Reg, const MachineInstr *Insert, const MachineRegisterInfo &MRI, const LiveIntervals &LIS) { … } // 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) { … } // Test whether it's safe to move Def to just before Insert. // TODO: Compute memory dependencies in a way that doesn't require always // walking the block. // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be // more precise. static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, const MachineInstr *Insert, const WebAssemblyFunctionInfo &MFI, const MachineRegisterInfo &MRI) { … } /// 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) { … } /// Get the appropriate tee opcode for the given register class. static unsigned getTeeOpcode(const TargetRegisterClass *RC) { … } // Shrink LI to its uses, cleaning up LI. static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) { … } /// A single-use def in the same block with no intervening memory or register /// 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, WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI) { … } 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) { … } /// A multiple-use def in the same block with no intervening memory or register /// dependencies; move the def down, nest it with the current instruction, and /// insert a tee to satisfy the rest of the uses. As an illustration, rewrite /// this: /// /// Reg = INST ... // Def /// INST ..., Reg, ... // Insert /// INST ..., Reg, ... /// INST ..., Reg, ... /// /// to this: /// /// DefReg = INST ... // Def (to become the new Insert) /// TeeReg, Reg = TEE_... DefReg /// INST ..., TeeReg, ... // Insert /// INST ..., Reg, ... /// INST ..., Reg, ... /// /// with DefReg and TeeReg stackified. This eliminates a local.get from the /// resulting code. static MachineInstr *moveAndTeeForMultiUse( unsigned Reg, MachineOperand &Op, MachineInstr *Def, MachineBasicBlock &MBB, MachineInstr *Insert, LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) { … } namespace { /// A stack for walking the tree of instructions being built, visiting the /// MachineOperands in DFS order. class TreeWalkerState { … }; /// State to keep track of whether commuting is in flight or whether it's been /// tried for the current instruction and didn't work. class CommutingState { … }; } // end anonymous namespace bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { … }