110e730a2SDan Gohman //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//
210e730a2SDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610e730a2SDan Gohman //
710e730a2SDan Gohman //===----------------------------------------------------------------------===//
810e730a2SDan Gohman ///
910e730a2SDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file contains the WebAssembly implementation of the
1110e730a2SDan Gohman /// TargetInstrInfo class.
1210e730a2SDan Gohman ///
1310e730a2SDan Gohman //===----------------------------------------------------------------------===//
1410e730a2SDan Gohman 
1510e730a2SDan Gohman #include "WebAssemblyInstrInfo.h"
1610e730a2SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
175dd86aadSHeejin Ahn #include "Utils/WebAssemblyUtilities.h"
18adf7a0a5SYury Delendik #include "WebAssembly.h"
19adf28177SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
2010e730a2SDan Gohman #include "WebAssemblySubtarget.h"
2110e730a2SDan Gohman #include "llvm/CodeGen/MachineFrameInfo.h"
2210e730a2SDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h"
2310e730a2SDan Gohman #include "llvm/CodeGen/MachineMemOperand.h"
2410e730a2SDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
2510e730a2SDan Gohman using namespace llvm;
2610e730a2SDan Gohman 
2710e730a2SDan Gohman #define DEBUG_TYPE "wasm-instr-info"
2810e730a2SDan Gohman 
29b9073fb2SJF Bastien #define GET_INSTRINFO_CTOR_DTOR
30b9073fb2SJF Bastien #include "WebAssemblyGenInstrInfo.inc"
31b9073fb2SJF Bastien 
32972d7d51SThomas Lively // defines WebAssembly::getNamedOperandIdx
33972d7d51SThomas Lively #define GET_INSTRINFO_NAMED_OPS
34972d7d51SThomas Lively #include "WebAssemblyGenInstrInfo.inc"
35972d7d51SThomas Lively 
WebAssemblyInstrInfo(const WebAssemblySubtarget & STI)3610e730a2SDan Gohman WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)
3735bfb24cSDan Gohman     : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN,
385ef4d5f9SHeejin Ahn                               WebAssembly::ADJCALLSTACKUP,
395ef4d5f9SHeejin Ahn                               WebAssembly::CATCHRET),
4035bfb24cSDan Gohman       RI(STI.getTargetTriple()) {}
414f52e00eSDan Gohman 
isReallyTriviallyReMaterializable(const MachineInstr & MI) const42b6fd39a3SDan Gohman bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable(
43*8d0383ebSMatt Arsenault     const MachineInstr &MI) const {
449cfc75c2SDuncan P. N. Exon Smith   switch (MI.getOpcode()) {
45b6fd39a3SDan Gohman   case WebAssembly::CONST_I32:
46b6fd39a3SDan Gohman   case WebAssembly::CONST_I64:
47b6fd39a3SDan Gohman   case WebAssembly::CONST_F32:
48b6fd39a3SDan Gohman   case WebAssembly::CONST_F64:
49b6fd39a3SDan Gohman     // isReallyTriviallyReMaterializableGeneric misses these because of the
50b6fd39a3SDan Gohman     // ARGUMENTS implicit def, so we manualy override it here.
51b6fd39a3SDan Gohman     return true;
52b6fd39a3SDan Gohman   default:
53b6fd39a3SDan Gohman     return false;
54b6fd39a3SDan Gohman   }
55b6fd39a3SDan Gohman }
56b6fd39a3SDan Gohman 
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const574f52e00eSDan Gohman void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
584f52e00eSDan Gohman                                        MachineBasicBlock::iterator I,
59e6c9a9afSMatt Arsenault                                        const DebugLoc &DL, MCRegister DestReg,
60e6c9a9afSMatt Arsenault                                        MCRegister SrcReg, bool KillSrc) const {
618bb5f292SDerek Schuff   // This method is called by post-RA expansion, which expects only pregs to
628bb5f292SDerek Schuff   // exist. However we need to handle both here.
638bb5f292SDerek Schuff   auto &MRI = MBB.getParent()->getRegInfo();
64b6fd39a3SDan Gohman   const TargetRegisterClass *RC =
652bea69bfSDaniel Sanders       Register::isVirtualRegister(DestReg)
66b6fd39a3SDan Gohman           ? MRI.getRegClass(DestReg)
676ea637afSDerek Schuff           : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);
684ba4816bSDan Gohman 
69beec3e8cSAlex Bradbury   unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC);
704ba4816bSDan Gohman 
714fc4e42dSDan Gohman   BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)
724f52e00eSDan Gohman       .addReg(SrcReg, KillSrc ? RegState::Kill : 0);
734f52e00eSDan Gohman }
74950a13cfSDan Gohman 
commuteInstructionImpl(MachineInstr & MI,bool NewMI,unsigned OpIdx1,unsigned OpIdx2) const75f208f631SHeejin Ahn MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl(
76f208f631SHeejin Ahn     MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const {
77adf28177SDan Gohman   // If the operands are stackified, we can't reorder them.
78adf28177SDan Gohman   WebAssemblyFunctionInfo &MFI =
799cfc75c2SDuncan P. N. Exon Smith       *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
809cfc75c2SDuncan P. N. Exon Smith   if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) ||
819cfc75c2SDuncan P. N. Exon Smith       MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg()))
82adf28177SDan Gohman     return nullptr;
83adf28177SDan Gohman 
84adf28177SDan Gohman   // Otherwise use the default implementation.
85adf28177SDan Gohman   return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
86adf28177SDan Gohman }
87adf28177SDan Gohman 
88950a13cfSDan Gohman // Branch analysis.
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool) const8971c30a14SJacques Pienaar bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
90950a13cfSDan Gohman                                          MachineBasicBlock *&TBB,
91950a13cfSDan Gohman                                          MachineBasicBlock *&FBB,
92950a13cfSDan Gohman                                          SmallVectorImpl<MachineOperand> &Cond,
937a6b9825SDan Gohman                                          bool /*AllowModify*/) const {
9454551c1dSHeejin Ahn   const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>();
9554551c1dSHeejin Ahn   // WebAssembly has control flow that doesn't have explicit branches or direct
9654551c1dSHeejin Ahn   // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It
9754551c1dSHeejin Ahn   // is created after CFGStackify.
9854551c1dSHeejin Ahn   if (MFI.isCFGStackified())
9954551c1dSHeejin Ahn     return true;
10054551c1dSHeejin Ahn 
101950a13cfSDan Gohman   bool HaveCond = false;
102d544e0c1SDan Gohman   for (MachineInstr &MI : MBB.terminators()) {
103950a13cfSDan Gohman     switch (MI.getOpcode()) {
104950a13cfSDan Gohman     default:
105950a13cfSDan Gohman       // Unhandled instruction; bail out.
106950a13cfSDan Gohman       return true;
107231244c3SDan Gohman     case WebAssembly::BR_IF:
108950a13cfSDan Gohman       if (HaveCond)
109950a13cfSDan Gohman         return true;
110f0b165a7SDan Gohman       Cond.push_back(MachineOperand::CreateImm(true));
11106b49582SDan Gohman       Cond.push_back(MI.getOperand(1));
11206b49582SDan Gohman       TBB = MI.getOperand(0).getMBB();
113f0b165a7SDan Gohman       HaveCond = true;
114f0b165a7SDan Gohman       break;
115f0b165a7SDan Gohman     case WebAssembly::BR_UNLESS:
116f0b165a7SDan Gohman       if (HaveCond)
117f0b165a7SDan Gohman         return true;
118f0b165a7SDan Gohman       Cond.push_back(MachineOperand::CreateImm(false));
11906b49582SDan Gohman       Cond.push_back(MI.getOperand(1));
12006b49582SDan Gohman       TBB = MI.getOperand(0).getMBB();
121950a13cfSDan Gohman       HaveCond = true;
122950a13cfSDan Gohman       break;
123950a13cfSDan Gohman     case WebAssembly::BR:
124950a13cfSDan Gohman       if (!HaveCond)
125950a13cfSDan Gohman         TBB = MI.getOperand(0).getMBB();
126950a13cfSDan Gohman       else
127950a13cfSDan Gohman         FBB = MI.getOperand(0).getMBB();
128950a13cfSDan Gohman       break;
129950a13cfSDan Gohman     }
130950a13cfSDan Gohman     if (MI.isBarrier())
131950a13cfSDan Gohman       break;
132950a13cfSDan Gohman   }
133950a13cfSDan Gohman 
134950a13cfSDan Gohman   return false;
135950a13cfSDan Gohman }
136950a13cfSDan Gohman 
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const1371b9fc8edSMatt Arsenault unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,
138a2b036e8SMatt Arsenault                                             int *BytesRemoved) const {
139a2b036e8SMatt Arsenault   assert(!BytesRemoved && "code size not handled");
140a2b036e8SMatt Arsenault 
141950a13cfSDan Gohman   MachineBasicBlock::instr_iterator I = MBB.instr_end();
142950a13cfSDan Gohman   unsigned Count = 0;
143950a13cfSDan Gohman 
144950a13cfSDan Gohman   while (I != MBB.instr_begin()) {
145950a13cfSDan Gohman     --I;
146801bf7ebSShiva Chen     if (I->isDebugInstr())
147950a13cfSDan Gohman       continue;
148950a13cfSDan Gohman     if (!I->isTerminator())
149950a13cfSDan Gohman       break;
150950a13cfSDan Gohman     // Remove the branch.
151950a13cfSDan Gohman     I->eraseFromParent();
152950a13cfSDan Gohman     I = MBB.instr_end();
153950a13cfSDan Gohman     ++Count;
154950a13cfSDan Gohman   }
155950a13cfSDan Gohman 
156950a13cfSDan Gohman   return Count;
157950a13cfSDan Gohman }
158950a13cfSDan Gohman 
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const159f208f631SHeejin Ahn unsigned WebAssemblyInstrInfo::insertBranch(
160f208f631SHeejin Ahn     MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
161f208f631SHeejin Ahn     ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
162a2b036e8SMatt Arsenault   assert(!BytesAdded && "code size not handled");
163a2b036e8SMatt Arsenault 
164950a13cfSDan Gohman   if (Cond.empty()) {
165950a13cfSDan Gohman     if (!TBB)
166950a13cfSDan Gohman       return 0;
167950a13cfSDan Gohman 
168950a13cfSDan Gohman     BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB);
169950a13cfSDan Gohman     return 1;
170950a13cfSDan Gohman   }
171950a13cfSDan Gohman 
172f0b165a7SDan Gohman   assert(Cond.size() == 2 && "Expected a flag and a successor block");
173f0b165a7SDan Gohman 
17452e240a0SHeejin Ahn   if (Cond[0].getImm())
175116bbab4SDiana Picus     BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
17652e240a0SHeejin Ahn   else
177116bbab4SDiana Picus     BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);
178950a13cfSDan Gohman   if (!FBB)
179950a13cfSDan Gohman     return 1;
180950a13cfSDan Gohman 
181950a13cfSDan Gohman   BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB);
182950a13cfSDan Gohman   return 2;
183950a13cfSDan Gohman }
184950a13cfSDan Gohman 
reverseBranchCondition(SmallVectorImpl<MachineOperand> & Cond) const1851b9fc8edSMatt Arsenault bool WebAssemblyInstrInfo::reverseBranchCondition(
186950a13cfSDan Gohman     SmallVectorImpl<MachineOperand> &Cond) const {
187d6f48786SHeejin Ahn   assert(Cond.size() == 2 && "Expected a flag and a condition expression");
188f0b165a7SDan Gohman   Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
189f0b165a7SDan Gohman   return false;
190950a13cfSDan Gohman }
191adf7a0a5SYury Delendik 
192adf7a0a5SYury Delendik ArrayRef<std::pair<int, const char *>>
getSerializableTargetIndices() const193adf7a0a5SYury Delendik WebAssemblyInstrInfo::getSerializableTargetIndices() const {
194adf7a0a5SYury Delendik   static const std::pair<int, const char *> TargetIndices[] = {
19548139ebcSWouter van Oortmerssen       {WebAssembly::TI_LOCAL, "wasm-local"},
19648139ebcSWouter van Oortmerssen       {WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"},
19748139ebcSWouter van Oortmerssen       {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"},
198e3c0b0feSWouter van Oortmerssen       {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"},
199e3c0b0feSWouter van Oortmerssen       {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}};
200adf7a0a5SYury Delendik   return makeArrayRef(TargetIndices);
201adf7a0a5SYury Delendik }
2025dd86aadSHeejin Ahn 
2035dd86aadSHeejin Ahn const MachineOperand &
getCalleeOperand(const MachineInstr & MI) const2045dd86aadSHeejin Ahn WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const {
2055dd86aadSHeejin Ahn   return WebAssembly::getCalleeOp(MI);
2065dd86aadSHeejin Ahn }
207