1292915Sdim//===-- WebAssemblyArgumentMove.cpp - Argument instruction moving ---------===//
2292915Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6292915Sdim//
7292915Sdim//===----------------------------------------------------------------------===//
8292915Sdim///
9292915Sdim/// \file
10341825Sdim/// This file moves ARGUMENT instructions after ScheduleDAG scheduling.
11292915Sdim///
12292915Sdim/// Arguments are really live-in registers, however, since we use virtual
13292915Sdim/// registers and LLVM doesn't support live-in virtual registers, we're
14292915Sdim/// currently making do with ARGUMENT instructions which are placed at the top
15292915Sdim/// of the entry block. The trick is to get them to *stay* at the top of the
16292915Sdim/// entry block.
17292915Sdim///
18292915Sdim/// The ARGUMENTS physical register keeps these instructions pinned in place
19292915Sdim/// during liveness-aware CodeGen passes, however one thing which does not
20292915Sdim/// respect this is the ScheduleDAG scheduler. This pass is therefore run
21292915Sdim/// immediately after that.
22292915Sdim///
23292915Sdim/// This is all hopefully a temporary solution until we find a better solution
24292915Sdim/// for describing the live-in nature of arguments.
25292915Sdim///
26292915Sdim//===----------------------------------------------------------------------===//
27292915Sdim
28314564Sdim#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
29292915Sdim#include "WebAssembly.h"
30292915Sdim#include "WebAssemblyMachineFunctionInfo.h"
31314564Sdim#include "WebAssemblySubtarget.h"
32314564Sdim#include "WebAssemblyUtilities.h"
33292915Sdim#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
34292915Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
35292915Sdim#include "llvm/CodeGen/Passes.h"
36292915Sdim#include "llvm/Support/Debug.h"
37292915Sdim#include "llvm/Support/raw_ostream.h"
38292915Sdimusing namespace llvm;
39292915Sdim
40292915Sdim#define DEBUG_TYPE "wasm-argument-move"
41292915Sdim
42292915Sdimnamespace {
43292915Sdimclass WebAssemblyArgumentMove final : public MachineFunctionPass {
44292915Sdimpublic:
45292915Sdim  static char ID; // Pass identification, replacement for typeid
46292915Sdim  WebAssemblyArgumentMove() : MachineFunctionPass(ID) {}
47292915Sdim
48314564Sdim  StringRef getPassName() const override { return "WebAssembly Argument Move"; }
49292915Sdim
50292915Sdim  void getAnalysisUsage(AnalysisUsage &AU) const override {
51292915Sdim    AU.setPreservesCFG();
52292915Sdim    AU.addPreserved<MachineBlockFrequencyInfo>();
53292915Sdim    AU.addPreservedID(MachineDominatorsID);
54292915Sdim    MachineFunctionPass::getAnalysisUsage(AU);
55292915Sdim  }
56292915Sdim
57292915Sdim  bool runOnMachineFunction(MachineFunction &MF) override;
58292915Sdim};
59292915Sdim} // end anonymous namespace
60292915Sdim
61292915Sdimchar WebAssemblyArgumentMove::ID = 0;
62341825SdimINITIALIZE_PASS(WebAssemblyArgumentMove, DEBUG_TYPE,
63341825Sdim                "Move ARGUMENT instructions for WebAssembly", false, false)
64341825Sdim
65292915SdimFunctionPass *llvm::createWebAssemblyArgumentMove() {
66292915Sdim  return new WebAssemblyArgumentMove();
67292915Sdim}
68292915Sdim
69292915Sdimbool WebAssemblyArgumentMove::runOnMachineFunction(MachineFunction &MF) {
70341825Sdim  LLVM_DEBUG({
71292915Sdim    dbgs() << "********** Argument Move **********\n"
72292915Sdim           << "********** Function: " << MF.getName() << '\n';
73292915Sdim  });
74292915Sdim
75292915Sdim  bool Changed = false;
76292915Sdim  MachineBasicBlock &EntryMBB = MF.front();
77292915Sdim  MachineBasicBlock::iterator InsertPt = EntryMBB.end();
78292915Sdim
79292915Sdim  // Look for the first NonArg instruction.
80309124Sdim  for (MachineInstr &MI : EntryMBB) {
81353358Sdim    if (!WebAssembly::isArgument(MI.getOpcode())) {
82309124Sdim      InsertPt = MI;
83292915Sdim      break;
84292915Sdim    }
85292915Sdim  }
86292915Sdim
87292915Sdim  // Now move any argument instructions later in the block
88292915Sdim  // to before our first NonArg instruction.
89309124Sdim  for (MachineInstr &MI : llvm::make_range(InsertPt, EntryMBB.end())) {
90353358Sdim    if (WebAssembly::isArgument(MI.getOpcode())) {
91309124Sdim      EntryMBB.insert(InsertPt, MI.removeFromParent());
92292915Sdim      Changed = true;
93292915Sdim    }
94292915Sdim  }
95292915Sdim
96292915Sdim  return Changed;
97292915Sdim}
98