blob: bc7020fded8c9729cf292f08164432ea9639b247 [file] [log] [blame]
Dan Gohman7b634842015-08-24 18:44:37 +00001//===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file defines the WebAssembly-specific support for the FastISel
12/// class. Some of the target-specific code is generated by tablegen in the file
13/// WebAssemblyGenFastISel.inc, which is #included here.
14///
Dan Gohman33e694a2016-05-12 04:19:09 +000015/// TODO: kill flags
16///
Dan Gohman7b634842015-08-24 18:44:37 +000017//===----------------------------------------------------------------------===//
18
19#include "WebAssembly.h"
20#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
Dan Gohman33e694a2016-05-12 04:19:09 +000021#include "WebAssemblyMachineFunctionInfo.h"
Dan Gohman7b634842015-08-24 18:44:37 +000022#include "WebAssemblySubtarget.h"
23#include "WebAssemblyTargetMachine.h"
24#include "llvm/Analysis/BranchProbabilityInfo.h"
25#include "llvm/CodeGen/FastISel.h"
26#include "llvm/CodeGen/FunctionLoweringInfo.h"
27#include "llvm/CodeGen/MachineConstantPool.h"
28#include "llvm/CodeGen/MachineFrameInfo.h"
29#include "llvm/CodeGen/MachineInstrBuilder.h"
30#include "llvm/CodeGen/MachineRegisterInfo.h"
31#include "llvm/IR/DataLayout.h"
32#include "llvm/IR/DerivedTypes.h"
33#include "llvm/IR/Function.h"
34#include "llvm/IR/GetElementPtrTypeIterator.h"
35#include "llvm/IR/GlobalAlias.h"
36#include "llvm/IR/GlobalVariable.h"
37#include "llvm/IR/Instructions.h"
38#include "llvm/IR/IntrinsicInst.h"
39#include "llvm/IR/Operator.h"
40using namespace llvm;
41
42#define DEBUG_TYPE "wasm-fastisel"
43
44namespace {
45
46class WebAssemblyFastISel final : public FastISel {
Dan Gohman2e644382016-05-10 17:39:48 +000047 // All possible address modes.
48 class Address {
49 public:
50 typedef enum { RegBase, FrameIndexBase } BaseKind;
51
52 private:
53 BaseKind Kind;
54 union {
55 unsigned Reg;
56 int FI;
57 } Base;
58
59 int64_t Offset;
60
61 const GlobalValue *GV;
62
63 public:
64 // Innocuous defaults for our address.
65 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; }
66 void setKind(BaseKind K) { Kind = K; }
67 BaseKind getKind() const { return Kind; }
68 bool isRegBase() const { return Kind == RegBase; }
69 bool isFIBase() const { return Kind == FrameIndexBase; }
70 void setReg(unsigned Reg) {
71 assert(isRegBase() && "Invalid base register access!");
72 Base.Reg = Reg;
73 }
74 unsigned getReg() const {
75 assert(isRegBase() && "Invalid base register access!");
76 return Base.Reg;
77 }
78 void setFI(unsigned FI) {
79 assert(isFIBase() && "Invalid base frame index access!");
80 Base.FI = FI;
81 }
82 unsigned getFI() const {
83 assert(isFIBase() && "Invalid base frame index access!");
84 return Base.FI;
85 }
86
Dan Gohman728926a2016-12-22 15:15:10 +000087 void setOffset(int64_t Offset_) {
88 assert(Offset_ >= 0 && "Offsets must be non-negative");
89 Offset = Offset_;
90 }
Dan Gohman2e644382016-05-10 17:39:48 +000091 int64_t getOffset() const { return Offset; }
92 void setGlobalValue(const GlobalValue *G) { GV = G; }
93 const GlobalValue *getGlobalValue() const { return GV; }
94 };
95
Dan Gohman7b634842015-08-24 18:44:37 +000096 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
97 /// right decision when generating code for different targets.
98 const WebAssemblySubtarget *Subtarget;
99 LLVMContext *Context;
100
Dan Gohman7b634842015-08-24 18:44:37 +0000101private:
Dan Gohman2e644382016-05-10 17:39:48 +0000102 // Utility helper routines
Dan Gohman3a5ce732016-05-11 16:32:42 +0000103 MVT::SimpleValueType getSimpleType(Type *Ty) {
104 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
105 return VT.isSimple() ? VT.getSimpleVT().SimpleTy :
106 MVT::INVALID_SIMPLE_VALUE_TYPE;
107 }
108 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
109 switch (VT) {
110 case MVT::i1:
111 case MVT::i8:
112 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000113 return MVT::i32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000114 case MVT::i32:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000115 case MVT::i64:
Dan Gohman33e694a2016-05-12 04:19:09 +0000116 case MVT::f32:
117 case MVT::f64:
118 return VT;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000119 case MVT::v16i8:
120 case MVT::v8i16:
121 case MVT::v4i32:
122 case MVT::v4f32:
123 if (Subtarget->hasSIMD128())
124 return VT;
125 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000126 default:
127 break;
128 }
129 return MVT::INVALID_SIMPLE_VALUE_TYPE;
130 }
Dan Gohman2e644382016-05-10 17:39:48 +0000131 bool computeAddress(const Value *Obj, Address &Addr);
132 void materializeLoadStoreOperands(Address &Addr);
133 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
134 MachineMemOperand *MMO);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000135 unsigned maskI1Value(unsigned Reg, const Value *V);
Dan Gohman33e694a2016-05-12 04:19:09 +0000136 unsigned getRegForI1Value(const Value *V, bool &Not);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000137 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
138 MVT::SimpleValueType From);
139 unsigned signExtendToI32(unsigned Reg, const Value *V,
140 MVT::SimpleValueType From);
141 unsigned zeroExtend(unsigned Reg, const Value *V,
142 MVT::SimpleValueType From,
143 MVT::SimpleValueType To);
144 unsigned signExtend(unsigned Reg, const Value *V,
145 MVT::SimpleValueType From,
146 MVT::SimpleValueType To);
147 unsigned getRegForUnsignedValue(const Value *V);
148 unsigned getRegForSignedValue(const Value *V);
149 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
150 unsigned notValue(unsigned Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000151 unsigned copyValue(unsigned Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000152
153 // Backend specific FastISel code.
154 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
155 unsigned fastMaterializeConstant(const Constant *C) override;
Dan Gohman33e694a2016-05-12 04:19:09 +0000156 bool fastLowerArguments() override;
Dan Gohman2e644382016-05-10 17:39:48 +0000157
158 // Selection routines.
Dan Gohman33e694a2016-05-12 04:19:09 +0000159 bool selectCall(const Instruction *I);
160 bool selectSelect(const Instruction *I);
161 bool selectTrunc(const Instruction *I);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000162 bool selectZExt(const Instruction *I);
163 bool selectSExt(const Instruction *I);
164 bool selectICmp(const Instruction *I);
165 bool selectFCmp(const Instruction *I);
Dan Gohman2e644382016-05-10 17:39:48 +0000166 bool selectBitCast(const Instruction *I);
167 bool selectLoad(const Instruction *I);
168 bool selectStore(const Instruction *I);
169 bool selectBr(const Instruction *I);
170 bool selectRet(const Instruction *I);
171 bool selectUnreachable(const Instruction *I);
172
Dan Gohman7b634842015-08-24 18:44:37 +0000173public:
174 // Backend specific FastISel code.
175 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
176 const TargetLibraryInfo *LibInfo)
177 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
178 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
179 Context = &FuncInfo.Fn->getContext();
180 }
181
182 bool fastSelectInstruction(const Instruction *I) override;
183
184#include "WebAssemblyGenFastISel.inc"
185};
186
187} // end anonymous namespace
188
Dan Gohman2e644382016-05-10 17:39:48 +0000189bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
190
191 const User *U = nullptr;
192 unsigned Opcode = Instruction::UserOp1;
193 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
194 // Don't walk into other basic blocks unless the object is an alloca from
195 // another block, otherwise it may not have a virtual register assigned.
196 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
197 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
198 Opcode = I->getOpcode();
199 U = I;
200 }
201 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
202 Opcode = C->getOpcode();
203 U = C;
204 }
205
206 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
207 if (Ty->getAddressSpace() > 255)
208 // Fast instruction selection doesn't support the special
209 // address spaces.
210 return false;
211
212 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
213 if (Addr.getGlobalValue())
214 return false;
215 Addr.setGlobalValue(GV);
216 return true;
217 }
218
219 switch (Opcode) {
Dan Gohman7b634842015-08-24 18:44:37 +0000220 default:
221 break;
Dan Gohman2e644382016-05-10 17:39:48 +0000222 case Instruction::BitCast: {
223 // Look through bitcasts.
224 return computeAddress(U->getOperand(0), Addr);
225 }
226 case Instruction::IntToPtr: {
227 // Look past no-op inttoptrs.
228 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
229 TLI.getPointerTy(DL))
230 return computeAddress(U->getOperand(0), Addr);
231 break;
232 }
233 case Instruction::PtrToInt: {
234 // Look past no-op ptrtoints.
235 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
236 return computeAddress(U->getOperand(0), Addr);
237 break;
238 }
239 case Instruction::GetElementPtr: {
240 Address SavedAddr = Addr;
241 uint64_t TmpOffset = Addr.getOffset();
Dan Gohman728926a2016-12-22 15:15:10 +0000242 // Non-inbounds geps can wrap; wasm's offsets can't.
243 if (!cast<GEPOperator>(U)->isInBounds())
244 goto unsupported_gep;
Dan Gohman2e644382016-05-10 17:39:48 +0000245 // Iterate through the GEP folding the constants into offsets where
246 // we can.
Dan Gohman33e694a2016-05-12 04:19:09 +0000247 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
Dan Gohman2e644382016-05-10 17:39:48 +0000248 GTI != E; ++GTI) {
249 const Value *Op = GTI.getOperand();
Peter Collingbourneab85225b2016-12-02 02:24:42 +0000250 if (StructType *STy = GTI.getStructTypeOrNull()) {
Dan Gohman2e644382016-05-10 17:39:48 +0000251 const StructLayout *SL = DL.getStructLayout(STy);
252 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
253 TmpOffset += SL->getElementOffset(Idx);
254 } else {
255 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
256 for (;;) {
257 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
258 // Constant-offset addressing.
259 TmpOffset += CI->getSExtValue() * S;
260 break;
261 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000262 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
263 // An unscaled add of a register. Set it as the new base.
264 Addr.setReg(getRegForValue(Op));
265 break;
266 }
Dan Gohman2e644382016-05-10 17:39:48 +0000267 if (canFoldAddIntoGEP(U, Op)) {
268 // A compatible add with a constant operand. Fold the constant.
269 ConstantInt *CI =
270 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
271 TmpOffset += CI->getSExtValue() * S;
272 // Iterate on the other operand.
273 Op = cast<AddOperator>(Op)->getOperand(0);
274 continue;
275 }
276 // Unsupported
277 goto unsupported_gep;
278 }
279 }
280 }
Dan Gohman728926a2016-12-22 15:15:10 +0000281 // Don't fold in negative offsets.
282 if (int64_t(TmpOffset) >= 0) {
283 // Try to grab the base operand now.
284 Addr.setOffset(TmpOffset);
285 if (computeAddress(U->getOperand(0), Addr))
286 return true;
287 }
Dan Gohman2e644382016-05-10 17:39:48 +0000288 // We failed, restore everything and try the other options.
289 Addr = SavedAddr;
290 unsupported_gep:
291 break;
292 }
293 case Instruction::Alloca: {
294 const AllocaInst *AI = cast<AllocaInst>(Obj);
295 DenseMap<const AllocaInst *, int>::iterator SI =
296 FuncInfo.StaticAllocaMap.find(AI);
297 if (SI != FuncInfo.StaticAllocaMap.end()) {
298 Addr.setKind(Address::FrameIndexBase);
299 Addr.setFI(SI->second);
300 return true;
301 }
302 break;
303 }
304 case Instruction::Add: {
305 // Adds of constants are common and easy enough.
306 const Value *LHS = U->getOperand(0);
307 const Value *RHS = U->getOperand(1);
308
309 if (isa<ConstantInt>(LHS))
310 std::swap(LHS, RHS);
311
312 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000313 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
314 if (int64_t(TmpOffset) >= 0) {
315 Addr.setOffset(TmpOffset);
316 return computeAddress(LHS, Addr);
317 }
Dan Gohman2e644382016-05-10 17:39:48 +0000318 }
319
320 Address Backup = Addr;
321 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
322 return true;
323 Addr = Backup;
324
325 break;
326 }
327 case Instruction::Sub: {
328 // Subs of constants are common and easy enough.
329 const Value *LHS = U->getOperand(0);
330 const Value *RHS = U->getOperand(1);
331
332 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000333 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
334 if (TmpOffset >= 0) {
335 Addr.setOffset(TmpOffset);
336 return computeAddress(LHS, Addr);
337 }
Dan Gohman2e644382016-05-10 17:39:48 +0000338 }
339 break;
340 }
341 }
342 Addr.setReg(getRegForValue(Obj));
343 return Addr.getReg() != 0;
344}
345
346void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
347 if (Addr.isRegBase()) {
348 unsigned Reg = Addr.getReg();
349 if (Reg == 0) {
350 Reg = createResultReg(Subtarget->hasAddr64() ?
351 &WebAssembly::I64RegClass :
352 &WebAssembly::I32RegClass);
353 unsigned Opc = Subtarget->hasAddr64() ?
354 WebAssembly::CONST_I64 :
355 WebAssembly::CONST_I32;
356 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
357 .addImm(0);
358 Addr.setReg(Reg);
359 }
360 }
361}
362
363void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
364 const MachineInstrBuilder &MIB,
365 MachineMemOperand *MMO) {
Dan Gohman48abaa92016-10-25 00:17:11 +0000366 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
367 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
368 MIB.addImm(0);
369
Dan Gohman2e644382016-05-10 17:39:48 +0000370 if (const GlobalValue *GV = Addr.getGlobalValue())
371 MIB.addGlobalAddress(GV, Addr.getOffset());
372 else
373 MIB.addImm(Addr.getOffset());
374
375 if (Addr.isRegBase())
376 MIB.addReg(Addr.getReg());
377 else
378 MIB.addFrameIndex(Addr.getFI());
379
Dan Gohman2e644382016-05-10 17:39:48 +0000380 MIB.addMemOperand(MMO);
381}
382
Dan Gohman3a5ce732016-05-11 16:32:42 +0000383unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
384 return zeroExtendToI32(Reg, V, MVT::i1);
Dan Gohman2e644382016-05-10 17:39:48 +0000385}
386
Dan Gohman33e694a2016-05-12 04:19:09 +0000387unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
388 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
389 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
390 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
391 Not = ICmp->isTrueWhenEqual();
392 return getRegForValue(ICmp->getOperand(0));
393 }
394
395 if (BinaryOperator::isNot(V)) {
396 Not = true;
397 return getRegForValue(BinaryOperator::getNotArgument(V));
398 }
399
400 Not = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000401 return maskI1Value(getRegForValue(V), V);
402}
403
404unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
405 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000406 if (Reg == 0)
407 return 0;
408
Dan Gohman3a5ce732016-05-11 16:32:42 +0000409 switch (From) {
410 case MVT::i1:
411 // If the value is naturally an i1, we don't need to mask it.
412 // TODO: Recursively examine selects, phis, and, or, xor, constants.
Dan Gohman33e694a2016-05-12 04:19:09 +0000413 if (From == MVT::i1 && V != nullptr) {
414 if (isa<CmpInst>(V) ||
415 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
416 return copyValue(Reg);
417 }
418 case MVT::i8:
419 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000420 break;
421 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000422 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000423 default:
424 return 0;
425 }
426
427 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
428 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
429 TII.get(WebAssembly::CONST_I32), Imm)
430 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
431
432 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
433 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
434 TII.get(WebAssembly::AND_I32), Result)
435 .addReg(Reg)
436 .addReg(Imm);
437
438 return Result;
439}
440
441unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
442 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000443 if (Reg == 0)
444 return 0;
445
Dan Gohman3a5ce732016-05-11 16:32:42 +0000446 switch (From) {
447 case MVT::i1:
448 case MVT::i8:
449 case MVT::i16:
450 break;
451 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000452 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000453 default:
Dan Gohman33e694a2016-05-12 04:19:09 +0000454 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000455 }
456
457 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
458 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
459 TII.get(WebAssembly::CONST_I32), Imm)
460 .addImm(32 - MVT(From).getSizeInBits());
461
462 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
463 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
464 TII.get(WebAssembly::SHL_I32), Left)
465 .addReg(Reg)
466 .addReg(Imm);
467
468 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
469 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
470 TII.get(WebAssembly::SHR_S_I32), Right)
471 .addReg(Left)
472 .addReg(Imm);
473
474 return Right;
475}
476
477unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
478 MVT::SimpleValueType From,
479 MVT::SimpleValueType To) {
480 if (To == MVT::i64) {
481 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000482 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000483
484 Reg = zeroExtendToI32(Reg, V, From);
485
486 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
487 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
488 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
489 .addReg(Reg);
490 return Result;
491 }
492
Dan Gohman3a5ce732016-05-11 16:32:42 +0000493 return zeroExtendToI32(Reg, V, From);
494}
495
496unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
497 MVT::SimpleValueType From,
498 MVT::SimpleValueType To) {
499 if (To == MVT::i64) {
500 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000501 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000502
503 Reg = signExtendToI32(Reg, V, From);
504
505 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
506 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
507 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
508 .addReg(Reg);
509 return Result;
510 }
511
Dan Gohman3a5ce732016-05-11 16:32:42 +0000512 return signExtendToI32(Reg, V, From);
513}
514
515unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
516 MVT::SimpleValueType From = getSimpleType(V->getType());
517 MVT::SimpleValueType To = getLegalType(From);
518 return zeroExtend(getRegForValue(V), V, From, To);
519}
520
521unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
522 MVT::SimpleValueType From = getSimpleType(V->getType());
523 MVT::SimpleValueType To = getLegalType(From);
524 return zeroExtend(getRegForValue(V), V, From, To);
525}
526
527unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
528 bool IsSigned) {
529 return IsSigned ? getRegForSignedValue(V) :
530 getRegForUnsignedValue(V);
531}
532
533unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000534 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
535
Dan Gohman3a5ce732016-05-11 16:32:42 +0000536 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
537 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
538 TII.get(WebAssembly::EQZ_I32), NotReg)
539 .addReg(Reg);
540 return NotReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000541}
542
Dan Gohman33e694a2016-05-12 04:19:09 +0000543unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
544 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
545 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
546 TII.get(WebAssembly::COPY), ResultReg)
547 .addReg(Reg);
548 return ResultReg;
549}
550
Dan Gohman2e644382016-05-10 17:39:48 +0000551unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
552 DenseMap<const AllocaInst *, int>::iterator SI =
553 FuncInfo.StaticAllocaMap.find(AI);
554
555 if (SI != FuncInfo.StaticAllocaMap.end()) {
556 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
557 &WebAssembly::I64RegClass :
558 &WebAssembly::I32RegClass);
559 unsigned Opc = Subtarget->hasAddr64() ?
Dan Gohman4fc4e422016-10-24 19:49:43 +0000560 WebAssembly::COPY_I64 :
561 WebAssembly::COPY_I32;
Dan Gohman2e644382016-05-10 17:39:48 +0000562 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
563 .addFrameIndex(SI->second);
564 return ResultReg;
565 }
566
567 return 0;
568}
569
570unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
571 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000572 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
573 &WebAssembly::I64RegClass :
574 &WebAssembly::I32RegClass);
Dan Gohman2e644382016-05-10 17:39:48 +0000575 unsigned Opc = Subtarget->hasAddr64() ?
576 WebAssembly::CONST_I64 :
577 WebAssembly::CONST_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000578 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Dan Gohman2e644382016-05-10 17:39:48 +0000579 .addGlobalAddress(GV);
Dan Gohman33e694a2016-05-12 04:19:09 +0000580 return ResultReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000581 }
582
583 // Let target-independent code handle it.
584 return 0;
585}
586
Dan Gohman33e694a2016-05-12 04:19:09 +0000587bool WebAssemblyFastISel::fastLowerArguments() {
588 if (!FuncInfo.CanLowerReturn)
589 return false;
590
591 const Function *F = FuncInfo.Fn;
592 if (F->isVarArg())
593 return false;
594
595 unsigned i = 0;
596 for (auto const &Arg : F->args()) {
597 const AttributeSet &Attrs = F->getAttributes();
598 if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
599 Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
600 Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
601 Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
602 Attrs.hasAttribute(i+1, Attribute::Nest))
603 return false;
604
605 Type *ArgTy = Arg.getType();
Derek Schuff39bf39f2016-08-02 23:16:09 +0000606 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
607 return false;
608 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
Dan Gohman33e694a2016-05-12 04:19:09 +0000609 return false;
610
611 unsigned Opc;
612 const TargetRegisterClass *RC;
613 switch (getSimpleType(ArgTy)) {
614 case MVT::i1:
615 case MVT::i8:
616 case MVT::i16:
617 case MVT::i32:
618 Opc = WebAssembly::ARGUMENT_I32;
619 RC = &WebAssembly::I32RegClass;
620 break;
621 case MVT::i64:
622 Opc = WebAssembly::ARGUMENT_I64;
623 RC = &WebAssembly::I64RegClass;
624 break;
625 case MVT::f32:
626 Opc = WebAssembly::ARGUMENT_F32;
627 RC = &WebAssembly::F32RegClass;
628 break;
629 case MVT::f64:
630 Opc = WebAssembly::ARGUMENT_F64;
631 RC = &WebAssembly::F64RegClass;
632 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000633 case MVT::v16i8:
634 Opc = WebAssembly::ARGUMENT_v16i8;
635 RC = &WebAssembly::V128RegClass;
636 break;
637 case MVT::v8i16:
638 Opc = WebAssembly::ARGUMENT_v8i16;
639 RC = &WebAssembly::V128RegClass;
640 break;
641 case MVT::v4i32:
642 Opc = WebAssembly::ARGUMENT_v4i32;
643 RC = &WebAssembly::V128RegClass;
644 break;
645 case MVT::v4f32:
646 Opc = WebAssembly::ARGUMENT_v4f32;
647 RC = &WebAssembly::V128RegClass;
648 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000649 default:
650 return false;
651 }
652 unsigned ResultReg = createResultReg(RC);
653 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
654 .addImm(i);
655 updateValueMap(&Arg, ResultReg);
656
657 ++i;
658 }
659
660 MRI.addLiveIn(WebAssembly::ARGUMENTS);
661
662 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
663 for (auto const &Arg : F->args())
664 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
665
Dan Gohman6055fba2017-01-09 23:09:38 +0000666 if (!F->getReturnType()->isVoidTy())
667 MFI->addResult(getLegalType(getSimpleType(F->getReturnType())));
668
Dan Gohman33e694a2016-05-12 04:19:09 +0000669 return true;
670}
671
672bool WebAssemblyFastISel::selectCall(const Instruction *I) {
673 const CallInst *Call = cast<CallInst>(I);
674
675 if (Call->isMustTailCall() || Call->isInlineAsm() ||
676 Call->getFunctionType()->isVarArg())
677 return false;
678
679 Function *Func = Call->getCalledFunction();
680 if (Func && Func->isIntrinsic())
681 return false;
682
683 FunctionType *FuncTy = Call->getFunctionType();
684 unsigned Opc;
685 bool IsDirect = Func != nullptr;
686 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
687 unsigned ResultReg;
688 if (IsVoid) {
Derek Schuff6f697832016-10-21 16:38:07 +0000689 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
Dan Gohman33e694a2016-05-12 04:19:09 +0000690 } else {
Derek Schuff39bf39f2016-08-02 23:16:09 +0000691 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
692 return false;
693
Dan Gohman33e694a2016-05-12 04:19:09 +0000694 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
695 switch (RetTy) {
696 case MVT::i1:
697 case MVT::i8:
698 case MVT::i16:
699 case MVT::i32:
Derek Schuff6f697832016-10-21 16:38:07 +0000700 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000701 ResultReg = createResultReg(&WebAssembly::I32RegClass);
702 break;
703 case MVT::i64:
Derek Schuff6f697832016-10-21 16:38:07 +0000704 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000705 ResultReg = createResultReg(&WebAssembly::I64RegClass);
706 break;
707 case MVT::f32:
Derek Schuff6f697832016-10-21 16:38:07 +0000708 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000709 ResultReg = createResultReg(&WebAssembly::F32RegClass);
710 break;
711 case MVT::f64:
Derek Schuff6f697832016-10-21 16:38:07 +0000712 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000713 ResultReg = createResultReg(&WebAssembly::F64RegClass);
714 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000715 case MVT::v16i8:
716 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000717 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000718 ResultReg = createResultReg(&WebAssembly::V128RegClass);
719 break;
720 case MVT::v8i16:
721 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000722 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000723 ResultReg = createResultReg(&WebAssembly::V128RegClass);
724 break;
725 case MVT::v4i32:
726 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000727 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000728 ResultReg = createResultReg(&WebAssembly::V128RegClass);
729 break;
730 case MVT::v4f32:
731 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000732 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000733 ResultReg = createResultReg(&WebAssembly::V128RegClass);
734 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000735 default:
736 return false;
737 }
738 }
739
740 SmallVector<unsigned, 8> Args;
741 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
742 Value *V = Call->getArgOperand(i);
743 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
744 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
745 return false;
746
747 const AttributeSet &Attrs = Call->getAttributes();
748 if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
749 Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
750 Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
751 Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
752 Attrs.hasAttribute(i+1, Attribute::Nest))
753 return false;
754
755 unsigned Reg;
756
757 if (Attrs.hasAttribute(i+1, Attribute::SExt))
758 Reg = getRegForSignedValue(V);
759 else if (Attrs.hasAttribute(i+1, Attribute::ZExt))
760 Reg = getRegForUnsignedValue(V);
761 else
762 Reg = getRegForValue(V);
763
764 if (Reg == 0)
765 return false;
766
767 Args.push_back(Reg);
768 }
769
770 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
771
772 if (!IsVoid)
773 MIB.addReg(ResultReg, RegState::Define);
774
775 if (IsDirect)
776 MIB.addGlobalAddress(Func);
777 else
778 MIB.addReg(getRegForValue(Call->getCalledValue()));
779
780 for (unsigned ArgReg : Args)
781 MIB.addReg(ArgReg);
782
783 if (!IsVoid)
784 updateValueMap(Call, ResultReg);
785 return true;
786}
787
788bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
789 const SelectInst *Select = cast<SelectInst>(I);
790
791 bool Not;
792 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
793 if (CondReg == 0)
794 return false;
795
796 unsigned TrueReg = getRegForValue(Select->getTrueValue());
797 if (TrueReg == 0)
798 return false;
799
800 unsigned FalseReg = getRegForValue(Select->getFalseValue());
801 if (FalseReg == 0)
802 return false;
803
804 if (Not)
805 std::swap(TrueReg, FalseReg);
806
807 unsigned Opc;
808 const TargetRegisterClass *RC;
809 switch (getSimpleType(Select->getType())) {
810 case MVT::i1:
811 case MVT::i8:
812 case MVT::i16:
813 case MVT::i32:
814 Opc = WebAssembly::SELECT_I32;
815 RC = &WebAssembly::I32RegClass;
816 break;
817 case MVT::i64:
818 Opc = WebAssembly::SELECT_I64;
819 RC = &WebAssembly::I64RegClass;
820 break;
821 case MVT::f32:
822 Opc = WebAssembly::SELECT_F32;
823 RC = &WebAssembly::F32RegClass;
824 break;
825 case MVT::f64:
826 Opc = WebAssembly::SELECT_F64;
827 RC = &WebAssembly::F64RegClass;
828 break;
829 default:
830 return false;
831 }
832
833 unsigned ResultReg = createResultReg(RC);
834 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
835 .addReg(TrueReg)
836 .addReg(FalseReg)
837 .addReg(CondReg);
838
839 updateValueMap(Select, ResultReg);
840 return true;
841}
842
843bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
844 const TruncInst *Trunc = cast<TruncInst>(I);
845
846 unsigned Reg = getRegForValue(Trunc->getOperand(0));
847 if (Reg == 0)
848 return false;
849
850 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
851 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
852 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
853 TII.get(WebAssembly::I32_WRAP_I64), Result)
854 .addReg(Reg);
855 Reg = Result;
856 }
857
858 updateValueMap(Trunc, Reg);
859 return true;
860}
861
Dan Gohman3a5ce732016-05-11 16:32:42 +0000862bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
863 const ZExtInst *ZExt = cast<ZExtInst>(I);
864
Dan Gohman33e694a2016-05-12 04:19:09 +0000865 const Value *Op = ZExt->getOperand(0);
866 MVT::SimpleValueType From = getSimpleType(Op->getType());
867 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
868 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000869 if (Reg == 0)
870 return false;
871
872 updateValueMap(ZExt, Reg);
873 return true;
874}
875
876bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
877 const SExtInst *SExt = cast<SExtInst>(I);
878
Dan Gohman33e694a2016-05-12 04:19:09 +0000879 const Value *Op = SExt->getOperand(0);
880 MVT::SimpleValueType From = getSimpleType(Op->getType());
881 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
882 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000883 if (Reg == 0)
884 return false;
885
886 updateValueMap(SExt, Reg);
887 return true;
888}
889
890bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
891 const ICmpInst *ICmp = cast<ICmpInst>(I);
892
893 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
894 unsigned Opc;
895 bool isSigned = false;
896 switch (ICmp->getPredicate()) {
897 case ICmpInst::ICMP_EQ:
898 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
899 break;
900 case ICmpInst::ICMP_NE:
901 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
902 break;
903 case ICmpInst::ICMP_UGT:
904 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
905 break;
906 case ICmpInst::ICMP_UGE:
907 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
908 break;
909 case ICmpInst::ICMP_ULT:
910 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
911 break;
912 case ICmpInst::ICMP_ULE:
913 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
914 break;
915 case ICmpInst::ICMP_SGT:
916 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
917 isSigned = true;
918 break;
919 case ICmpInst::ICMP_SGE:
920 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
921 isSigned = true;
922 break;
923 case ICmpInst::ICMP_SLT:
924 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
925 isSigned = true;
926 break;
927 case ICmpInst::ICMP_SLE:
928 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
929 isSigned = true;
930 break;
931 default: return false;
932 }
933
934 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
935 if (LHS == 0)
936 return false;
937
938 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
939 if (RHS == 0)
940 return false;
941
942 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
943 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
944 .addReg(LHS)
945 .addReg(RHS);
946 updateValueMap(ICmp, ResultReg);
947 return true;
948}
949
950bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
951 const FCmpInst *FCmp = cast<FCmpInst>(I);
952
953 unsigned LHS = getRegForValue(FCmp->getOperand(0));
954 if (LHS == 0)
955 return false;
956
957 unsigned RHS = getRegForValue(FCmp->getOperand(1));
958 if (RHS == 0)
959 return false;
960
961 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
962 unsigned Opc;
963 bool Not = false;
964 switch (FCmp->getPredicate()) {
965 case FCmpInst::FCMP_OEQ:
966 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
967 break;
968 case FCmpInst::FCMP_UNE:
969 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
970 break;
971 case FCmpInst::FCMP_OGT:
972 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
973 break;
974 case FCmpInst::FCMP_OGE:
975 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
976 break;
977 case FCmpInst::FCMP_OLT:
978 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
979 break;
980 case FCmpInst::FCMP_OLE:
981 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
982 break;
983 case FCmpInst::FCMP_UGT:
984 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
985 Not = true;
986 break;
987 case FCmpInst::FCMP_UGE:
988 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
989 Not = true;
990 break;
991 case FCmpInst::FCMP_ULT:
992 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
993 Not = true;
994 break;
995 case FCmpInst::FCMP_ULE:
996 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
997 Not = true;
998 break;
999 default:
1000 return false;
1001 }
1002
1003 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1004 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1005 .addReg(LHS)
1006 .addReg(RHS);
1007
1008 if (Not)
1009 ResultReg = notValue(ResultReg);
1010
1011 updateValueMap(FCmp, ResultReg);
1012 return true;
1013}
1014
Dan Gohman2e644382016-05-10 17:39:48 +00001015bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1016 // Target-independent code can handle this, except it doesn't set the dead
1017 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1018 // to satisfy code that expects this of isBitcast() instructions.
1019 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1020 EVT RetVT = TLI.getValueType(DL, I->getType());
1021 if (!VT.isSimple() || !RetVT.isSimple())
1022 return false;
Dan Gohman33e694a2016-05-12 04:19:09 +00001023
1024 if (VT == RetVT) {
1025 // No-op bitcast.
1026 updateValueMap(I, getRegForValue(I->getOperand(0)));
1027 return true;
1028 }
1029
Dan Gohman2e644382016-05-10 17:39:48 +00001030 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1031 getRegForValue(I->getOperand(0)),
1032 I->getOperand(0)->hasOneUse());
1033 if (!Reg)
1034 return false;
1035 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1036 --Iter;
1037 assert(Iter->isBitcast());
1038 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1039 updateValueMap(I, Reg);
1040 return true;
1041}
1042
1043bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1044 const LoadInst *Load = cast<LoadInst>(I);
1045 if (Load->isAtomic())
1046 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001047 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1048 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001049
1050 Address Addr;
1051 if (!computeAddress(Load->getPointerOperand(), Addr))
1052 return false;
1053
1054 // TODO: Fold a following sign-/zero-extend into the load instruction.
1055
1056 unsigned Opc;
1057 const TargetRegisterClass *RC;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001058 switch (getSimpleType(Load->getType())) {
1059 case MVT::i1:
1060 case MVT::i8:
1061 Opc = WebAssembly::LOAD8_U_I32;
1062 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +00001063 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001064 case MVT::i16:
1065 Opc = WebAssembly::LOAD16_U_I32;
1066 RC = &WebAssembly::I32RegClass;
1067 break;
1068 case MVT::i32:
1069 Opc = WebAssembly::LOAD_I32;
1070 RC = &WebAssembly::I32RegClass;
1071 break;
1072 case MVT::i64:
1073 Opc = WebAssembly::LOAD_I64;
1074 RC = &WebAssembly::I64RegClass;
1075 break;
1076 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001077 Opc = WebAssembly::LOAD_F32;
1078 RC = &WebAssembly::F32RegClass;
1079 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001080 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001081 Opc = WebAssembly::LOAD_F64;
1082 RC = &WebAssembly::F64RegClass;
1083 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001084 default:
1085 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001086 }
1087
1088 materializeLoadStoreOperands(Addr);
1089
1090 unsigned ResultReg = createResultReg(RC);
1091 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1092 ResultReg);
1093
1094 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1095
1096 updateValueMap(Load, ResultReg);
1097 return true;
1098}
1099
1100bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1101 const StoreInst *Store = cast<StoreInst>(I);
1102 if (Store->isAtomic())
1103 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001104 if (!Subtarget->hasSIMD128() &&
1105 Store->getValueOperand()->getType()->isVectorTy())
1106 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001107
1108 Address Addr;
1109 if (!computeAddress(Store->getPointerOperand(), Addr))
1110 return false;
1111
1112 unsigned Opc;
Dan Gohman2e644382016-05-10 17:39:48 +00001113 bool VTIsi1 = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001114 switch (getSimpleType(Store->getValueOperand()->getType())) {
1115 case MVT::i1:
1116 VTIsi1 = true;
1117 case MVT::i8:
1118 Opc = WebAssembly::STORE8_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001119 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001120 case MVT::i16:
1121 Opc = WebAssembly::STORE16_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001122 break;
1123 case MVT::i32:
1124 Opc = WebAssembly::STORE_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001125 break;
1126 case MVT::i64:
1127 Opc = WebAssembly::STORE_I64;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001128 break;
1129 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001130 Opc = WebAssembly::STORE_F32;
Dan Gohman2e644382016-05-10 17:39:48 +00001131 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001132 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001133 Opc = WebAssembly::STORE_F64;
Dan Gohman2e644382016-05-10 17:39:48 +00001134 break;
1135 default: return false;
1136 }
1137
1138 materializeLoadStoreOperands(Addr);
1139
1140 unsigned ValueReg = getRegForValue(Store->getValueOperand());
Derek Schuff732636d2016-08-04 18:01:52 +00001141 if (ValueReg == 0)
1142 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001143 if (VTIsi1)
Dan Gohman3a5ce732016-05-11 16:32:42 +00001144 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
Dan Gohman2e644382016-05-10 17:39:48 +00001145
Dan Gohman7f1bdb22016-10-06 22:08:28 +00001146 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
Dan Gohman2e644382016-05-10 17:39:48 +00001147
1148 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1149
1150 MIB.addReg(ValueReg);
1151 return true;
1152}
1153
1154bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1155 const BranchInst *Br = cast<BranchInst>(I);
1156 if (Br->isUnconditional()) {
1157 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1158 fastEmitBranch(MSucc, Br->getDebugLoc());
1159 return true;
1160 }
1161
1162 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1163 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1164
Dan Gohman33e694a2016-05-12 04:19:09 +00001165 bool Not;
1166 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
Derek Schuff732636d2016-08-04 18:01:52 +00001167 if (CondReg == 0)
1168 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001169
Dan Gohman33e694a2016-05-12 04:19:09 +00001170 unsigned Opc = WebAssembly::BR_IF;
1171 if (Not)
1172 Opc = WebAssembly::BR_UNLESS;
1173
Dan Gohman2e644382016-05-10 17:39:48 +00001174 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1175 .addMBB(TBB)
1176 .addReg(CondReg);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001177
Dan Gohman2e644382016-05-10 17:39:48 +00001178 finishCondBranch(Br->getParent(), TBB, FBB);
1179 return true;
1180}
1181
1182bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1183 if (!FuncInfo.CanLowerReturn)
1184 return false;
1185
1186 const ReturnInst *Ret = cast<ReturnInst>(I);
1187
1188 if (Ret->getNumOperands() == 0) {
1189 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1190 TII.get(WebAssembly::RETURN_VOID));
1191 return true;
1192 }
1193
1194 Value *RV = Ret->getOperand(0);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001195 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1196 return false;
1197
Dan Gohman2e644382016-05-10 17:39:48 +00001198 unsigned Opc;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001199 switch (getSimpleType(RV->getType())) {
1200 case MVT::i1: case MVT::i8:
1201 case MVT::i16: case MVT::i32:
1202 Opc = WebAssembly::RETURN_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001203 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001204 case MVT::i64:
1205 Opc = WebAssembly::RETURN_I64;
1206 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001207 case MVT::f32:
1208 Opc = WebAssembly::RETURN_F32;
1209 break;
1210 case MVT::f64:
1211 Opc = WebAssembly::RETURN_F64;
1212 break;
1213 case MVT::v16i8:
1214 Opc = WebAssembly::RETURN_v16i8;
1215 break;
1216 case MVT::v8i16:
1217 Opc = WebAssembly::RETURN_v8i16;
1218 break;
1219 case MVT::v4i32:
1220 Opc = WebAssembly::RETURN_v4i32;
1221 break;
1222 case MVT::v4f32:
1223 Opc = WebAssembly::RETURN_v4f32;
1224 break;
Dan Gohman2e644382016-05-10 17:39:48 +00001225 default: return false;
1226 }
1227
Dan Gohman33e694a2016-05-12 04:19:09 +00001228 unsigned Reg;
1229 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1230 Reg = getRegForSignedValue(RV);
1231 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1232 Reg = getRegForUnsignedValue(RV);
1233 else
1234 Reg = getRegForValue(RV);
1235
Derek Schuff732636d2016-08-04 18:01:52 +00001236 if (Reg == 0)
1237 return false;
1238
Dan Gohman2e644382016-05-10 17:39:48 +00001239 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1240 return true;
1241}
1242
1243bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1244 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1245 TII.get(WebAssembly::UNREACHABLE));
1246 return true;
1247}
1248
1249bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1250 switch (I->getOpcode()) {
Dan Gohman33e694a2016-05-12 04:19:09 +00001251 case Instruction::Call:
1252 if (selectCall(I))
1253 return true;
1254 break;
1255 case Instruction::Select: return selectSelect(I);
1256 case Instruction::Trunc: return selectTrunc(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001257 case Instruction::ZExt: return selectZExt(I);
1258 case Instruction::SExt: return selectSExt(I);
1259 case Instruction::ICmp: return selectICmp(I);
1260 case Instruction::FCmp: return selectFCmp(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001261 case Instruction::BitCast: return selectBitCast(I);
1262 case Instruction::Load: return selectLoad(I);
1263 case Instruction::Store: return selectStore(I);
1264 case Instruction::Br: return selectBr(I);
1265 case Instruction::Ret: return selectRet(I);
1266 case Instruction::Unreachable: return selectUnreachable(I);
1267 default: break;
Dan Gohman7b634842015-08-24 18:44:37 +00001268 }
1269
1270 // Fall back to target-independent instruction selection.
1271 return selectOperator(I, I->getOpcode());
1272}
1273
1274FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1275 const TargetLibraryInfo *LibInfo) {
1276 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1277}