//===-- WebAssemblyArgumentMove.cpp - Argument instruction moving ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file moves ARGUMENT instructions after ScheduleDAG scheduling. /// /// Arguments are really live-in registers, however, since we use virtual /// registers and LLVM doesn't support live-in virtual registers, we're /// currently making do with ARGUMENT instructions which are placed at the top /// of the entry block. The trick is to get them to *stay* at the top of the /// entry block. /// /// The ARGUMENTS physical register keeps these instructions pinned in place /// during liveness-aware CodeGen passes, however one thing which does not /// respect this is the ScheduleDAG scheduler. This pass is therefore run /// immediately after that. /// /// This is all hopefully a temporary solution until we find a better solution /// for describing the live-in nature of arguments. /// //===----------------------------------------------------------------------===// #include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssemblyMachineFunctionInfo.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "wasm-argument-move" namespace { class WebAssemblyArgumentMove final : public MachineFunctionPass { public: static char ID; // Pass identification, replacement for typeid WebAssemblyArgumentMove() : MachineFunctionPass(ID) {} const char *getPassName() const override { return "WebAssembly Argument Move"; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addPreserved<MachineBlockFrequencyInfo>(); AU.addPreservedID(MachineDominatorsID); MachineFunctionPass::getAnalysisUsage(AU); } bool runOnMachineFunction(MachineFunction &MF) override; }; } // end anonymous namespace char WebAssemblyArgumentMove::ID = 0; FunctionPass *llvm::createWebAssemblyArgumentMove() { return new WebAssemblyArgumentMove(); } /// Test whether the given instruction is an ARGUMENT. static bool IsArgument(const MachineInstr *MI) { switch (MI->getOpcode()) { case WebAssembly::ARGUMENT_I32: case WebAssembly::ARGUMENT_I64: case WebAssembly::ARGUMENT_F32: case WebAssembly::ARGUMENT_F64: return true; default: return false; } } bool WebAssemblyArgumentMove::runOnMachineFunction(MachineFunction &MF) { DEBUG({ dbgs() << "********** Argument Move **********\n" << "********** Function: " << MF.getName() << '\n'; }); bool Changed = false; MachineBasicBlock &EntryMBB = MF.front(); MachineBasicBlock::iterator InsertPt = EntryMBB.end(); // Look for the first NonArg instruction. for (auto MII = EntryMBB.begin(), MIE = EntryMBB.end(); MII != MIE; ++MII) { MachineInstr *MI = MII; if (!IsArgument(MI)) { InsertPt = MII; break; } } // Now move any argument instructions later in the block // to before our first NonArg instruction. for (auto I = InsertPt, E = EntryMBB.end(); I != E; ++I) { MachineInstr *MI = I; if (IsArgument(MI)) { EntryMBB.insert(InsertPt, MI->removeFromParent()); Changed = true; } } return Changed; }