1 //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file contains the WebAssembly implementation of the
11 /// TargetInstrInfo class.
13 //===----------------------------------------------------------------------===//
15 #include "WebAssemblyInstrInfo.h"
16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17 #include "Utils/WebAssemblyUtilities.h"
18 #include "WebAssembly.h"
19 #include "WebAssemblyMachineFunctionInfo.h"
20 #include "WebAssemblySubtarget.h"
21 #include "llvm/CodeGen/MachineFrameInfo.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/CodeGen/MachineMemOperand.h"
24 #include "llvm/CodeGen/MachineRegisterInfo.h"
27 #define DEBUG_TYPE "wasm-instr-info"
29 #define GET_INSTRINFO_CTOR_DTOR
30 #include "WebAssemblyGenInstrInfo.inc"
32 // defines WebAssembly::getNamedOperandIdx
33 #define GET_INSTRINFO_NAMED_OPS
34 #include "WebAssemblyGenInstrInfo.inc"
36 WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget
&STI
)
37 : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN
,
38 WebAssembly::ADJCALLSTACKUP
,
39 WebAssembly::CATCHRET
),
40 RI(STI
.getTargetTriple()) {}
42 bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable(
43 const MachineInstr
&MI
, AAResults
*AA
) const {
44 switch (MI
.getOpcode()) {
45 case WebAssembly::CONST_I32
:
46 case WebAssembly::CONST_I64
:
47 case WebAssembly::CONST_F32
:
48 case WebAssembly::CONST_F64
:
49 // isReallyTriviallyReMaterializableGeneric misses these because of the
50 // ARGUMENTS implicit def, so we manualy override it here.
57 void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock
&MBB
,
58 MachineBasicBlock::iterator I
,
59 const DebugLoc
&DL
, MCRegister DestReg
,
60 MCRegister SrcReg
, bool KillSrc
) const {
61 // This method is called by post-RA expansion, which expects only pregs to
62 // exist. However we need to handle both here.
63 auto &MRI
= MBB
.getParent()->getRegInfo();
64 const TargetRegisterClass
*RC
=
65 Register::isVirtualRegister(DestReg
)
66 ? MRI
.getRegClass(DestReg
)
67 : MRI
.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg
);
70 if (RC
== &WebAssembly::I32RegClass
)
71 CopyOpcode
= WebAssembly::COPY_I32
;
72 else if (RC
== &WebAssembly::I64RegClass
)
73 CopyOpcode
= WebAssembly::COPY_I64
;
74 else if (RC
== &WebAssembly::F32RegClass
)
75 CopyOpcode
= WebAssembly::COPY_F32
;
76 else if (RC
== &WebAssembly::F64RegClass
)
77 CopyOpcode
= WebAssembly::COPY_F64
;
78 else if (RC
== &WebAssembly::V128RegClass
)
79 CopyOpcode
= WebAssembly::COPY_V128
;
80 else if (RC
== &WebAssembly::FUNCREFRegClass
)
81 CopyOpcode
= WebAssembly::COPY_FUNCREF
;
82 else if (RC
== &WebAssembly::EXTERNREFRegClass
)
83 CopyOpcode
= WebAssembly::COPY_EXTERNREF
;
85 llvm_unreachable("Unexpected register class");
87 BuildMI(MBB
, I
, DL
, get(CopyOpcode
), DestReg
)
88 .addReg(SrcReg
, KillSrc
? RegState::Kill
: 0);
91 MachineInstr
*WebAssemblyInstrInfo::commuteInstructionImpl(
92 MachineInstr
&MI
, bool NewMI
, unsigned OpIdx1
, unsigned OpIdx2
) const {
93 // If the operands are stackified, we can't reorder them.
94 WebAssemblyFunctionInfo
&MFI
=
95 *MI
.getParent()->getParent()->getInfo
<WebAssemblyFunctionInfo
>();
96 if (MFI
.isVRegStackified(MI
.getOperand(OpIdx1
).getReg()) ||
97 MFI
.isVRegStackified(MI
.getOperand(OpIdx2
).getReg()))
100 // Otherwise use the default implementation.
101 return TargetInstrInfo::commuteInstructionImpl(MI
, NewMI
, OpIdx1
, OpIdx2
);
105 bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock
&MBB
,
106 MachineBasicBlock
*&TBB
,
107 MachineBasicBlock
*&FBB
,
108 SmallVectorImpl
<MachineOperand
> &Cond
,
109 bool /*AllowModify*/) const {
110 const auto &MFI
= *MBB
.getParent()->getInfo
<WebAssemblyFunctionInfo
>();
111 // WebAssembly has control flow that doesn't have explicit branches or direct
112 // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It
113 // is created after CFGStackify.
114 if (MFI
.isCFGStackified())
117 bool HaveCond
= false;
118 for (MachineInstr
&MI
: MBB
.terminators()) {
119 switch (MI
.getOpcode()) {
121 // Unhandled instruction; bail out.
123 case WebAssembly::BR_IF
:
126 Cond
.push_back(MachineOperand::CreateImm(true));
127 Cond
.push_back(MI
.getOperand(1));
128 TBB
= MI
.getOperand(0).getMBB();
131 case WebAssembly::BR_UNLESS
:
134 Cond
.push_back(MachineOperand::CreateImm(false));
135 Cond
.push_back(MI
.getOperand(1));
136 TBB
= MI
.getOperand(0).getMBB();
139 case WebAssembly::BR
:
141 TBB
= MI
.getOperand(0).getMBB();
143 FBB
= MI
.getOperand(0).getMBB();
153 unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock
&MBB
,
154 int *BytesRemoved
) const {
155 assert(!BytesRemoved
&& "code size not handled");
157 MachineBasicBlock::instr_iterator I
= MBB
.instr_end();
160 while (I
!= MBB
.instr_begin()) {
162 if (I
->isDebugInstr())
164 if (!I
->isTerminator())
166 // Remove the branch.
167 I
->eraseFromParent();
175 unsigned WebAssemblyInstrInfo::insertBranch(
176 MachineBasicBlock
&MBB
, MachineBasicBlock
*TBB
, MachineBasicBlock
*FBB
,
177 ArrayRef
<MachineOperand
> Cond
, const DebugLoc
&DL
, int *BytesAdded
) const {
178 assert(!BytesAdded
&& "code size not handled");
184 BuildMI(&MBB
, DL
, get(WebAssembly::BR
)).addMBB(TBB
);
188 assert(Cond
.size() == 2 && "Expected a flag and a successor block");
190 if (Cond
[0].getImm())
191 BuildMI(&MBB
, DL
, get(WebAssembly::BR_IF
)).addMBB(TBB
).add(Cond
[1]);
193 BuildMI(&MBB
, DL
, get(WebAssembly::BR_UNLESS
)).addMBB(TBB
).add(Cond
[1]);
197 BuildMI(&MBB
, DL
, get(WebAssembly::BR
)).addMBB(FBB
);
201 bool WebAssemblyInstrInfo::reverseBranchCondition(
202 SmallVectorImpl
<MachineOperand
> &Cond
) const {
203 assert(Cond
.size() == 2 && "Expected a flag and a condition expression");
204 Cond
.front() = MachineOperand::CreateImm(!Cond
.front().getImm());
208 ArrayRef
<std::pair
<int, const char *>>
209 WebAssemblyInstrInfo::getSerializableTargetIndices() const {
210 static const std::pair
<int, const char *> TargetIndices
[] = {
211 {WebAssembly::TI_LOCAL
, "wasm-local"},
212 {WebAssembly::TI_GLOBAL_FIXED
, "wasm-global-fixed"},
213 {WebAssembly::TI_OPERAND_STACK
, "wasm-operand-stack"},
214 {WebAssembly::TI_GLOBAL_RELOC
, "wasm-global-reloc"},
215 {WebAssembly::TI_LOCAL_INDIRECT
, "wasm-local-indirect"}};
216 return makeArrayRef(TargetIndices
);
219 const MachineOperand
&
220 WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr
&MI
) const {
221 return WebAssembly::getCalleeOp(MI
);