1//===- WebAssemblyInstructionSelector.cpp ------------------------*- C++ -*-==//
2//
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
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file implements the targeting of the InstructionSelector class for
10/// WebAssembly.
11/// \todo This should be generated by TableGen.
12//===----------------------------------------------------------------------===//
13
14#include "GISel/WebAssemblyRegisterBankInfo.h"
15#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16#include "Utils/WasmAddressSpaces.h"
17#include "Utils/WebAssemblyTypeUtilities.h"
18#include "WebAssemblyRegisterInfo.h"
19#include "WebAssemblySubtarget.h"
20#include "WebAssemblyTargetMachine.h"
21#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
22#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
23#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
24#include "llvm/CodeGen/GlobalISel/Utils.h"
25#include "llvm/CodeGen/MachineOperand.h"
26#include "llvm/CodeGen/TargetLowering.h"
27#include "llvm/IR/IntrinsicsWebAssembly.h"
28
29#define DEBUG_TYPE "wasm-isel"
30
31using namespace llvm;
32
33namespace {
34
35#define GET_GLOBALISEL_PREDICATE_BITSET
36#include "WebAssemblyGenGlobalISel.inc"
37#undef GET_GLOBALISEL_PREDICATE_BITSET
38
39class WebAssemblyInstructionSelector : public InstructionSelector {
40public:
41 WebAssemblyInstructionSelector(const WebAssemblyTargetMachine &TM,
42 const WebAssemblySubtarget &STI,
43 const WebAssemblyRegisterBankInfo &RBI);
44
45 bool select(MachineInstr &I) override;
46
47 InstructionSelector::ComplexRendererFns
48 selectAddrOperands32(MachineOperand &Root) const;
49 InstructionSelector::ComplexRendererFns
50 selectAddrOperands64(MachineOperand &Root) const;
51
52 static const char *getName() { return DEBUG_TYPE; }
53
54private:
55 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
56 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
57
58 InstructionSelector::ComplexRendererFns
59 selectAddrOperands(LLT AddrType, unsigned int ConstOpc,
60 MachineOperand &Root) const;
61
62 const WebAssemblyTargetMachine &TM;
63 const WebAssemblySubtarget &STI;
64 const WebAssemblyInstrInfo &TII;
65 const WebAssemblyRegisterInfo &TRI;
66 const WebAssemblyRegisterBankInfo &RBI;
67
68#define GET_GLOBALISEL_PREDICATES_DECL
69#include "WebAssemblyGenGlobalISel.inc"
70#undef GET_GLOBALISEL_PREDICATES_DECL
71
72#define GET_GLOBALISEL_TEMPORARIES_DECL
73#include "WebAssemblyGenGlobalISel.inc"
74#undef GET_GLOBALISEL_TEMPORARIES_DECL
75};
76
77} // end anonymous namespace
78
79#define GET_GLOBALISEL_IMPL
80#include "WebAssemblyGenGlobalISel.inc"
81#undef GET_GLOBALISEL_IMPL
82
83WebAssemblyInstructionSelector::WebAssemblyInstructionSelector(
84 const WebAssemblyTargetMachine &TM, const WebAssemblySubtarget &STI,
85 const WebAssemblyRegisterBankInfo &RBI)
86 : TM(TM), STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()),
87 RBI(RBI),
88
89#define GET_GLOBALISEL_PREDICATES_INIT
90#include "WebAssemblyGenGlobalISel.inc"
91#undef GET_GLOBALISEL_PREDICATES_INIT
92#define GET_GLOBALISEL_TEMPORARIES_INIT
93#include "WebAssemblyGenGlobalISel.inc"
94#undef GET_GLOBALISEL_TEMPORARIES_INIT
95{
96}
97
98InstructionSelector::ComplexRendererFns
99WebAssemblyInstructionSelector::selectAddrOperands(LLT AddrType,
100 unsigned int ConstOpc,
101 MachineOperand &Root) const {
102 return {{
103 [=](MachineInstrBuilder &MIB) { MIB.addImm(Val: 0); },
104 [=](MachineInstrBuilder &MIB) { MIB.addReg(RegNo: Root.getReg()); },
105 }};
106}
107
108InstructionSelector::ComplexRendererFns
109WebAssemblyInstructionSelector::selectAddrOperands32(
110 MachineOperand &Root) const {
111 return selectAddrOperands(AddrType: LLT::integer(SizeInBits: 32), ConstOpc: WebAssembly::CONST_I32, Root);
112}
113
114InstructionSelector::ComplexRendererFns
115WebAssemblyInstructionSelector::selectAddrOperands64(
116 MachineOperand &Root) const {
117 return selectAddrOperands(AddrType: LLT::integer(SizeInBits: 64), ConstOpc: WebAssembly::CONST_I64, Root);
118}
119
120bool WebAssemblyInstructionSelector::selectCopy(
121 MachineInstr &I, MachineRegisterInfo &MRI) const {
122 Register DstReg = I.getOperand(i: 0).getReg();
123 Register SrcReg = I.getOperand(i: 1).getReg();
124
125 const TargetRegisterClass *DstRC =
126 TRI.getConstrainedRegClassForReg(Reg: DstReg, MRI);
127 if (!DstRC)
128 return false;
129
130 const TargetRegisterClass *SrcRC =
131 TRI.getConstrainedRegClassForReg(Reg: SrcReg, MRI);
132 if (!SrcRC)
133 return false;
134
135 if (DstReg.isVirtual())
136 RBI.constrainGenericRegister(Reg: DstReg, RC: *DstRC, MRI);
137 if (SrcReg.isVirtual())
138 RBI.constrainGenericRegister(Reg: SrcReg, RC: *SrcRC, MRI);
139
140 if (DstRC != SrcRC) {
141 if (DstReg.isPhysical() || SrcReg.isPhysical())
142 llvm_unreachable("COPY to/from SP[32/64] or FP[32/64] with mismatching "
143 "classes not currently supported");
144
145 if (DstRC == &WebAssembly::I32RegClass &&
146 SrcRC == &WebAssembly::F32RegClass) {
147 I.setDesc(TII.get(Opcode: WebAssembly::I32_REINTERPRET_F32));
148 return true;
149 }
150 if (DstRC == &WebAssembly::F32RegClass &&
151 SrcRC == &WebAssembly::I32RegClass) {
152 I.setDesc(TII.get(Opcode: WebAssembly::F32_REINTERPRET_I32));
153 return true;
154 }
155 if (DstRC == &WebAssembly::I64RegClass &&
156 SrcRC == &WebAssembly::F64RegClass) {
157 I.setDesc(TII.get(Opcode: WebAssembly::I64_REINTERPRET_F64));
158 return true;
159 }
160 if (DstRC == &WebAssembly::F64RegClass &&
161 SrcRC == &WebAssembly::I64RegClass) {
162 I.setDesc(TII.get(Opcode: WebAssembly::F64_REINTERPRET_I64));
163 return true;
164 }
165
166 llvm_unreachable("COPY between unsupported reg classes.");
167 }
168
169 return true;
170}
171
172bool WebAssemblyInstructionSelector::select(MachineInstr &I) {
173 MachineBasicBlock &MBB = *I.getParent();
174 MachineFunction &MF = *MBB.getParent();
175 MachineRegisterInfo &MRI = MF.getRegInfo();
176 const TargetLowering &TLI = *STI.getTargetLowering();
177
178 if (!I.isPreISelOpcode()) {
179 if (I.isCopy())
180 return selectCopy(I, MRI);
181 return true;
182 }
183
184 if (selectImpl(I, CoverageInfo&: *CoverageInfo))
185 return true;
186
187 using namespace TargetOpcode;
188
189 switch (I.getOpcode()) {
190 case G_IMPLICIT_DEF: {
191 const Register DefReg = I.getOperand(i: 0).getReg();
192
193 const TargetRegisterClass *DefRC =
194 TRI.getConstrainedRegClassForReg(Reg: DefReg, MRI);
195
196 if (!DefRC)
197 return false;
198
199 I.setDesc(TII.get(Opcode: TargetOpcode::IMPLICIT_DEF));
200 return RBI.constrainGenericRegister(Reg: DefReg, RC: *DefRC, MRI) != nullptr;
201 }
202 case G_PTRTOINT: {
203 bool PtrIsI64 = MRI.getType(Reg: I.getOperand(i: 1).getReg()).getSizeInBits() == 64;
204
205 I.setDesc(
206 TII.get(Opcode: PtrIsI64 ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32));
207 constrainSelectedInstRegOperands(I, TII, TRI, RBI);
208 return true;
209 }
210 case G_INTTOPTR: {
211 bool PtrIsI64 = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits() == 64;
212
213 I.setDesc(
214 TII.get(Opcode: PtrIsI64 ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32));
215 constrainSelectedInstRegOperands(I, TII, TRI, RBI);
216 return true;
217 }
218 case G_PTRMASK: {
219 bool PtrIsI64 = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits() == 64;
220
221 I.setDesc(TII.get(Opcode: PtrIsI64 ? WebAssembly::AND_I64 : WebAssembly::AND_I32));
222 constrainSelectedInstRegOperands(I, TII, TRI, RBI);
223 return true;
224 }
225 case G_GLOBAL_VALUE: {
226 assert(I.getOperand(1).getTargetFlags() == 0 &&
227 "Unexpected target flags on generic G_GLOBAL_VALUE instruction");
228
229 unsigned OperandFlags = 0;
230 const llvm::GlobalValue *GV = I.getOperand(i: 1).getGlobal();
231 LLT PtrTy = MRI.getType(Reg: I.getOperand(i: 0).getReg());
232 bool PtrIsI64 = PtrTy.getSizeInBits() == 64;
233
234 if (TLI.isPositionIndependent()) {
235 if (TM.shouldAssumeDSOLocal(GV)) {
236 const char *BaseName;
237 if (GV->getValueType()->isFunctionTy()) {
238 BaseName = MF.createExternalSymbolName(Name: "__table_base");
239 OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL;
240 } else {
241 BaseName = MF.createExternalSymbolName(Name: "__memory_base");
242 OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL;
243 }
244 MachineIRBuilder B(I);
245
246 Register MemBase = MRI.createVirtualRegister(
247 RegClass: PtrIsI64 ? &WebAssembly::I64RegClass : &WebAssembly::I32RegClass);
248
249 Register Offset = MRI.createVirtualRegister(
250 RegClass: PtrIsI64 ? &WebAssembly::I64RegClass : &WebAssembly::I32RegClass);
251
252 B.buildInstr(Opcode: PtrIsI64 ? WebAssembly::GLOBAL_GET_I64
253 : WebAssembly::GLOBAL_GET_I32)
254 .addDef(RegNo: MemBase)
255 .addExternalSymbol(FnName: BaseName);
256
257 B.buildInstr(Opcode: PtrIsI64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32)
258 .addDef(RegNo: Offset)
259 .addGlobalAddress(GV, Offset: I.getOperand(i: 1).getOffset(), TargetFlags: OperandFlags);
260
261 auto MIB =
262 B.buildInstr(Opcode: PtrIsI64 ? WebAssembly::ADD_I64 : WebAssembly::ADD_I32)
263 .addDef(RegNo: I.getOperand(i: 0).getReg())
264 .addReg(RegNo: MemBase)
265 .addReg(RegNo: Offset);
266 constrainSelectedInstRegOperands(I&: *MIB, TII, TRI, RBI);
267
268 I.eraseFromParent();
269 return true;
270 }
271 OperandFlags = WebAssemblyII::MO_GOT;
272 }
273
274 unsigned NewOpc =
275 PtrIsI64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
276
277 if (OperandFlags & WebAssemblyII::MO_GOT) {
278 NewOpc =
279 PtrIsI64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32;
280 }
281
282 I.setDesc(TII.get(Opcode: NewOpc));
283 I.getOperand(i: 1).setTargetFlags(OperandFlags);
284 constrainSelectedInstRegOperands(I, TII, TRI, RBI);
285
286 return true;
287 }
288 default:
289 break;
290 }
291
292 return false;
293}
294
295namespace llvm {
296InstructionSelector *
297createWebAssemblyInstructionSelector(const WebAssemblyTargetMachine &TM,
298 const WebAssemblySubtarget &Subtarget,
299 const WebAssemblyRegisterBankInfo &RBI) {
300 return new WebAssemblyInstructionSelector(TM, Subtarget, RBI);
301}
302} // namespace llvm
303