xref: /src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
11a82d4c0SDimitry Andric //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//
21a82d4c0SDimitry 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
61a82d4c0SDimitry Andric //
71a82d4c0SDimitry Andric //===----------------------------------------------------------------------===//
81a82d4c0SDimitry Andric ///
91a82d4c0SDimitry Andric /// \file
10eb11fae6SDimitry Andric /// This file contains the WebAssembly implementation of the
111a82d4c0SDimitry Andric /// TargetInstrInfo class.
121a82d4c0SDimitry Andric ///
131a82d4c0SDimitry Andric //===----------------------------------------------------------------------===//
141a82d4c0SDimitry Andric 
151a82d4c0SDimitry Andric #include "WebAssemblyInstrInfo.h"
161a82d4c0SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17706b4fc4SDimitry Andric #include "WebAssembly.h"
1801095a5dSDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
191a82d4c0SDimitry Andric #include "WebAssemblySubtarget.h"
20b1c73532SDimitry Andric #include "WebAssemblyUtilities.h"
211a82d4c0SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
221a82d4c0SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
231a82d4c0SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
241a82d4c0SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
251a82d4c0SDimitry Andric using namespace llvm;
261a82d4c0SDimitry Andric 
271a82d4c0SDimitry Andric #define DEBUG_TYPE "wasm-instr-info"
281a82d4c0SDimitry Andric 
29dd58ef01SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR
30dd58ef01SDimitry Andric #include "WebAssemblyGenInstrInfo.inc"
31dd58ef01SDimitry Andric 
32e6d15924SDimitry Andric // defines WebAssembly::getNamedOperandIdx
33e6d15924SDimitry Andric #define GET_INSTRINFO_NAMED_OPS
34e6d15924SDimitry Andric #include "WebAssemblyGenInstrInfo.inc"
35e6d15924SDimitry Andric 
WebAssemblyInstrInfo(const WebAssemblySubtarget & STI)361a82d4c0SDimitry Andric WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)
37dd58ef01SDimitry Andric     : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN,
38eb11fae6SDimitry Andric                               WebAssembly::ADJCALLSTACKUP,
39eb11fae6SDimitry Andric                               WebAssembly::CATCHRET),
40dd58ef01SDimitry Andric       RI(STI.getTargetTriple()) {}
41dd58ef01SDimitry Andric 
isReallyTriviallyReMaterializable(const MachineInstr & MI) const4201095a5dSDimitry Andric bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable(
434b4fe385SDimitry Andric     const MachineInstr &MI) const {
4401095a5dSDimitry Andric   switch (MI.getOpcode()) {
4501095a5dSDimitry Andric   case WebAssembly::CONST_I32:
4601095a5dSDimitry Andric   case WebAssembly::CONST_I64:
4701095a5dSDimitry Andric   case WebAssembly::CONST_F32:
4801095a5dSDimitry Andric   case WebAssembly::CONST_F64:
49b1c73532SDimitry Andric     // TargetInstrInfo::isReallyTriviallyReMaterializable misses these
50b1c73532SDimitry Andric     // because of the ARGUMENTS implicit def, so we manualy override it here.
5101095a5dSDimitry Andric     return true;
5201095a5dSDimitry Andric   default:
53b1c73532SDimitry Andric     return TargetInstrInfo::isReallyTriviallyReMaterializable(MI);
5401095a5dSDimitry Andric   }
5501095a5dSDimitry Andric }
5601095a5dSDimitry Andric 
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const57dd58ef01SDimitry Andric void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
58dd58ef01SDimitry Andric                                        MachineBasicBlock::iterator I,
59706b4fc4SDimitry Andric                                        const DebugLoc &DL, MCRegister DestReg,
60706b4fc4SDimitry Andric                                        MCRegister SrcReg, bool KillSrc) const {
61dd58ef01SDimitry Andric   // This method is called by post-RA expansion, which expects only pregs to
62dd58ef01SDimitry Andric   // exist. However we need to handle both here.
63dd58ef01SDimitry Andric   auto &MRI = MBB.getParent()->getRegInfo();
6401095a5dSDimitry Andric   const TargetRegisterClass *RC =
651d5ae102SDimitry Andric       Register::isVirtualRegister(DestReg)
6601095a5dSDimitry Andric           ? MRI.getRegClass(DestReg)
6701095a5dSDimitry Andric           : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);
68dd58ef01SDimitry Andric 
691f917f69SDimitry Andric   unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC);
70dd58ef01SDimitry Andric 
71b915e9e0SDimitry Andric   BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)
72dd58ef01SDimitry Andric       .addReg(SrcReg, KillSrc ? RegState::Kill : 0);
73dd58ef01SDimitry Andric }
74dd58ef01SDimitry Andric 
commuteInstructionImpl(MachineInstr & MI,bool NewMI,unsigned OpIdx1,unsigned OpIdx2) const75d8e91e46SDimitry Andric MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl(
76d8e91e46SDimitry Andric     MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const {
7701095a5dSDimitry Andric   // If the operands are stackified, we can't reorder them.
7801095a5dSDimitry Andric   WebAssemblyFunctionInfo &MFI =
7901095a5dSDimitry Andric       *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
8001095a5dSDimitry Andric   if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) ||
8101095a5dSDimitry Andric       MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg()))
8201095a5dSDimitry Andric     return nullptr;
8301095a5dSDimitry Andric 
8401095a5dSDimitry Andric   // Otherwise use the default implementation.
8501095a5dSDimitry Andric   return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
8601095a5dSDimitry Andric }
8701095a5dSDimitry Andric 
88dd58ef01SDimitry Andric // Branch analysis.
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool) const8901095a5dSDimitry Andric bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
90dd58ef01SDimitry Andric                                          MachineBasicBlock *&TBB,
91dd58ef01SDimitry Andric                                          MachineBasicBlock *&FBB,
92dd58ef01SDimitry Andric                                          SmallVectorImpl<MachineOperand> &Cond,
93dd58ef01SDimitry Andric                                          bool /*AllowModify*/) const {
94e6d15924SDimitry Andric   const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>();
95e6d15924SDimitry Andric   // WebAssembly has control flow that doesn't have explicit branches or direct
96e6d15924SDimitry Andric   // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It
97e6d15924SDimitry Andric   // is created after CFGStackify.
98e6d15924SDimitry Andric   if (MFI.isCFGStackified())
99e6d15924SDimitry Andric     return true;
100e6d15924SDimitry Andric 
101dd58ef01SDimitry Andric   bool HaveCond = false;
102dd58ef01SDimitry Andric   for (MachineInstr &MI : MBB.terminators()) {
103dd58ef01SDimitry Andric     switch (MI.getOpcode()) {
104dd58ef01SDimitry Andric     default:
105dd58ef01SDimitry Andric       // Unhandled instruction; bail out.
106dd58ef01SDimitry Andric       return true;
107dd58ef01SDimitry Andric     case WebAssembly::BR_IF:
108dd58ef01SDimitry Andric       if (HaveCond)
109dd58ef01SDimitry Andric         return true;
110dd58ef01SDimitry Andric       Cond.push_back(MachineOperand::CreateImm(true));
11101095a5dSDimitry Andric       Cond.push_back(MI.getOperand(1));
11201095a5dSDimitry Andric       TBB = MI.getOperand(0).getMBB();
113dd58ef01SDimitry Andric       HaveCond = true;
114dd58ef01SDimitry Andric       break;
115dd58ef01SDimitry Andric     case WebAssembly::BR_UNLESS:
116dd58ef01SDimitry Andric       if (HaveCond)
117dd58ef01SDimitry Andric         return true;
118dd58ef01SDimitry Andric       Cond.push_back(MachineOperand::CreateImm(false));
11901095a5dSDimitry Andric       Cond.push_back(MI.getOperand(1));
12001095a5dSDimitry Andric       TBB = MI.getOperand(0).getMBB();
121dd58ef01SDimitry Andric       HaveCond = true;
122dd58ef01SDimitry Andric       break;
123dd58ef01SDimitry Andric     case WebAssembly::BR:
124dd58ef01SDimitry Andric       if (!HaveCond)
125dd58ef01SDimitry Andric         TBB = MI.getOperand(0).getMBB();
126dd58ef01SDimitry Andric       else
127dd58ef01SDimitry Andric         FBB = MI.getOperand(0).getMBB();
128dd58ef01SDimitry Andric       break;
129dd58ef01SDimitry Andric     }
130dd58ef01SDimitry Andric     if (MI.isBarrier())
131dd58ef01SDimitry Andric       break;
132dd58ef01SDimitry Andric   }
133dd58ef01SDimitry Andric 
134dd58ef01SDimitry Andric   return false;
135dd58ef01SDimitry Andric }
136dd58ef01SDimitry Andric 
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const137b915e9e0SDimitry Andric unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,
138b915e9e0SDimitry Andric                                             int *BytesRemoved) const {
139b915e9e0SDimitry Andric   assert(!BytesRemoved && "code size not handled");
140b915e9e0SDimitry Andric 
141dd58ef01SDimitry Andric   MachineBasicBlock::instr_iterator I = MBB.instr_end();
142dd58ef01SDimitry Andric   unsigned Count = 0;
143dd58ef01SDimitry Andric 
144dd58ef01SDimitry Andric   while (I != MBB.instr_begin()) {
145dd58ef01SDimitry Andric     --I;
146eb11fae6SDimitry Andric     if (I->isDebugInstr())
147dd58ef01SDimitry Andric       continue;
148dd58ef01SDimitry Andric     if (!I->isTerminator())
149dd58ef01SDimitry Andric       break;
150dd58ef01SDimitry Andric     // Remove the branch.
151dd58ef01SDimitry Andric     I->eraseFromParent();
152dd58ef01SDimitry Andric     I = MBB.instr_end();
153dd58ef01SDimitry Andric     ++Count;
154dd58ef01SDimitry Andric   }
155dd58ef01SDimitry Andric 
156dd58ef01SDimitry Andric   return Count;
157dd58ef01SDimitry Andric }
158dd58ef01SDimitry Andric 
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const159d8e91e46SDimitry Andric unsigned WebAssemblyInstrInfo::insertBranch(
160d8e91e46SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
161d8e91e46SDimitry Andric     ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
162b915e9e0SDimitry Andric   assert(!BytesAdded && "code size not handled");
163b915e9e0SDimitry Andric 
164dd58ef01SDimitry Andric   if (Cond.empty()) {
165dd58ef01SDimitry Andric     if (!TBB)
166dd58ef01SDimitry Andric       return 0;
167dd58ef01SDimitry Andric 
168dd58ef01SDimitry Andric     BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB);
169dd58ef01SDimitry Andric     return 1;
170dd58ef01SDimitry Andric   }
171dd58ef01SDimitry Andric 
172dd58ef01SDimitry Andric   assert(Cond.size() == 2 && "Expected a flag and a successor block");
173dd58ef01SDimitry Andric 
174b60736ecSDimitry Andric   if (Cond[0].getImm())
17571d5a254SDimitry Andric     BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
176b60736ecSDimitry Andric   else
17771d5a254SDimitry Andric     BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);
178dd58ef01SDimitry Andric   if (!FBB)
179dd58ef01SDimitry Andric     return 1;
180dd58ef01SDimitry Andric 
181dd58ef01SDimitry Andric   BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB);
182dd58ef01SDimitry Andric   return 2;
183dd58ef01SDimitry Andric }
184dd58ef01SDimitry Andric 
reverseBranchCondition(SmallVectorImpl<MachineOperand> & Cond) const185b915e9e0SDimitry Andric bool WebAssemblyInstrInfo::reverseBranchCondition(
186dd58ef01SDimitry Andric     SmallVectorImpl<MachineOperand> &Cond) const {
187e6d15924SDimitry Andric   assert(Cond.size() == 2 && "Expected a flag and a condition expression");
188dd58ef01SDimitry Andric   Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
189dd58ef01SDimitry Andric   return false;
190dd58ef01SDimitry Andric }
191706b4fc4SDimitry Andric 
192706b4fc4SDimitry Andric ArrayRef<std::pair<int, const char *>>
getSerializableTargetIndices() const193706b4fc4SDimitry Andric WebAssemblyInstrInfo::getSerializableTargetIndices() const {
194706b4fc4SDimitry Andric   static const std::pair<int, const char *> TargetIndices[] = {
195cfca06d7SDimitry Andric       {WebAssembly::TI_LOCAL, "wasm-local"},
196cfca06d7SDimitry Andric       {WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"},
197cfca06d7SDimitry Andric       {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"},
198344a3780SDimitry Andric       {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"},
199344a3780SDimitry Andric       {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}};
200e3b55780SDimitry Andric   return ArrayRef(TargetIndices);
201706b4fc4SDimitry Andric }
202344a3780SDimitry Andric 
203344a3780SDimitry Andric const MachineOperand &
getCalleeOperand(const MachineInstr & MI) const204344a3780SDimitry Andric WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const {
205344a3780SDimitry Andric   return WebAssembly::getCalleeOp(MI);
206344a3780SDimitry Andric }
207e3b55780SDimitry Andric 
208e3b55780SDimitry Andric // This returns true when the instruction defines a value of a TargetIndex
209e3b55780SDimitry Andric // operand that can be tracked by offsets. For Wasm, this returns true for only
210e3b55780SDimitry Andric // local.set/local.tees. This is currently used by LiveDebugValues analysis.
211e3b55780SDimitry Andric //
212e3b55780SDimitry Andric // These are not included:
213e3b55780SDimitry Andric // - In theory we need to add global.set here too, but we don't have global
214e3b55780SDimitry Andric //   indices at this point because they are relocatable and we address them by
215e3b55780SDimitry Andric //   names until linking, so we don't have 'offsets' (which are used to store
216e3b55780SDimitry Andric //   local/global indices) to deal with in LiveDebugValues. And we don't
217e3b55780SDimitry Andric //   associate debug info in values in globals anyway.
218e3b55780SDimitry Andric // - All other value-producing instructions, i.e. instructions with defs, can
219e3b55780SDimitry Andric //   define values in the Wasm stack, which is represented by TI_OPERAND_STACK
220e3b55780SDimitry Andric //   TargetIndex. But they don't have offset info within the instruction itself,
221e3b55780SDimitry Andric //   and debug info analysis for them is handled separately in
222e3b55780SDimitry Andric //   WebAssemblyDebugFixup pass, so we don't worry about them here.
isExplicitTargetIndexDef(const MachineInstr & MI,int & Index,int64_t & Offset) const223e3b55780SDimitry Andric bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI,
224e3b55780SDimitry Andric                                                     int &Index,
225e3b55780SDimitry Andric                                                     int64_t &Offset) const {
226e3b55780SDimitry Andric   unsigned Opc = MI.getOpcode();
227e3b55780SDimitry Andric   if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) {
228e3b55780SDimitry Andric     Index = WebAssembly::TI_LOCAL;
229e3b55780SDimitry Andric     Offset = MI.explicit_uses().begin()->getImm();
230e3b55780SDimitry Andric     return true;
231e3b55780SDimitry Andric   }
232e3b55780SDimitry Andric   return false;
233e3b55780SDimitry Andric }
234