//===-- WebAssemblyArgumentMove.cpp - Argument instruction moving ---------===// // // 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 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 "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "Utils/WebAssemblyUtilities.h" #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.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) {} StringRef getPassName() const override { return "WebAssembly Argument Move"; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addPreserved(); AU.addPreservedID(MachineDominatorsID); MachineFunctionPass::getAnalysisUsage(AU); } bool runOnMachineFunction(MachineFunction &MF) override; }; } // end anonymous namespace char WebAssemblyArgumentMove::ID = 0; INITIALIZE_PASS(WebAssemblyArgumentMove, DEBUG_TYPE, "Move ARGUMENT instructions for WebAssembly", false, false) FunctionPass *llvm::createWebAssemblyArgumentMove() { return new WebAssemblyArgumentMove(); } bool WebAssemblyArgumentMove::runOnMachineFunction(MachineFunction &MF) { LLVM_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 (MachineInstr &MI : EntryMBB) { if (!WebAssembly::isArgument(MI.getOpcode())) { InsertPt = MI; break; } } // Now move any argument instructions later in the block // to before our first NonArg instruction. for (MachineInstr &MI : llvm::make_range(InsertPt, EntryMBB.end())) { if (WebAssembly::isArgument(MI.getOpcode())) { EntryMBB.insert(InsertPt, MI.removeFromParent()); Changed = true; } } return Changed; }