blob: 2552e91508334740a72a96d39be48a63bb065fef [file] [log] [blame]
Dan Gohman7b634842015-08-24 18:44:37 +00001//===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dan Gohman7b634842015-08-24 18:44:37 +00006//
7//===----------------------------------------------------------------------===//
8///
9/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000010/// This file defines the WebAssembly-specific support for the FastISel
Dan Gohman7b634842015-08-24 18:44:37 +000011/// class. Some of the target-specific code is generated by tablegen in the file
12/// WebAssemblyGenFastISel.inc, which is #included here.
13///
Dan Gohman33e694a2016-05-12 04:19:09 +000014/// TODO: kill flags
15///
Dan Gohman7b634842015-08-24 18:44:37 +000016//===----------------------------------------------------------------------===//
17
Dan Gohman7b634842015-08-24 18:44:37 +000018#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000019#include "WebAssembly.h"
Dan Gohman33e694a2016-05-12 04:19:09 +000020#include "WebAssemblyMachineFunctionInfo.h"
Dan Gohman7b634842015-08-24 18:44:37 +000021#include "WebAssemblySubtarget.h"
22#include "WebAssemblyTargetMachine.h"
23#include "llvm/Analysis/BranchProbabilityInfo.h"
24#include "llvm/CodeGen/FastISel.h"
25#include "llvm/CodeGen/FunctionLoweringInfo.h"
26#include "llvm/CodeGen/MachineConstantPool.h"
27#include "llvm/CodeGen/MachineFrameInfo.h"
28#include "llvm/CodeGen/MachineInstrBuilder.h"
29#include "llvm/CodeGen/MachineRegisterInfo.h"
30#include "llvm/IR/DataLayout.h"
31#include "llvm/IR/DerivedTypes.h"
32#include "llvm/IR/Function.h"
33#include "llvm/IR/GetElementPtrTypeIterator.h"
34#include "llvm/IR/GlobalAlias.h"
35#include "llvm/IR/GlobalVariable.h"
36#include "llvm/IR/Instructions.h"
37#include "llvm/IR/IntrinsicInst.h"
38#include "llvm/IR/Operator.h"
Sanjay Patel47a52a02018-10-23 16:05:09 +000039#include "llvm/IR/PatternMatch.h"
40
Dan Gohman7b634842015-08-24 18:44:37 +000041using namespace llvm;
Sanjay Patel47a52a02018-10-23 16:05:09 +000042using namespace PatternMatch;
Dan Gohman7b634842015-08-24 18:44:37 +000043
44#define DEBUG_TYPE "wasm-fastisel"
45
46namespace {
47
48class WebAssemblyFastISel final : public FastISel {
Dan Gohman2e644382016-05-10 17:39:48 +000049 // All possible address modes.
50 class Address {
51 public:
Heejin Ahn18c56a02019-02-04 19:13:39 +000052 using BaseKind = enum { RegBase, FrameIndexBase };
Dan Gohman2e644382016-05-10 17:39:48 +000053
54 private:
Heejin Ahn18c56a02019-02-04 19:13:39 +000055 BaseKind Kind = RegBase;
Dan Gohman2e644382016-05-10 17:39:48 +000056 union {
57 unsigned Reg;
58 int FI;
59 } Base;
60
Heejin Ahn18c56a02019-02-04 19:13:39 +000061 int64_t Offset = 0;
Dan Gohman2e644382016-05-10 17:39:48 +000062
Heejin Ahn18c56a02019-02-04 19:13:39 +000063 const GlobalValue *GV = nullptr;
Dan Gohman2e644382016-05-10 17:39:48 +000064
65 public:
66 // Innocuous defaults for our address.
Heejin Ahn18c56a02019-02-04 19:13:39 +000067 Address() { Base.Reg = 0; }
Jacob Gravellea31ec612017-06-22 21:26:08 +000068 void setKind(BaseKind K) {
69 assert(!isSet() && "Can't change kind with non-zero base");
70 Kind = K;
71 }
Dan Gohman2e644382016-05-10 17:39:48 +000072 BaseKind getKind() const { return Kind; }
73 bool isRegBase() const { return Kind == RegBase; }
74 bool isFIBase() const { return Kind == FrameIndexBase; }
75 void setReg(unsigned Reg) {
76 assert(isRegBase() && "Invalid base register access!");
Jacob Gravellea31ec612017-06-22 21:26:08 +000077 assert(Base.Reg == 0 && "Overwriting non-zero register");
Dan Gohman2e644382016-05-10 17:39:48 +000078 Base.Reg = Reg;
79 }
80 unsigned getReg() const {
81 assert(isRegBase() && "Invalid base register access!");
82 return Base.Reg;
83 }
84 void setFI(unsigned FI) {
85 assert(isFIBase() && "Invalid base frame index access!");
Jacob Gravellea31ec612017-06-22 21:26:08 +000086 assert(Base.FI == 0 && "Overwriting non-zero frame index");
Dan Gohman2e644382016-05-10 17:39:48 +000087 Base.FI = FI;
88 }
89 unsigned getFI() const {
90 assert(isFIBase() && "Invalid base frame index access!");
91 return Base.FI;
92 }
93
Heejin Ahn18c56a02019-02-04 19:13:39 +000094 void setOffset(int64_t NewOffset) {
95 assert(NewOffset >= 0 && "Offsets must be non-negative");
96 Offset = NewOffset;
Dan Gohman728926a2016-12-22 15:15:10 +000097 }
Dan Gohman2e644382016-05-10 17:39:48 +000098 int64_t getOffset() const { return Offset; }
99 void setGlobalValue(const GlobalValue *G) { GV = G; }
100 const GlobalValue *getGlobalValue() const { return GV; }
Jacob Gravellea31ec612017-06-22 21:26:08 +0000101 bool isSet() const {
102 if (isRegBase()) {
103 return Base.Reg != 0;
104 } else {
105 return Base.FI != 0;
106 }
107 }
Dan Gohman2e644382016-05-10 17:39:48 +0000108 };
109
Dan Gohman7b634842015-08-24 18:44:37 +0000110 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
111 /// right decision when generating code for different targets.
112 const WebAssemblySubtarget *Subtarget;
113 LLVMContext *Context;
114
Dan Gohman7b634842015-08-24 18:44:37 +0000115private:
Dan Gohman2e644382016-05-10 17:39:48 +0000116 // Utility helper routines
Dan Gohman3a5ce732016-05-11 16:32:42 +0000117 MVT::SimpleValueType getSimpleType(Type *Ty) {
Rui Ueyama49a3ad22019-07-16 04:46:31 +0000118 EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
Heejin Ahnf208f632018-09-05 01:27:38 +0000119 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
120 : MVT::INVALID_SIMPLE_VALUE_TYPE;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000121 }
122 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
123 switch (VT) {
124 case MVT::i1:
125 case MVT::i8:
126 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000127 return MVT::i32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000128 case MVT::i32:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000129 case MVT::i64:
Dan Gohman33e694a2016-05-12 04:19:09 +0000130 case MVT::f32:
131 case MVT::f64:
Heejin Ahn9f96a582019-07-15 22:49:25 +0000132 case MVT::exnref:
Dan Gohman33e694a2016-05-12 04:19:09 +0000133 return VT;
Dan Gohman6999c4f2017-02-24 21:05:35 +0000134 case MVT::f16:
135 return MVT::f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000136 case MVT::v16i8:
137 case MVT::v8i16:
138 case MVT::v4i32:
139 case MVT::v4f32:
140 if (Subtarget->hasSIMD128())
141 return VT;
142 break;
Thomas Livelyb6dac892018-12-21 06:58:15 +0000143 case MVT::v2i64:
144 case MVT::v2f64:
Thomas Lively64a39a12019-01-10 22:32:11 +0000145 if (Subtarget->hasUnimplementedSIMD128())
Thomas Livelyb6dac892018-12-21 06:58:15 +0000146 return VT;
147 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000148 default:
149 break;
150 }
151 return MVT::INVALID_SIMPLE_VALUE_TYPE;
152 }
Dan Gohman2e644382016-05-10 17:39:48 +0000153 bool computeAddress(const Value *Obj, Address &Addr);
Sam Clegg9da81422019-04-23 03:43:26 +0000154 void materializeLoadStoreOperands(Address &Addr);
Dan Gohman2e644382016-05-10 17:39:48 +0000155 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
156 MachineMemOperand *MMO);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000157 unsigned maskI1Value(unsigned Reg, const Value *V);
Dan Gohman33e694a2016-05-12 04:19:09 +0000158 unsigned getRegForI1Value(const Value *V, bool &Not);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000159 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
160 MVT::SimpleValueType From);
161 unsigned signExtendToI32(unsigned Reg, const Value *V,
162 MVT::SimpleValueType From);
Heejin Ahnf208f632018-09-05 01:27:38 +0000163 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
Dan Gohman3a5ce732016-05-11 16:32:42 +0000164 MVT::SimpleValueType To);
Heejin Ahnf208f632018-09-05 01:27:38 +0000165 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
Dan Gohman3a5ce732016-05-11 16:32:42 +0000166 MVT::SimpleValueType To);
167 unsigned getRegForUnsignedValue(const Value *V);
168 unsigned getRegForSignedValue(const Value *V);
169 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
170 unsigned notValue(unsigned Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000171 unsigned copyValue(unsigned Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000172
173 // Backend specific FastISel code.
174 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
175 unsigned fastMaterializeConstant(const Constant *C) override;
Dan Gohman33e694a2016-05-12 04:19:09 +0000176 bool fastLowerArguments() override;
Dan Gohman2e644382016-05-10 17:39:48 +0000177
178 // Selection routines.
Dan Gohman33e694a2016-05-12 04:19:09 +0000179 bool selectCall(const Instruction *I);
180 bool selectSelect(const Instruction *I);
181 bool selectTrunc(const Instruction *I);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000182 bool selectZExt(const Instruction *I);
183 bool selectSExt(const Instruction *I);
184 bool selectICmp(const Instruction *I);
185 bool selectFCmp(const Instruction *I);
Dan Gohman2e644382016-05-10 17:39:48 +0000186 bool selectBitCast(const Instruction *I);
187 bool selectLoad(const Instruction *I);
188 bool selectStore(const Instruction *I);
189 bool selectBr(const Instruction *I);
190 bool selectRet(const Instruction *I);
191 bool selectUnreachable(const Instruction *I);
192
Dan Gohman7b634842015-08-24 18:44:37 +0000193public:
194 // Backend specific FastISel code.
195 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
196 const TargetLibraryInfo *LibInfo)
197 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
198 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
199 Context = &FuncInfo.Fn->getContext();
200 }
201
202 bool fastSelectInstruction(const Instruction *I) override;
203
204#include "WebAssemblyGenFastISel.inc"
205};
206
207} // end anonymous namespace
208
Dan Gohman2e644382016-05-10 17:39:48 +0000209bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
Dan Gohman2e644382016-05-10 17:39:48 +0000210 const User *U = nullptr;
211 unsigned Opcode = Instruction::UserOp1;
Heejin Ahn18c56a02019-02-04 19:13:39 +0000212 if (const auto *I = dyn_cast<Instruction>(Obj)) {
Dan Gohman2e644382016-05-10 17:39:48 +0000213 // Don't walk into other basic blocks unless the object is an alloca from
214 // another block, otherwise it may not have a virtual register assigned.
215 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
216 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
217 Opcode = I->getOpcode();
218 U = I;
219 }
Heejin Ahn18c56a02019-02-04 19:13:39 +0000220 } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
Dan Gohman2e644382016-05-10 17:39:48 +0000221 Opcode = C->getOpcode();
222 U = C;
223 }
224
225 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
226 if (Ty->getAddressSpace() > 255)
227 // Fast instruction selection doesn't support the special
228 // address spaces.
229 return false;
230
Heejin Ahn18c56a02019-02-04 19:13:39 +0000231 if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
Sam Clegg9da81422019-04-23 03:43:26 +0000232 if (TLI.isPositionIndependent())
233 return false;
Dan Gohman2e644382016-05-10 17:39:48 +0000234 if (Addr.getGlobalValue())
235 return false;
Guanzhong Chen42bba4b2019-07-16 22:00:45 +0000236 if (GV->isThreadLocal())
237 return false;
Dan Gohman2e644382016-05-10 17:39:48 +0000238 Addr.setGlobalValue(GV);
239 return true;
240 }
241
242 switch (Opcode) {
Dan Gohman7b634842015-08-24 18:44:37 +0000243 default:
244 break;
Dan Gohman2e644382016-05-10 17:39:48 +0000245 case Instruction::BitCast: {
246 // Look through bitcasts.
247 return computeAddress(U->getOperand(0), Addr);
248 }
249 case Instruction::IntToPtr: {
250 // Look past no-op inttoptrs.
251 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
252 TLI.getPointerTy(DL))
253 return computeAddress(U->getOperand(0), Addr);
254 break;
255 }
256 case Instruction::PtrToInt: {
257 // Look past no-op ptrtoints.
258 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
259 return computeAddress(U->getOperand(0), Addr);
260 break;
261 }
262 case Instruction::GetElementPtr: {
263 Address SavedAddr = Addr;
264 uint64_t TmpOffset = Addr.getOffset();
Dan Gohman728926a2016-12-22 15:15:10 +0000265 // Non-inbounds geps can wrap; wasm's offsets can't.
266 if (!cast<GEPOperator>(U)->isInBounds())
267 goto unsupported_gep;
Dan Gohman2e644382016-05-10 17:39:48 +0000268 // Iterate through the GEP folding the constants into offsets where
269 // we can.
Dan Gohman33e694a2016-05-12 04:19:09 +0000270 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
Dan Gohman2e644382016-05-10 17:39:48 +0000271 GTI != E; ++GTI) {
272 const Value *Op = GTI.getOperand();
Peter Collingbourneab85225b2016-12-02 02:24:42 +0000273 if (StructType *STy = GTI.getStructTypeOrNull()) {
Dan Gohman2e644382016-05-10 17:39:48 +0000274 const StructLayout *SL = DL.getStructLayout(STy);
275 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
276 TmpOffset += SL->getElementOffset(Idx);
277 } else {
278 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
279 for (;;) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000280 if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
Dan Gohman2e644382016-05-10 17:39:48 +0000281 // Constant-offset addressing.
282 TmpOffset += CI->getSExtValue() * S;
283 break;
284 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000285 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
286 // An unscaled add of a register. Set it as the new base.
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000287 unsigned Reg = getRegForValue(Op);
288 if (Reg == 0)
289 return false;
290 Addr.setReg(Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000291 break;
292 }
Dan Gohman2e644382016-05-10 17:39:48 +0000293 if (canFoldAddIntoGEP(U, Op)) {
294 // A compatible add with a constant operand. Fold the constant.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000295 auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
Dan Gohman2e644382016-05-10 17:39:48 +0000296 TmpOffset += CI->getSExtValue() * S;
297 // Iterate on the other operand.
298 Op = cast<AddOperator>(Op)->getOperand(0);
299 continue;
300 }
301 // Unsupported
302 goto unsupported_gep;
303 }
304 }
305 }
Dan Gohman728926a2016-12-22 15:15:10 +0000306 // Don't fold in negative offsets.
307 if (int64_t(TmpOffset) >= 0) {
308 // Try to grab the base operand now.
309 Addr.setOffset(TmpOffset);
310 if (computeAddress(U->getOperand(0), Addr))
311 return true;
312 }
Dan Gohman2e644382016-05-10 17:39:48 +0000313 // We failed, restore everything and try the other options.
314 Addr = SavedAddr;
315 unsupported_gep:
316 break;
317 }
318 case Instruction::Alloca: {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000319 const auto *AI = cast<AllocaInst>(Obj);
Dan Gohman2e644382016-05-10 17:39:48 +0000320 DenseMap<const AllocaInst *, int>::iterator SI =
321 FuncInfo.StaticAllocaMap.find(AI);
322 if (SI != FuncInfo.StaticAllocaMap.end()) {
Jacob Gravellea31ec612017-06-22 21:26:08 +0000323 if (Addr.isSet()) {
324 return false;
325 }
Dan Gohman2e644382016-05-10 17:39:48 +0000326 Addr.setKind(Address::FrameIndexBase);
327 Addr.setFI(SI->second);
328 return true;
329 }
330 break;
331 }
332 case Instruction::Add: {
333 // Adds of constants are common and easy enough.
334 const Value *LHS = U->getOperand(0);
335 const Value *RHS = U->getOperand(1);
336
337 if (isa<ConstantInt>(LHS))
338 std::swap(LHS, RHS);
339
Heejin Ahn18c56a02019-02-04 19:13:39 +0000340 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000341 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
342 if (int64_t(TmpOffset) >= 0) {
343 Addr.setOffset(TmpOffset);
344 return computeAddress(LHS, Addr);
345 }
Dan Gohman2e644382016-05-10 17:39:48 +0000346 }
347
348 Address Backup = Addr;
349 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
350 return true;
351 Addr = Backup;
352
353 break;
354 }
355 case Instruction::Sub: {
356 // Subs of constants are common and easy enough.
357 const Value *LHS = U->getOperand(0);
358 const Value *RHS = U->getOperand(1);
359
Heejin Ahn18c56a02019-02-04 19:13:39 +0000360 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000361 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
362 if (TmpOffset >= 0) {
363 Addr.setOffset(TmpOffset);
364 return computeAddress(LHS, Addr);
365 }
Dan Gohman2e644382016-05-10 17:39:48 +0000366 }
367 break;
368 }
369 }
Jacob Gravellea31ec612017-06-22 21:26:08 +0000370 if (Addr.isSet()) {
371 return false;
372 }
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000373 unsigned Reg = getRegForValue(Obj);
374 if (Reg == 0)
375 return false;
376 Addr.setReg(Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000377 return Addr.getReg() != 0;
378}
379
Sam Clegg9da81422019-04-23 03:43:26 +0000380void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
Dan Gohman2e644382016-05-10 17:39:48 +0000381 if (Addr.isRegBase()) {
382 unsigned Reg = Addr.getReg();
383 if (Reg == 0) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000384 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
385 : &WebAssembly::I32RegClass);
386 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
387 : WebAssembly::CONST_I32;
Dan Gohman2e644382016-05-10 17:39:48 +0000388 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
Heejin Ahnf208f632018-09-05 01:27:38 +0000389 .addImm(0);
Dan Gohman2e644382016-05-10 17:39:48 +0000390 Addr.setReg(Reg);
391 }
392 }
393}
394
395void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
396 const MachineInstrBuilder &MIB,
397 MachineMemOperand *MMO) {
Dan Gohman48abaa92016-10-25 00:17:11 +0000398 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
399 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
400 MIB.addImm(0);
401
Dan Gohman2e644382016-05-10 17:39:48 +0000402 if (const GlobalValue *GV = Addr.getGlobalValue())
403 MIB.addGlobalAddress(GV, Addr.getOffset());
404 else
405 MIB.addImm(Addr.getOffset());
406
407 if (Addr.isRegBase())
408 MIB.addReg(Addr.getReg());
409 else
410 MIB.addFrameIndex(Addr.getFI());
411
Dan Gohman2e644382016-05-10 17:39:48 +0000412 MIB.addMemOperand(MMO);
413}
414
Dan Gohman3a5ce732016-05-11 16:32:42 +0000415unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
416 return zeroExtendToI32(Reg, V, MVT::i1);
Dan Gohman2e644382016-05-10 17:39:48 +0000417}
418
Dan Gohman33e694a2016-05-12 04:19:09 +0000419unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000420 if (const auto *ICmp = dyn_cast<ICmpInst>(V))
Dan Gohman33e694a2016-05-12 04:19:09 +0000421 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
422 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
423 Not = ICmp->isTrueWhenEqual();
424 return getRegForValue(ICmp->getOperand(0));
425 }
426
Sanjay Patel47a52a02018-10-23 16:05:09 +0000427 Value *NotV;
428 if (match(V, m_Not(m_Value(NotV))) && V->getType()->isIntegerTy(32)) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000429 Not = true;
Sanjay Patel47a52a02018-10-23 16:05:09 +0000430 return getRegForValue(NotV);
Dan Gohman33e694a2016-05-12 04:19:09 +0000431 }
432
433 Not = false;
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000434 unsigned Reg = getRegForValue(V);
435 if (Reg == 0)
436 return 0;
437 return maskI1Value(Reg, V);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000438}
439
440unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
441 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000442 if (Reg == 0)
443 return 0;
444
Dan Gohman3a5ce732016-05-11 16:32:42 +0000445 switch (From) {
446 case MVT::i1:
Thomas Lively2a47e032019-01-14 22:03:43 +0000447 // If the value is naturally an i1, we don't need to mask it. We only know
448 // if a value is naturally an i1 if it is definitely lowered by FastISel,
449 // not a DAG ISel fallback.
450 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
451 return copyValue(Reg);
Reid Kleckner4dc0b1a2018-11-01 19:54:45 +0000452 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000453 case MVT::i8:
454 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000455 break;
456 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000457 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000458 default:
459 return 0;
460 }
461
462 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
463 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
464 TII.get(WebAssembly::CONST_I32), Imm)
Heejin Ahnf208f632018-09-05 01:27:38 +0000465 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
Dan Gohman3a5ce732016-05-11 16:32:42 +0000466
467 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
468 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
469 TII.get(WebAssembly::AND_I32), Result)
Heejin Ahnf208f632018-09-05 01:27:38 +0000470 .addReg(Reg)
471 .addReg(Imm);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000472
473 return Result;
474}
475
476unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
477 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000478 if (Reg == 0)
479 return 0;
480
Dan Gohman3a5ce732016-05-11 16:32:42 +0000481 switch (From) {
482 case MVT::i1:
483 case MVT::i8:
484 case MVT::i16:
485 break;
486 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000487 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000488 default:
Dan Gohman33e694a2016-05-12 04:19:09 +0000489 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000490 }
491
492 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
493 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
494 TII.get(WebAssembly::CONST_I32), Imm)
Heejin Ahnf208f632018-09-05 01:27:38 +0000495 .addImm(32 - MVT(From).getSizeInBits());
Dan Gohman3a5ce732016-05-11 16:32:42 +0000496
497 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
499 TII.get(WebAssembly::SHL_I32), Left)
Heejin Ahnf208f632018-09-05 01:27:38 +0000500 .addReg(Reg)
501 .addReg(Imm);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000502
503 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
504 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
505 TII.get(WebAssembly::SHR_S_I32), Right)
Heejin Ahnf208f632018-09-05 01:27:38 +0000506 .addReg(Left)
507 .addReg(Imm);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000508
509 return Right;
510}
511
512unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
513 MVT::SimpleValueType From,
514 MVT::SimpleValueType To) {
515 if (To == MVT::i64) {
516 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000517 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000518
519 Reg = zeroExtendToI32(Reg, V, From);
520
521 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
522 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
523 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
524 .addReg(Reg);
525 return Result;
526 }
527
Nikita Popov323dc632019-05-13 19:40:18 +0000528 if (To == MVT::i32)
529 return zeroExtendToI32(Reg, V, From);
530
531 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000532}
533
534unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
535 MVT::SimpleValueType From,
536 MVT::SimpleValueType To) {
537 if (To == MVT::i64) {
538 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000539 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000540
541 Reg = signExtendToI32(Reg, V, From);
542
543 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
544 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
545 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
546 .addReg(Reg);
547 return Result;
548 }
549
Nikita Popov323dc632019-05-13 19:40:18 +0000550 if (To == MVT::i32)
551 return signExtendToI32(Reg, V, From);
552
553 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000554}
555
556unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
557 MVT::SimpleValueType From = getSimpleType(V->getType());
558 MVT::SimpleValueType To = getLegalType(From);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000559 unsigned VReg = getRegForValue(V);
560 if (VReg == 0)
561 return 0;
562 return zeroExtend(VReg, V, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000563}
564
565unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
566 MVT::SimpleValueType From = getSimpleType(V->getType());
567 MVT::SimpleValueType To = getLegalType(From);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000568 unsigned VReg = getRegForValue(V);
569 if (VReg == 0)
570 return 0;
571 return signExtend(VReg, V, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000572}
573
574unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
575 bool IsSigned) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000576 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000577}
578
579unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000580 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
581
Dan Gohman3a5ce732016-05-11 16:32:42 +0000582 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
583 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
584 TII.get(WebAssembly::EQZ_I32), NotReg)
Heejin Ahnf208f632018-09-05 01:27:38 +0000585 .addReg(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000586 return NotReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000587}
588
Dan Gohman33e694a2016-05-12 04:19:09 +0000589unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
590 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
Heejin Ahnf208f632018-09-05 01:27:38 +0000591 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY),
592 ResultReg)
593 .addReg(Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000594 return ResultReg;
595}
596
Dan Gohman2e644382016-05-10 17:39:48 +0000597unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
598 DenseMap<const AllocaInst *, int>::iterator SI =
599 FuncInfo.StaticAllocaMap.find(AI);
600
601 if (SI != FuncInfo.StaticAllocaMap.end()) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000602 unsigned ResultReg =
603 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
604 : &WebAssembly::I32RegClass);
605 unsigned Opc =
606 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
Dan Gohman2e644382016-05-10 17:39:48 +0000607 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
608 .addFrameIndex(SI->second);
609 return ResultReg;
610 }
611
612 return 0;
613}
614
615unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
Sam Clegg492f7522019-03-26 19:46:15 +0000616 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
617 if (TLI.isPositionIndependent())
618 return 0;
Guanzhong Chen42bba4b2019-07-16 22:00:45 +0000619 if (GV->isThreadLocal())
620 return 0;
Heejin Ahnf208f632018-09-05 01:27:38 +0000621 unsigned ResultReg =
622 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
623 : &WebAssembly::I32RegClass);
624 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
625 : WebAssembly::CONST_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000626 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Heejin Ahnf208f632018-09-05 01:27:38 +0000627 .addGlobalAddress(GV);
Dan Gohman33e694a2016-05-12 04:19:09 +0000628 return ResultReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000629 }
630
631 // Let target-independent code handle it.
632 return 0;
633}
634
Dan Gohman33e694a2016-05-12 04:19:09 +0000635bool WebAssemblyFastISel::fastLowerArguments() {
636 if (!FuncInfo.CanLowerReturn)
637 return false;
638
639 const Function *F = FuncInfo.Fn;
640 if (F->isVarArg())
641 return false;
642
Heejin Ahn18c56a02019-02-04 19:13:39 +0000643 unsigned I = 0;
Dan Gohman33e694a2016-05-12 04:19:09 +0000644 for (auto const &Arg : F->args()) {
Reid Klecknerb5180542017-03-21 16:57:19 +0000645 const AttributeList &Attrs = F->getAttributes();
Heejin Ahn18c56a02019-02-04 19:13:39 +0000646 if (Attrs.hasParamAttribute(I, Attribute::ByVal) ||
647 Attrs.hasParamAttribute(I, Attribute::SwiftSelf) ||
648 Attrs.hasParamAttribute(I, Attribute::SwiftError) ||
649 Attrs.hasParamAttribute(I, Attribute::InAlloca) ||
650 Attrs.hasParamAttribute(I, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000651 return false;
652
653 Type *ArgTy = Arg.getType();
Derek Schuff39bf39f2016-08-02 23:16:09 +0000654 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
655 return false;
656 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
Dan Gohman33e694a2016-05-12 04:19:09 +0000657 return false;
658
659 unsigned Opc;
660 const TargetRegisterClass *RC;
661 switch (getSimpleType(ArgTy)) {
662 case MVT::i1:
663 case MVT::i8:
664 case MVT::i16:
665 case MVT::i32:
Thomas Lively0ff82ac2018-10-13 07:09:10 +0000666 Opc = WebAssembly::ARGUMENT_i32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000667 RC = &WebAssembly::I32RegClass;
668 break;
669 case MVT::i64:
Thomas Lively0ff82ac2018-10-13 07:09:10 +0000670 Opc = WebAssembly::ARGUMENT_i64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000671 RC = &WebAssembly::I64RegClass;
672 break;
673 case MVT::f32:
Thomas Lively0ff82ac2018-10-13 07:09:10 +0000674 Opc = WebAssembly::ARGUMENT_f32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000675 RC = &WebAssembly::F32RegClass;
676 break;
677 case MVT::f64:
Thomas Lively0ff82ac2018-10-13 07:09:10 +0000678 Opc = WebAssembly::ARGUMENT_f64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000679 RC = &WebAssembly::F64RegClass;
680 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000681 case MVT::v16i8:
682 Opc = WebAssembly::ARGUMENT_v16i8;
683 RC = &WebAssembly::V128RegClass;
684 break;
685 case MVT::v8i16:
686 Opc = WebAssembly::ARGUMENT_v8i16;
687 RC = &WebAssembly::V128RegClass;
688 break;
689 case MVT::v4i32:
690 Opc = WebAssembly::ARGUMENT_v4i32;
691 RC = &WebAssembly::V128RegClass;
692 break;
Derek Schuff51ed1312018-08-07 21:24:01 +0000693 case MVT::v2i64:
694 Opc = WebAssembly::ARGUMENT_v2i64;
695 RC = &WebAssembly::V128RegClass;
696 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000697 case MVT::v4f32:
698 Opc = WebAssembly::ARGUMENT_v4f32;
699 RC = &WebAssembly::V128RegClass;
700 break;
Derek Schuff51ed1312018-08-07 21:24:01 +0000701 case MVT::v2f64:
702 Opc = WebAssembly::ARGUMENT_v2f64;
703 RC = &WebAssembly::V128RegClass;
704 break;
Heejin Ahn9f96a582019-07-15 22:49:25 +0000705 case MVT::exnref:
706 Opc = WebAssembly::ARGUMENT_exnref;
707 RC = &WebAssembly::EXNREFRegClass;
Heejin Ahn0de58722018-03-08 04:05:37 +0000708 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000709 default:
710 return false;
711 }
712 unsigned ResultReg = createResultReg(RC);
713 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Heejin Ahn18c56a02019-02-04 19:13:39 +0000714 .addImm(I);
Dan Gohman33e694a2016-05-12 04:19:09 +0000715 updateValueMap(&Arg, ResultReg);
716
Heejin Ahn18c56a02019-02-04 19:13:39 +0000717 ++I;
Dan Gohman33e694a2016-05-12 04:19:09 +0000718 }
719
720 MRI.addLiveIn(WebAssembly::ARGUMENTS);
721
722 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
Dan Gohmanb8184822018-05-22 04:58:36 +0000723 for (auto const &Arg : F->args()) {
724 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
725 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
726 MFI->clearParamsAndResults();
727 return false;
728 }
729 MFI->addParam(ArgTy);
730 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000731
Dan Gohman4576dc02018-04-17 20:46:42 +0000732 if (!F->getReturnType()->isVoidTy()) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000733 MVT::SimpleValueType RetTy =
734 getLegalType(getSimpleType(F->getReturnType()));
Dan Gohmanb8184822018-05-22 04:58:36 +0000735 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
736 MFI->clearParamsAndResults();
Dan Gohman4576dc02018-04-17 20:46:42 +0000737 return false;
Dan Gohmanb8184822018-05-22 04:58:36 +0000738 }
739 MFI->addResult(RetTy);
Dan Gohman4576dc02018-04-17 20:46:42 +0000740 }
Dan Gohman6055fba2017-01-09 23:09:38 +0000741
Dan Gohman33e694a2016-05-12 04:19:09 +0000742 return true;
743}
744
745bool WebAssemblyFastISel::selectCall(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000746 const auto *Call = cast<CallInst>(I);
Dan Gohman33e694a2016-05-12 04:19:09 +0000747
Thomas Livelya1d97a92019-06-26 16:17:15 +0000748 // TODO: Support tail calls in FastISel
Dan Gohman33e694a2016-05-12 04:19:09 +0000749 if (Call->isMustTailCall() || Call->isInlineAsm() ||
750 Call->getFunctionType()->isVarArg())
751 return false;
752
753 Function *Func = Call->getCalledFunction();
754 if (Func && Func->isIntrinsic())
755 return false;
756
Jacob Gravelle690b76e2017-08-24 19:53:44 +0000757 bool IsDirect = Func != nullptr;
758 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
759 return false;
760
Dan Gohman33e694a2016-05-12 04:19:09 +0000761 FunctionType *FuncTy = Call->getFunctionType();
762 unsigned Opc;
Dan Gohman33e694a2016-05-12 04:19:09 +0000763 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
764 unsigned ResultReg;
765 if (IsVoid) {
Derek Schuff6f697832016-10-21 16:38:07 +0000766 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
Dan Gohman33e694a2016-05-12 04:19:09 +0000767 } else {
Derek Schuff39bf39f2016-08-02 23:16:09 +0000768 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
769 return false;
770
Dan Gohman33e694a2016-05-12 04:19:09 +0000771 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
772 switch (RetTy) {
773 case MVT::i1:
774 case MVT::i8:
775 case MVT::i16:
776 case MVT::i32:
Thomas Livelya1d97a92019-06-26 16:17:15 +0000777 Opc = IsDirect ? WebAssembly::CALL_i32 : WebAssembly::PCALL_INDIRECT_i32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000778 ResultReg = createResultReg(&WebAssembly::I32RegClass);
779 break;
780 case MVT::i64:
Thomas Livelya1d97a92019-06-26 16:17:15 +0000781 Opc = IsDirect ? WebAssembly::CALL_i64 : WebAssembly::PCALL_INDIRECT_i64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000782 ResultReg = createResultReg(&WebAssembly::I64RegClass);
783 break;
784 case MVT::f32:
Thomas Livelya1d97a92019-06-26 16:17:15 +0000785 Opc = IsDirect ? WebAssembly::CALL_f32 : WebAssembly::PCALL_INDIRECT_f32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000786 ResultReg = createResultReg(&WebAssembly::F32RegClass);
787 break;
788 case MVT::f64:
Thomas Livelya1d97a92019-06-26 16:17:15 +0000789 Opc = IsDirect ? WebAssembly::CALL_f64 : WebAssembly::PCALL_INDIRECT_f64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000790 ResultReg = createResultReg(&WebAssembly::F64RegClass);
791 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000792 case MVT::v16i8:
Heejin Ahnf208f632018-09-05 01:27:38 +0000793 Opc = IsDirect ? WebAssembly::CALL_v16i8
794 : WebAssembly::PCALL_INDIRECT_v16i8;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000795 ResultReg = createResultReg(&WebAssembly::V128RegClass);
796 break;
797 case MVT::v8i16:
Heejin Ahnf208f632018-09-05 01:27:38 +0000798 Opc = IsDirect ? WebAssembly::CALL_v8i16
799 : WebAssembly::PCALL_INDIRECT_v8i16;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000800 ResultReg = createResultReg(&WebAssembly::V128RegClass);
801 break;
802 case MVT::v4i32:
Heejin Ahnf208f632018-09-05 01:27:38 +0000803 Opc = IsDirect ? WebAssembly::CALL_v4i32
804 : WebAssembly::PCALL_INDIRECT_v4i32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000805 ResultReg = createResultReg(&WebAssembly::V128RegClass);
806 break;
Derek Schuff51ed1312018-08-07 21:24:01 +0000807 case MVT::v2i64:
Heejin Ahnf208f632018-09-05 01:27:38 +0000808 Opc = IsDirect ? WebAssembly::CALL_v2i64
809 : WebAssembly::PCALL_INDIRECT_v2i64;
Derek Schuff51ed1312018-08-07 21:24:01 +0000810 ResultReg = createResultReg(&WebAssembly::V128RegClass);
811 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000812 case MVT::v4f32:
Heejin Ahnf208f632018-09-05 01:27:38 +0000813 Opc = IsDirect ? WebAssembly::CALL_v4f32
814 : WebAssembly::PCALL_INDIRECT_v4f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000815 ResultReg = createResultReg(&WebAssembly::V128RegClass);
816 break;
Derek Schuff51ed1312018-08-07 21:24:01 +0000817 case MVT::v2f64:
Heejin Ahnf208f632018-09-05 01:27:38 +0000818 Opc = IsDirect ? WebAssembly::CALL_v2f64
819 : WebAssembly::PCALL_INDIRECT_v2f64;
Derek Schuff51ed1312018-08-07 21:24:01 +0000820 ResultReg = createResultReg(&WebAssembly::V128RegClass);
821 break;
Heejin Ahn9f96a582019-07-15 22:49:25 +0000822 case MVT::exnref:
823 Opc = IsDirect ? WebAssembly::CALL_exnref
824 : WebAssembly::PCALL_INDIRECT_exnref;
825 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
Heejin Ahn0de58722018-03-08 04:05:37 +0000826 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000827 default:
828 return false;
829 }
830 }
831
832 SmallVector<unsigned, 8> Args;
Heejin Ahn18c56a02019-02-04 19:13:39 +0000833 for (unsigned I = 0, E = Call->getNumArgOperands(); I < E; ++I) {
834 Value *V = Call->getArgOperand(I);
Dan Gohman33e694a2016-05-12 04:19:09 +0000835 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
836 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
837 return false;
838
Reid Klecknerb5180542017-03-21 16:57:19 +0000839 const AttributeList &Attrs = Call->getAttributes();
Heejin Ahn18c56a02019-02-04 19:13:39 +0000840 if (Attrs.hasParamAttribute(I, Attribute::ByVal) ||
841 Attrs.hasParamAttribute(I, Attribute::SwiftSelf) ||
842 Attrs.hasParamAttribute(I, Attribute::SwiftError) ||
843 Attrs.hasParamAttribute(I, Attribute::InAlloca) ||
844 Attrs.hasParamAttribute(I, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000845 return false;
846
847 unsigned Reg;
848
Heejin Ahn18c56a02019-02-04 19:13:39 +0000849 if (Attrs.hasParamAttribute(I, Attribute::SExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000850 Reg = getRegForSignedValue(V);
Heejin Ahn18c56a02019-02-04 19:13:39 +0000851 else if (Attrs.hasParamAttribute(I, Attribute::ZExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000852 Reg = getRegForUnsignedValue(V);
853 else
854 Reg = getRegForValue(V);
855
856 if (Reg == 0)
857 return false;
858
859 Args.push_back(Reg);
860 }
861
Sam Clegga2725272019-04-19 22:43:32 +0000862 unsigned CalleeReg = 0;
863 if (!IsDirect) {
864 CalleeReg = getRegForValue(Call->getCalledValue());
865 if (!CalleeReg)
866 return false;
867 }
868
Dan Gohman33e694a2016-05-12 04:19:09 +0000869 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
870
871 if (!IsVoid)
872 MIB.addReg(ResultReg, RegState::Define);
873
874 if (IsDirect)
875 MIB.addGlobalAddress(Func);
Sam Clegga2725272019-04-19 22:43:32 +0000876 else
877 MIB.addReg(CalleeReg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000878
879 for (unsigned ArgReg : Args)
880 MIB.addReg(ArgReg);
881
882 if (!IsVoid)
883 updateValueMap(Call, ResultReg);
884 return true;
885}
886
887bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000888 const auto *Select = cast<SelectInst>(I);
Dan Gohman33e694a2016-05-12 04:19:09 +0000889
890 bool Not;
Heejin Ahnf208f632018-09-05 01:27:38 +0000891 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
Dan Gohman33e694a2016-05-12 04:19:09 +0000892 if (CondReg == 0)
893 return false;
894
Heejin Ahnf208f632018-09-05 01:27:38 +0000895 unsigned TrueReg = getRegForValue(Select->getTrueValue());
Dan Gohman33e694a2016-05-12 04:19:09 +0000896 if (TrueReg == 0)
897 return false;
898
899 unsigned FalseReg = getRegForValue(Select->getFalseValue());
900 if (FalseReg == 0)
901 return false;
902
903 if (Not)
904 std::swap(TrueReg, FalseReg);
905
906 unsigned Opc;
907 const TargetRegisterClass *RC;
908 switch (getSimpleType(Select->getType())) {
909 case MVT::i1:
910 case MVT::i8:
911 case MVT::i16:
912 case MVT::i32:
913 Opc = WebAssembly::SELECT_I32;
914 RC = &WebAssembly::I32RegClass;
915 break;
916 case MVT::i64:
917 Opc = WebAssembly::SELECT_I64;
918 RC = &WebAssembly::I64RegClass;
919 break;
920 case MVT::f32:
921 Opc = WebAssembly::SELECT_F32;
922 RC = &WebAssembly::F32RegClass;
923 break;
924 case MVT::f64:
925 Opc = WebAssembly::SELECT_F64;
926 RC = &WebAssembly::F64RegClass;
927 break;
Heejin Ahn9f96a582019-07-15 22:49:25 +0000928 case MVT::exnref:
929 Opc = WebAssembly::SELECT_EXNREF;
930 RC = &WebAssembly::EXNREFRegClass;
Heejin Ahn0de58722018-03-08 04:05:37 +0000931 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000932 default:
933 return false;
934 }
935
936 unsigned ResultReg = createResultReg(RC);
937 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Heejin Ahnf208f632018-09-05 01:27:38 +0000938 .addReg(TrueReg)
939 .addReg(FalseReg)
940 .addReg(CondReg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000941
942 updateValueMap(Select, ResultReg);
943 return true;
944}
945
946bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000947 const auto *Trunc = cast<TruncInst>(I);
Dan Gohman33e694a2016-05-12 04:19:09 +0000948
949 unsigned Reg = getRegForValue(Trunc->getOperand(0));
950 if (Reg == 0)
951 return false;
952
953 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
954 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
955 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
956 TII.get(WebAssembly::I32_WRAP_I64), Result)
957 .addReg(Reg);
958 Reg = Result;
959 }
960
961 updateValueMap(Trunc, Reg);
962 return true;
963}
964
Dan Gohman3a5ce732016-05-11 16:32:42 +0000965bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000966 const auto *ZExt = cast<ZExtInst>(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000967
Dan Gohman33e694a2016-05-12 04:19:09 +0000968 const Value *Op = ZExt->getOperand(0);
969 MVT::SimpleValueType From = getSimpleType(Op->getType());
970 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000971 unsigned In = getRegForValue(Op);
972 if (In == 0)
973 return false;
974 unsigned Reg = zeroExtend(In, Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000975 if (Reg == 0)
976 return false;
977
978 updateValueMap(ZExt, Reg);
979 return true;
980}
981
982bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000983 const auto *SExt = cast<SExtInst>(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000984
Dan Gohman33e694a2016-05-12 04:19:09 +0000985 const Value *Op = SExt->getOperand(0);
986 MVT::SimpleValueType From = getSimpleType(Op->getType());
987 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000988 unsigned In = getRegForValue(Op);
989 if (In == 0)
990 return false;
991 unsigned Reg = signExtend(In, Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000992 if (Reg == 0)
993 return false;
994
995 updateValueMap(SExt, Reg);
996 return true;
997}
998
999bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +00001000 const auto *ICmp = cast<ICmpInst>(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001001
1002 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1003 unsigned Opc;
Heejin Ahn18c56a02019-02-04 19:13:39 +00001004 bool IsSigned = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001005 switch (ICmp->getPredicate()) {
1006 case ICmpInst::ICMP_EQ:
1007 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1008 break;
1009 case ICmpInst::ICMP_NE:
1010 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1011 break;
1012 case ICmpInst::ICMP_UGT:
1013 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1014 break;
1015 case ICmpInst::ICMP_UGE:
1016 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1017 break;
1018 case ICmpInst::ICMP_ULT:
1019 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1020 break;
1021 case ICmpInst::ICMP_ULE:
1022 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1023 break;
1024 case ICmpInst::ICMP_SGT:
1025 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
Heejin Ahn18c56a02019-02-04 19:13:39 +00001026 IsSigned = true;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001027 break;
1028 case ICmpInst::ICMP_SGE:
1029 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
Heejin Ahn18c56a02019-02-04 19:13:39 +00001030 IsSigned = true;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001031 break;
1032 case ICmpInst::ICMP_SLT:
1033 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
Heejin Ahn18c56a02019-02-04 19:13:39 +00001034 IsSigned = true;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001035 break;
1036 case ICmpInst::ICMP_SLE:
1037 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
Heejin Ahn18c56a02019-02-04 19:13:39 +00001038 IsSigned = true;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001039 break;
Heejin Ahnf208f632018-09-05 01:27:38 +00001040 default:
1041 return false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001042 }
1043
Heejin Ahn18c56a02019-02-04 19:13:39 +00001044 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001045 if (LHS == 0)
1046 return false;
1047
Heejin Ahn18c56a02019-02-04 19:13:39 +00001048 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001049 if (RHS == 0)
1050 return false;
1051
1052 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1053 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1054 .addReg(LHS)
1055 .addReg(RHS);
1056 updateValueMap(ICmp, ResultReg);
1057 return true;
1058}
1059
1060bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +00001061 const auto *FCmp = cast<FCmpInst>(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001062
1063 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1064 if (LHS == 0)
1065 return false;
1066
1067 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1068 if (RHS == 0)
1069 return false;
1070
1071 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1072 unsigned Opc;
1073 bool Not = false;
1074 switch (FCmp->getPredicate()) {
1075 case FCmpInst::FCMP_OEQ:
1076 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1077 break;
1078 case FCmpInst::FCMP_UNE:
1079 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1080 break;
1081 case FCmpInst::FCMP_OGT:
1082 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1083 break;
1084 case FCmpInst::FCMP_OGE:
1085 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1086 break;
1087 case FCmpInst::FCMP_OLT:
1088 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1089 break;
1090 case FCmpInst::FCMP_OLE:
1091 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1092 break;
1093 case FCmpInst::FCMP_UGT:
1094 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1095 Not = true;
1096 break;
1097 case FCmpInst::FCMP_UGE:
1098 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1099 Not = true;
1100 break;
1101 case FCmpInst::FCMP_ULT:
1102 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1103 Not = true;
1104 break;
1105 case FCmpInst::FCMP_ULE:
1106 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1107 Not = true;
1108 break;
1109 default:
1110 return false;
1111 }
1112
1113 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1114 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1115 .addReg(LHS)
1116 .addReg(RHS);
1117
1118 if (Not)
1119 ResultReg = notValue(ResultReg);
1120
1121 updateValueMap(FCmp, ResultReg);
1122 return true;
1123}
1124
Dan Gohman2e644382016-05-10 17:39:48 +00001125bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1126 // Target-independent code can handle this, except it doesn't set the dead
1127 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1128 // to satisfy code that expects this of isBitcast() instructions.
1129 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1130 EVT RetVT = TLI.getValueType(DL, I->getType());
1131 if (!VT.isSimple() || !RetVT.isSimple())
1132 return false;
Dan Gohman33e694a2016-05-12 04:19:09 +00001133
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001134 unsigned In = getRegForValue(I->getOperand(0));
1135 if (In == 0)
1136 return false;
1137
Dan Gohman33e694a2016-05-12 04:19:09 +00001138 if (VT == RetVT) {
1139 // No-op bitcast.
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001140 updateValueMap(I, In);
Dan Gohman33e694a2016-05-12 04:19:09 +00001141 return true;
1142 }
1143
Dan Gohman2e644382016-05-10 17:39:48 +00001144 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001145 In, I->getOperand(0)->hasOneUse());
Dan Gohman2e644382016-05-10 17:39:48 +00001146 if (!Reg)
1147 return false;
1148 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1149 --Iter;
1150 assert(Iter->isBitcast());
1151 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1152 updateValueMap(I, Reg);
1153 return true;
1154}
1155
1156bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +00001157 const auto *Load = cast<LoadInst>(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001158 if (Load->isAtomic())
1159 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001160 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1161 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001162
1163 Address Addr;
1164 if (!computeAddress(Load->getPointerOperand(), Addr))
1165 return false;
1166
1167 // TODO: Fold a following sign-/zero-extend into the load instruction.
1168
1169 unsigned Opc;
1170 const TargetRegisterClass *RC;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001171 switch (getSimpleType(Load->getType())) {
1172 case MVT::i1:
1173 case MVT::i8:
1174 Opc = WebAssembly::LOAD8_U_I32;
1175 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +00001176 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001177 case MVT::i16:
1178 Opc = WebAssembly::LOAD16_U_I32;
1179 RC = &WebAssembly::I32RegClass;
1180 break;
1181 case MVT::i32:
1182 Opc = WebAssembly::LOAD_I32;
1183 RC = &WebAssembly::I32RegClass;
1184 break;
1185 case MVT::i64:
1186 Opc = WebAssembly::LOAD_I64;
1187 RC = &WebAssembly::I64RegClass;
1188 break;
1189 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001190 Opc = WebAssembly::LOAD_F32;
1191 RC = &WebAssembly::F32RegClass;
1192 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001193 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001194 Opc = WebAssembly::LOAD_F64;
1195 RC = &WebAssembly::F64RegClass;
1196 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001197 default:
1198 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001199 }
1200
Sam Clegg9da81422019-04-23 03:43:26 +00001201 materializeLoadStoreOperands(Addr);
Dan Gohman2e644382016-05-10 17:39:48 +00001202
1203 unsigned ResultReg = createResultReg(RC);
1204 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1205 ResultReg);
1206
1207 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1208
1209 updateValueMap(Load, ResultReg);
1210 return true;
1211}
1212
1213bool WebAssemblyFastISel::selectStore(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +00001214 const auto *Store = cast<StoreInst>(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001215 if (Store->isAtomic())
1216 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001217 if (!Subtarget->hasSIMD128() &&
1218 Store->getValueOperand()->getType()->isVectorTy())
1219 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001220
1221 Address Addr;
1222 if (!computeAddress(Store->getPointerOperand(), Addr))
1223 return false;
1224
1225 unsigned Opc;
Dan Gohman2e644382016-05-10 17:39:48 +00001226 bool VTIsi1 = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001227 switch (getSimpleType(Store->getValueOperand()->getType())) {
1228 case MVT::i1:
1229 VTIsi1 = true;
Dan Gohman861bec22018-02-09 22:59:01 +00001230 LLVM_FALLTHROUGH;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001231 case MVT::i8:
1232 Opc = WebAssembly::STORE8_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001233 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001234 case MVT::i16:
1235 Opc = WebAssembly::STORE16_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001236 break;
1237 case MVT::i32:
1238 Opc = WebAssembly::STORE_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001239 break;
1240 case MVT::i64:
1241 Opc = WebAssembly::STORE_I64;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001242 break;
1243 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001244 Opc = WebAssembly::STORE_F32;
Dan Gohman2e644382016-05-10 17:39:48 +00001245 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001246 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001247 Opc = WebAssembly::STORE_F64;
Dan Gohman2e644382016-05-10 17:39:48 +00001248 break;
Heejin Ahnf208f632018-09-05 01:27:38 +00001249 default:
1250 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001251 }
1252
Sam Clegg9da81422019-04-23 03:43:26 +00001253 materializeLoadStoreOperands(Addr);
Dan Gohman2e644382016-05-10 17:39:48 +00001254
1255 unsigned ValueReg = getRegForValue(Store->getValueOperand());
Derek Schuff732636d2016-08-04 18:01:52 +00001256 if (ValueReg == 0)
1257 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001258 if (VTIsi1)
Dan Gohman3a5ce732016-05-11 16:32:42 +00001259 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
Dan Gohman2e644382016-05-10 17:39:48 +00001260
Dan Gohman7f1bdb22016-10-06 22:08:28 +00001261 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
Dan Gohman2e644382016-05-10 17:39:48 +00001262
1263 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1264
1265 MIB.addReg(ValueReg);
1266 return true;
1267}
1268
1269bool WebAssemblyFastISel::selectBr(const Instruction *I) {
Heejin Ahn18c56a02019-02-04 19:13:39 +00001270 const auto *Br = cast<BranchInst>(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001271 if (Br->isUnconditional()) {
1272 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1273 fastEmitBranch(MSucc, Br->getDebugLoc());
1274 return true;
1275 }
1276
1277 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1278 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1279
Dan Gohman33e694a2016-05-12 04:19:09 +00001280 bool Not;
1281 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
Derek Schuff732636d2016-08-04 18:01:52 +00001282 if (CondReg == 0)
1283 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001284
Dan Gohman33e694a2016-05-12 04:19:09 +00001285 unsigned Opc = WebAssembly::BR_IF;
1286 if (Not)
1287 Opc = WebAssembly::BR_UNLESS;
1288
Dan Gohman2e644382016-05-10 17:39:48 +00001289 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1290 .addMBB(TBB)
1291 .addReg(CondReg);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001292
Dan Gohman2e644382016-05-10 17:39:48 +00001293 finishCondBranch(Br->getParent(), TBB, FBB);
1294 return true;
1295}
1296
1297bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1298 if (!FuncInfo.CanLowerReturn)
1299 return false;
1300
Heejin Ahn18c56a02019-02-04 19:13:39 +00001301 const auto *Ret = cast<ReturnInst>(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001302
1303 if (Ret->getNumOperands() == 0) {
1304 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1305 TII.get(WebAssembly::RETURN_VOID));
1306 return true;
1307 }
1308
1309 Value *RV = Ret->getOperand(0);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001310 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1311 return false;
1312
Dan Gohman2e644382016-05-10 17:39:48 +00001313 unsigned Opc;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001314 switch (getSimpleType(RV->getType())) {
Heejin Ahnf208f632018-09-05 01:27:38 +00001315 case MVT::i1:
1316 case MVT::i8:
1317 case MVT::i16:
1318 case MVT::i32:
Dan Gohman3a5ce732016-05-11 16:32:42 +00001319 Opc = WebAssembly::RETURN_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001320 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001321 case MVT::i64:
1322 Opc = WebAssembly::RETURN_I64;
1323 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001324 case MVT::f32:
1325 Opc = WebAssembly::RETURN_F32;
1326 break;
1327 case MVT::f64:
1328 Opc = WebAssembly::RETURN_F64;
1329 break;
1330 case MVT::v16i8:
1331 Opc = WebAssembly::RETURN_v16i8;
1332 break;
1333 case MVT::v8i16:
1334 Opc = WebAssembly::RETURN_v8i16;
1335 break;
1336 case MVT::v4i32:
1337 Opc = WebAssembly::RETURN_v4i32;
1338 break;
Derek Schuff51ed1312018-08-07 21:24:01 +00001339 case MVT::v2i64:
1340 Opc = WebAssembly::RETURN_v2i64;
1341 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001342 case MVT::v4f32:
1343 Opc = WebAssembly::RETURN_v4f32;
1344 break;
Derek Schuff51ed1312018-08-07 21:24:01 +00001345 case MVT::v2f64:
1346 Opc = WebAssembly::RETURN_v2f64;
1347 break;
Heejin Ahn9f96a582019-07-15 22:49:25 +00001348 case MVT::exnref:
1349 Opc = WebAssembly::RETURN_EXNREF;
Heejin Ahn0de58722018-03-08 04:05:37 +00001350 break;
Heejin Ahnf208f632018-09-05 01:27:38 +00001351 default:
1352 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001353 }
1354
Dan Gohman33e694a2016-05-12 04:19:09 +00001355 unsigned Reg;
1356 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1357 Reg = getRegForSignedValue(RV);
1358 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1359 Reg = getRegForUnsignedValue(RV);
1360 else
1361 Reg = getRegForValue(RV);
1362
Derek Schuff732636d2016-08-04 18:01:52 +00001363 if (Reg == 0)
1364 return false;
1365
Dan Gohman2e644382016-05-10 17:39:48 +00001366 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1367 return true;
1368}
1369
1370bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1371 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1372 TII.get(WebAssembly::UNREACHABLE));
1373 return true;
1374}
1375
1376bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1377 switch (I->getOpcode()) {
Dan Gohman33e694a2016-05-12 04:19:09 +00001378 case Instruction::Call:
1379 if (selectCall(I))
1380 return true;
1381 break;
Heejin Ahnf208f632018-09-05 01:27:38 +00001382 case Instruction::Select:
1383 return selectSelect(I);
1384 case Instruction::Trunc:
1385 return selectTrunc(I);
1386 case Instruction::ZExt:
1387 return selectZExt(I);
1388 case Instruction::SExt:
1389 return selectSExt(I);
1390 case Instruction::ICmp:
1391 return selectICmp(I);
1392 case Instruction::FCmp:
1393 return selectFCmp(I);
1394 case Instruction::BitCast:
1395 return selectBitCast(I);
1396 case Instruction::Load:
1397 return selectLoad(I);
1398 case Instruction::Store:
1399 return selectStore(I);
1400 case Instruction::Br:
1401 return selectBr(I);
1402 case Instruction::Ret:
1403 return selectRet(I);
1404 case Instruction::Unreachable:
1405 return selectUnreachable(I);
1406 default:
1407 break;
Dan Gohman7b634842015-08-24 18:44:37 +00001408 }
1409
1410 // Fall back to target-independent instruction selection.
1411 return selectOperator(I, I->getOpcode());
1412}
1413
1414FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1415 const TargetLibraryInfo *LibInfo) {
1416 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1417}