blob: 8575603075b475514da1c3e9ad7a5cbdb3f81f67 [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
87 void setOffset(int64_t Offset_) { Offset = Offset_; }
88 int64_t getOffset() const { return Offset; }
89 void setGlobalValue(const GlobalValue *G) { GV = G; }
90 const GlobalValue *getGlobalValue() const { return GV; }
91 };
92
Dan Gohman7b634842015-08-24 18:44:37 +000093 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
94 /// right decision when generating code for different targets.
95 const WebAssemblySubtarget *Subtarget;
96 LLVMContext *Context;
97
Dan Gohman7b634842015-08-24 18:44:37 +000098private:
Dan Gohman2e644382016-05-10 17:39:48 +000099 // Utility helper routines
Dan Gohman3a5ce732016-05-11 16:32:42 +0000100 MVT::SimpleValueType getSimpleType(Type *Ty) {
101 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
102 return VT.isSimple() ? VT.getSimpleVT().SimpleTy :
103 MVT::INVALID_SIMPLE_VALUE_TYPE;
104 }
105 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
106 switch (VT) {
107 case MVT::i1:
108 case MVT::i8:
109 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000110 return MVT::i32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000111 case MVT::i32:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000112 case MVT::i64:
Dan Gohman33e694a2016-05-12 04:19:09 +0000113 case MVT::f32:
114 case MVT::f64:
115 return VT;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000116 case MVT::v16i8:
117 case MVT::v8i16:
118 case MVT::v4i32:
119 case MVT::v4f32:
120 if (Subtarget->hasSIMD128())
121 return VT;
122 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000123 default:
124 break;
125 }
126 return MVT::INVALID_SIMPLE_VALUE_TYPE;
127 }
Dan Gohman2e644382016-05-10 17:39:48 +0000128 bool computeAddress(const Value *Obj, Address &Addr);
129 void materializeLoadStoreOperands(Address &Addr);
130 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
131 MachineMemOperand *MMO);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000132 unsigned maskI1Value(unsigned Reg, const Value *V);
Dan Gohman33e694a2016-05-12 04:19:09 +0000133 unsigned getRegForI1Value(const Value *V, bool &Not);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000134 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
135 MVT::SimpleValueType From);
136 unsigned signExtendToI32(unsigned Reg, const Value *V,
137 MVT::SimpleValueType From);
138 unsigned zeroExtend(unsigned Reg, const Value *V,
139 MVT::SimpleValueType From,
140 MVT::SimpleValueType To);
141 unsigned signExtend(unsigned Reg, const Value *V,
142 MVT::SimpleValueType From,
143 MVT::SimpleValueType To);
144 unsigned getRegForUnsignedValue(const Value *V);
145 unsigned getRegForSignedValue(const Value *V);
146 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
147 unsigned notValue(unsigned Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000148 unsigned copyValue(unsigned Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000149
150 // Backend specific FastISel code.
151 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
152 unsigned fastMaterializeConstant(const Constant *C) override;
Dan Gohman33e694a2016-05-12 04:19:09 +0000153 bool fastLowerArguments() override;
Dan Gohman2e644382016-05-10 17:39:48 +0000154
155 // Selection routines.
Dan Gohman33e694a2016-05-12 04:19:09 +0000156 bool selectCall(const Instruction *I);
157 bool selectSelect(const Instruction *I);
158 bool selectTrunc(const Instruction *I);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000159 bool selectZExt(const Instruction *I);
160 bool selectSExt(const Instruction *I);
161 bool selectICmp(const Instruction *I);
162 bool selectFCmp(const Instruction *I);
Dan Gohman2e644382016-05-10 17:39:48 +0000163 bool selectBitCast(const Instruction *I);
164 bool selectLoad(const Instruction *I);
165 bool selectStore(const Instruction *I);
166 bool selectBr(const Instruction *I);
167 bool selectRet(const Instruction *I);
168 bool selectUnreachable(const Instruction *I);
169
Dan Gohman7b634842015-08-24 18:44:37 +0000170public:
171 // Backend specific FastISel code.
172 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
173 const TargetLibraryInfo *LibInfo)
174 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
175 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
176 Context = &FuncInfo.Fn->getContext();
177 }
178
179 bool fastSelectInstruction(const Instruction *I) override;
180
181#include "WebAssemblyGenFastISel.inc"
182};
183
184} // end anonymous namespace
185
Dan Gohman2e644382016-05-10 17:39:48 +0000186bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
187
188 const User *U = nullptr;
189 unsigned Opcode = Instruction::UserOp1;
190 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
191 // Don't walk into other basic blocks unless the object is an alloca from
192 // another block, otherwise it may not have a virtual register assigned.
193 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
194 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
195 Opcode = I->getOpcode();
196 U = I;
197 }
198 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
199 Opcode = C->getOpcode();
200 U = C;
201 }
202
203 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
204 if (Ty->getAddressSpace() > 255)
205 // Fast instruction selection doesn't support the special
206 // address spaces.
207 return false;
208
209 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
210 if (Addr.getGlobalValue())
211 return false;
212 Addr.setGlobalValue(GV);
213 return true;
214 }
215
216 switch (Opcode) {
Dan Gohman7b634842015-08-24 18:44:37 +0000217 default:
218 break;
Dan Gohman2e644382016-05-10 17:39:48 +0000219 case Instruction::BitCast: {
220 // Look through bitcasts.
221 return computeAddress(U->getOperand(0), Addr);
222 }
223 case Instruction::IntToPtr: {
224 // Look past no-op inttoptrs.
225 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
226 TLI.getPointerTy(DL))
227 return computeAddress(U->getOperand(0), Addr);
228 break;
229 }
230 case Instruction::PtrToInt: {
231 // Look past no-op ptrtoints.
232 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
233 return computeAddress(U->getOperand(0), Addr);
234 break;
235 }
236 case Instruction::GetElementPtr: {
237 Address SavedAddr = Addr;
238 uint64_t TmpOffset = Addr.getOffset();
239 // Iterate through the GEP folding the constants into offsets where
240 // we can.
Dan Gohman33e694a2016-05-12 04:19:09 +0000241 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
Dan Gohman2e644382016-05-10 17:39:48 +0000242 GTI != E; ++GTI) {
243 const Value *Op = GTI.getOperand();
244 if (StructType *STy = dyn_cast<StructType>(*GTI)) {
245 const StructLayout *SL = DL.getStructLayout(STy);
246 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
247 TmpOffset += SL->getElementOffset(Idx);
248 } else {
249 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
250 for (;;) {
251 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
252 // Constant-offset addressing.
253 TmpOffset += CI->getSExtValue() * S;
254 break;
255 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000256 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
257 // An unscaled add of a register. Set it as the new base.
258 Addr.setReg(getRegForValue(Op));
259 break;
260 }
Dan Gohman2e644382016-05-10 17:39:48 +0000261 if (canFoldAddIntoGEP(U, Op)) {
262 // A compatible add with a constant operand. Fold the constant.
263 ConstantInt *CI =
264 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
265 TmpOffset += CI->getSExtValue() * S;
266 // Iterate on the other operand.
267 Op = cast<AddOperator>(Op)->getOperand(0);
268 continue;
269 }
270 // Unsupported
271 goto unsupported_gep;
272 }
273 }
274 }
275 // Try to grab the base operand now.
276 Addr.setOffset(TmpOffset);
277 if (computeAddress(U->getOperand(0), Addr))
278 return true;
279 // We failed, restore everything and try the other options.
280 Addr = SavedAddr;
281 unsupported_gep:
282 break;
283 }
284 case Instruction::Alloca: {
285 const AllocaInst *AI = cast<AllocaInst>(Obj);
286 DenseMap<const AllocaInst *, int>::iterator SI =
287 FuncInfo.StaticAllocaMap.find(AI);
288 if (SI != FuncInfo.StaticAllocaMap.end()) {
289 Addr.setKind(Address::FrameIndexBase);
290 Addr.setFI(SI->second);
291 return true;
292 }
293 break;
294 }
295 case Instruction::Add: {
296 // Adds of constants are common and easy enough.
297 const Value *LHS = U->getOperand(0);
298 const Value *RHS = U->getOperand(1);
299
300 if (isa<ConstantInt>(LHS))
301 std::swap(LHS, RHS);
302
303 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
304 Addr.setOffset(Addr.getOffset() + CI->getSExtValue());
305 return computeAddress(LHS, Addr);
306 }
307
308 Address Backup = Addr;
309 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
310 return true;
311 Addr = Backup;
312
313 break;
314 }
315 case Instruction::Sub: {
316 // Subs of constants are common and easy enough.
317 const Value *LHS = U->getOperand(0);
318 const Value *RHS = U->getOperand(1);
319
320 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
321 Addr.setOffset(Addr.getOffset() - CI->getSExtValue());
322 return computeAddress(LHS, Addr);
323 }
324 break;
325 }
326 }
327 Addr.setReg(getRegForValue(Obj));
328 return Addr.getReg() != 0;
329}
330
331void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
332 if (Addr.isRegBase()) {
333 unsigned Reg = Addr.getReg();
334 if (Reg == 0) {
335 Reg = createResultReg(Subtarget->hasAddr64() ?
336 &WebAssembly::I64RegClass :
337 &WebAssembly::I32RegClass);
338 unsigned Opc = Subtarget->hasAddr64() ?
339 WebAssembly::CONST_I64 :
340 WebAssembly::CONST_I32;
341 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
342 .addImm(0);
343 Addr.setReg(Reg);
344 }
345 }
346}
347
348void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
349 const MachineInstrBuilder &MIB,
350 MachineMemOperand *MMO) {
351 if (const GlobalValue *GV = Addr.getGlobalValue())
352 MIB.addGlobalAddress(GV, Addr.getOffset());
353 else
354 MIB.addImm(Addr.getOffset());
355
356 if (Addr.isRegBase())
357 MIB.addReg(Addr.getReg());
358 else
359 MIB.addFrameIndex(Addr.getFI());
360
361 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
362 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
363 MIB.addImm(0);
364
365 MIB.addMemOperand(MMO);
366}
367
Dan Gohman3a5ce732016-05-11 16:32:42 +0000368unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
369 return zeroExtendToI32(Reg, V, MVT::i1);
Dan Gohman2e644382016-05-10 17:39:48 +0000370}
371
Dan Gohman33e694a2016-05-12 04:19:09 +0000372unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
373 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
374 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
375 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
376 Not = ICmp->isTrueWhenEqual();
377 return getRegForValue(ICmp->getOperand(0));
378 }
379
380 if (BinaryOperator::isNot(V)) {
381 Not = true;
382 return getRegForValue(BinaryOperator::getNotArgument(V));
383 }
384
385 Not = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000386 return maskI1Value(getRegForValue(V), V);
387}
388
389unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
390 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000391 if (Reg == 0)
392 return 0;
393
Dan Gohman3a5ce732016-05-11 16:32:42 +0000394 switch (From) {
395 case MVT::i1:
396 // If the value is naturally an i1, we don't need to mask it.
397 // TODO: Recursively examine selects, phis, and, or, xor, constants.
Dan Gohman33e694a2016-05-12 04:19:09 +0000398 if (From == MVT::i1 && V != nullptr) {
399 if (isa<CmpInst>(V) ||
400 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
401 return copyValue(Reg);
402 }
403 case MVT::i8:
404 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000405 break;
406 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000407 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000408 default:
409 return 0;
410 }
411
412 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
413 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
414 TII.get(WebAssembly::CONST_I32), Imm)
415 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
416
417 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
418 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
419 TII.get(WebAssembly::AND_I32), Result)
420 .addReg(Reg)
421 .addReg(Imm);
422
423 return Result;
424}
425
426unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
427 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000428 if (Reg == 0)
429 return 0;
430
Dan Gohman3a5ce732016-05-11 16:32:42 +0000431 switch (From) {
432 case MVT::i1:
433 case MVT::i8:
434 case MVT::i16:
435 break;
436 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000437 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000438 default:
Dan Gohman33e694a2016-05-12 04:19:09 +0000439 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000440 }
441
442 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
443 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
444 TII.get(WebAssembly::CONST_I32), Imm)
445 .addImm(32 - MVT(From).getSizeInBits());
446
447 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
448 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
449 TII.get(WebAssembly::SHL_I32), Left)
450 .addReg(Reg)
451 .addReg(Imm);
452
453 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
454 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
455 TII.get(WebAssembly::SHR_S_I32), Right)
456 .addReg(Left)
457 .addReg(Imm);
458
459 return Right;
460}
461
462unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
463 MVT::SimpleValueType From,
464 MVT::SimpleValueType To) {
465 if (To == MVT::i64) {
466 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000467 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000468
469 Reg = zeroExtendToI32(Reg, V, From);
470
471 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
472 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
473 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
474 .addReg(Reg);
475 return Result;
476 }
477
Dan Gohman3a5ce732016-05-11 16:32:42 +0000478 return zeroExtendToI32(Reg, V, From);
479}
480
481unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
482 MVT::SimpleValueType From,
483 MVT::SimpleValueType To) {
484 if (To == MVT::i64) {
485 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000486 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000487
488 Reg = signExtendToI32(Reg, V, From);
489
490 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
491 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
492 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
493 .addReg(Reg);
494 return Result;
495 }
496
Dan Gohman3a5ce732016-05-11 16:32:42 +0000497 return signExtendToI32(Reg, V, From);
498}
499
500unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
501 MVT::SimpleValueType From = getSimpleType(V->getType());
502 MVT::SimpleValueType To = getLegalType(From);
503 return zeroExtend(getRegForValue(V), V, From, To);
504}
505
506unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
507 MVT::SimpleValueType From = getSimpleType(V->getType());
508 MVT::SimpleValueType To = getLegalType(From);
509 return zeroExtend(getRegForValue(V), V, From, To);
510}
511
512unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
513 bool IsSigned) {
514 return IsSigned ? getRegForSignedValue(V) :
515 getRegForUnsignedValue(V);
516}
517
518unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000519 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
520
Dan Gohman3a5ce732016-05-11 16:32:42 +0000521 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
522 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
523 TII.get(WebAssembly::EQZ_I32), NotReg)
524 .addReg(Reg);
525 return NotReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000526}
527
Dan Gohman33e694a2016-05-12 04:19:09 +0000528unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
529 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
530 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
531 TII.get(WebAssembly::COPY), ResultReg)
532 .addReg(Reg);
533 return ResultReg;
534}
535
Dan Gohman2e644382016-05-10 17:39:48 +0000536unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
537 DenseMap<const AllocaInst *, int>::iterator SI =
538 FuncInfo.StaticAllocaMap.find(AI);
539
540 if (SI != FuncInfo.StaticAllocaMap.end()) {
541 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
542 &WebAssembly::I64RegClass :
543 &WebAssembly::I32RegClass);
544 unsigned Opc = Subtarget->hasAddr64() ?
545 WebAssembly::COPY_LOCAL_I64 :
546 WebAssembly::COPY_LOCAL_I32;
547 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
548 .addFrameIndex(SI->second);
549 return ResultReg;
550 }
551
552 return 0;
553}
554
555unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
556 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000557 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
558 &WebAssembly::I64RegClass :
559 &WebAssembly::I32RegClass);
Dan Gohman2e644382016-05-10 17:39:48 +0000560 unsigned Opc = Subtarget->hasAddr64() ?
561 WebAssembly::CONST_I64 :
562 WebAssembly::CONST_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000563 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Dan Gohman2e644382016-05-10 17:39:48 +0000564 .addGlobalAddress(GV);
Dan Gohman33e694a2016-05-12 04:19:09 +0000565 return ResultReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000566 }
567
568 // Let target-independent code handle it.
569 return 0;
570}
571
Dan Gohman33e694a2016-05-12 04:19:09 +0000572bool WebAssemblyFastISel::fastLowerArguments() {
573 if (!FuncInfo.CanLowerReturn)
574 return false;
575
576 const Function *F = FuncInfo.Fn;
577 if (F->isVarArg())
578 return false;
579
580 unsigned i = 0;
581 for (auto const &Arg : F->args()) {
582 const AttributeSet &Attrs = F->getAttributes();
583 if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
584 Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
585 Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
586 Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
587 Attrs.hasAttribute(i+1, Attribute::Nest))
588 return false;
589
590 Type *ArgTy = Arg.getType();
Derek Schuff39bf39f2016-08-02 23:16:09 +0000591 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
592 return false;
593 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
Dan Gohman33e694a2016-05-12 04:19:09 +0000594 return false;
595
596 unsigned Opc;
597 const TargetRegisterClass *RC;
598 switch (getSimpleType(ArgTy)) {
599 case MVT::i1:
600 case MVT::i8:
601 case MVT::i16:
602 case MVT::i32:
603 Opc = WebAssembly::ARGUMENT_I32;
604 RC = &WebAssembly::I32RegClass;
605 break;
606 case MVT::i64:
607 Opc = WebAssembly::ARGUMENT_I64;
608 RC = &WebAssembly::I64RegClass;
609 break;
610 case MVT::f32:
611 Opc = WebAssembly::ARGUMENT_F32;
612 RC = &WebAssembly::F32RegClass;
613 break;
614 case MVT::f64:
615 Opc = WebAssembly::ARGUMENT_F64;
616 RC = &WebAssembly::F64RegClass;
617 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000618 case MVT::v16i8:
619 Opc = WebAssembly::ARGUMENT_v16i8;
620 RC = &WebAssembly::V128RegClass;
621 break;
622 case MVT::v8i16:
623 Opc = WebAssembly::ARGUMENT_v8i16;
624 RC = &WebAssembly::V128RegClass;
625 break;
626 case MVT::v4i32:
627 Opc = WebAssembly::ARGUMENT_v4i32;
628 RC = &WebAssembly::V128RegClass;
629 break;
630 case MVT::v4f32:
631 Opc = WebAssembly::ARGUMENT_v4f32;
632 RC = &WebAssembly::V128RegClass;
633 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000634 default:
635 return false;
636 }
637 unsigned ResultReg = createResultReg(RC);
638 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
639 .addImm(i);
640 updateValueMap(&Arg, ResultReg);
641
642 ++i;
643 }
644
645 MRI.addLiveIn(WebAssembly::ARGUMENTS);
646
647 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
648 for (auto const &Arg : F->args())
649 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
650
651 return true;
652}
653
654bool WebAssemblyFastISel::selectCall(const Instruction *I) {
655 const CallInst *Call = cast<CallInst>(I);
656
657 if (Call->isMustTailCall() || Call->isInlineAsm() ||
658 Call->getFunctionType()->isVarArg())
659 return false;
660
661 Function *Func = Call->getCalledFunction();
662 if (Func && Func->isIntrinsic())
663 return false;
664
665 FunctionType *FuncTy = Call->getFunctionType();
666 unsigned Opc;
667 bool IsDirect = Func != nullptr;
668 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
669 unsigned ResultReg;
670 if (IsVoid) {
Derek Schuff6f697832016-10-21 16:38:07 +0000671 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
Dan Gohman33e694a2016-05-12 04:19:09 +0000672 } else {
Derek Schuff39bf39f2016-08-02 23:16:09 +0000673 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
674 return false;
675
Dan Gohman33e694a2016-05-12 04:19:09 +0000676 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
677 switch (RetTy) {
678 case MVT::i1:
679 case MVT::i8:
680 case MVT::i16:
681 case MVT::i32:
Derek Schuff6f697832016-10-21 16:38:07 +0000682 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000683 ResultReg = createResultReg(&WebAssembly::I32RegClass);
684 break;
685 case MVT::i64:
Derek Schuff6f697832016-10-21 16:38:07 +0000686 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000687 ResultReg = createResultReg(&WebAssembly::I64RegClass);
688 break;
689 case MVT::f32:
Derek Schuff6f697832016-10-21 16:38:07 +0000690 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000691 ResultReg = createResultReg(&WebAssembly::F32RegClass);
692 break;
693 case MVT::f64:
Derek Schuff6f697832016-10-21 16:38:07 +0000694 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000695 ResultReg = createResultReg(&WebAssembly::F64RegClass);
696 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000697 case MVT::v16i8:
698 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000699 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000700 ResultReg = createResultReg(&WebAssembly::V128RegClass);
701 break;
702 case MVT::v8i16:
703 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000704 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000705 ResultReg = createResultReg(&WebAssembly::V128RegClass);
706 break;
707 case MVT::v4i32:
708 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000709 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000710 ResultReg = createResultReg(&WebAssembly::V128RegClass);
711 break;
712 case MVT::v4f32:
713 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000714 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000715 ResultReg = createResultReg(&WebAssembly::V128RegClass);
716 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000717 default:
718 return false;
719 }
720 }
721
722 SmallVector<unsigned, 8> Args;
723 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
724 Value *V = Call->getArgOperand(i);
725 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
726 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
727 return false;
728
729 const AttributeSet &Attrs = Call->getAttributes();
730 if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
731 Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
732 Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
733 Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
734 Attrs.hasAttribute(i+1, Attribute::Nest))
735 return false;
736
737 unsigned Reg;
738
739 if (Attrs.hasAttribute(i+1, Attribute::SExt))
740 Reg = getRegForSignedValue(V);
741 else if (Attrs.hasAttribute(i+1, Attribute::ZExt))
742 Reg = getRegForUnsignedValue(V);
743 else
744 Reg = getRegForValue(V);
745
746 if (Reg == 0)
747 return false;
748
749 Args.push_back(Reg);
750 }
751
752 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
753
754 if (!IsVoid)
755 MIB.addReg(ResultReg, RegState::Define);
756
757 if (IsDirect)
758 MIB.addGlobalAddress(Func);
759 else
760 MIB.addReg(getRegForValue(Call->getCalledValue()));
761
762 for (unsigned ArgReg : Args)
763 MIB.addReg(ArgReg);
764
765 if (!IsVoid)
766 updateValueMap(Call, ResultReg);
767 return true;
768}
769
770bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
771 const SelectInst *Select = cast<SelectInst>(I);
772
773 bool Not;
774 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
775 if (CondReg == 0)
776 return false;
777
778 unsigned TrueReg = getRegForValue(Select->getTrueValue());
779 if (TrueReg == 0)
780 return false;
781
782 unsigned FalseReg = getRegForValue(Select->getFalseValue());
783 if (FalseReg == 0)
784 return false;
785
786 if (Not)
787 std::swap(TrueReg, FalseReg);
788
789 unsigned Opc;
790 const TargetRegisterClass *RC;
791 switch (getSimpleType(Select->getType())) {
792 case MVT::i1:
793 case MVT::i8:
794 case MVT::i16:
795 case MVT::i32:
796 Opc = WebAssembly::SELECT_I32;
797 RC = &WebAssembly::I32RegClass;
798 break;
799 case MVT::i64:
800 Opc = WebAssembly::SELECT_I64;
801 RC = &WebAssembly::I64RegClass;
802 break;
803 case MVT::f32:
804 Opc = WebAssembly::SELECT_F32;
805 RC = &WebAssembly::F32RegClass;
806 break;
807 case MVT::f64:
808 Opc = WebAssembly::SELECT_F64;
809 RC = &WebAssembly::F64RegClass;
810 break;
811 default:
812 return false;
813 }
814
815 unsigned ResultReg = createResultReg(RC);
816 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
817 .addReg(TrueReg)
818 .addReg(FalseReg)
819 .addReg(CondReg);
820
821 updateValueMap(Select, ResultReg);
822 return true;
823}
824
825bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
826 const TruncInst *Trunc = cast<TruncInst>(I);
827
828 unsigned Reg = getRegForValue(Trunc->getOperand(0));
829 if (Reg == 0)
830 return false;
831
832 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
833 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
834 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
835 TII.get(WebAssembly::I32_WRAP_I64), Result)
836 .addReg(Reg);
837 Reg = Result;
838 }
839
840 updateValueMap(Trunc, Reg);
841 return true;
842}
843
Dan Gohman3a5ce732016-05-11 16:32:42 +0000844bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
845 const ZExtInst *ZExt = cast<ZExtInst>(I);
846
Dan Gohman33e694a2016-05-12 04:19:09 +0000847 const Value *Op = ZExt->getOperand(0);
848 MVT::SimpleValueType From = getSimpleType(Op->getType());
849 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
850 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000851 if (Reg == 0)
852 return false;
853
854 updateValueMap(ZExt, Reg);
855 return true;
856}
857
858bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
859 const SExtInst *SExt = cast<SExtInst>(I);
860
Dan Gohman33e694a2016-05-12 04:19:09 +0000861 const Value *Op = SExt->getOperand(0);
862 MVT::SimpleValueType From = getSimpleType(Op->getType());
863 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
864 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000865 if (Reg == 0)
866 return false;
867
868 updateValueMap(SExt, Reg);
869 return true;
870}
871
872bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
873 const ICmpInst *ICmp = cast<ICmpInst>(I);
874
875 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
876 unsigned Opc;
877 bool isSigned = false;
878 switch (ICmp->getPredicate()) {
879 case ICmpInst::ICMP_EQ:
880 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
881 break;
882 case ICmpInst::ICMP_NE:
883 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
884 break;
885 case ICmpInst::ICMP_UGT:
886 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
887 break;
888 case ICmpInst::ICMP_UGE:
889 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
890 break;
891 case ICmpInst::ICMP_ULT:
892 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
893 break;
894 case ICmpInst::ICMP_ULE:
895 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
896 break;
897 case ICmpInst::ICMP_SGT:
898 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
899 isSigned = true;
900 break;
901 case ICmpInst::ICMP_SGE:
902 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
903 isSigned = true;
904 break;
905 case ICmpInst::ICMP_SLT:
906 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
907 isSigned = true;
908 break;
909 case ICmpInst::ICMP_SLE:
910 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
911 isSigned = true;
912 break;
913 default: return false;
914 }
915
916 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
917 if (LHS == 0)
918 return false;
919
920 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
921 if (RHS == 0)
922 return false;
923
924 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
925 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
926 .addReg(LHS)
927 .addReg(RHS);
928 updateValueMap(ICmp, ResultReg);
929 return true;
930}
931
932bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
933 const FCmpInst *FCmp = cast<FCmpInst>(I);
934
935 unsigned LHS = getRegForValue(FCmp->getOperand(0));
936 if (LHS == 0)
937 return false;
938
939 unsigned RHS = getRegForValue(FCmp->getOperand(1));
940 if (RHS == 0)
941 return false;
942
943 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
944 unsigned Opc;
945 bool Not = false;
946 switch (FCmp->getPredicate()) {
947 case FCmpInst::FCMP_OEQ:
948 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
949 break;
950 case FCmpInst::FCMP_UNE:
951 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
952 break;
953 case FCmpInst::FCMP_OGT:
954 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
955 break;
956 case FCmpInst::FCMP_OGE:
957 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
958 break;
959 case FCmpInst::FCMP_OLT:
960 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
961 break;
962 case FCmpInst::FCMP_OLE:
963 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
964 break;
965 case FCmpInst::FCMP_UGT:
966 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
967 Not = true;
968 break;
969 case FCmpInst::FCMP_UGE:
970 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
971 Not = true;
972 break;
973 case FCmpInst::FCMP_ULT:
974 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
975 Not = true;
976 break;
977 case FCmpInst::FCMP_ULE:
978 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
979 Not = true;
980 break;
981 default:
982 return false;
983 }
984
985 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
986 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
987 .addReg(LHS)
988 .addReg(RHS);
989
990 if (Not)
991 ResultReg = notValue(ResultReg);
992
993 updateValueMap(FCmp, ResultReg);
994 return true;
995}
996
Dan Gohman2e644382016-05-10 17:39:48 +0000997bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
998 // Target-independent code can handle this, except it doesn't set the dead
999 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1000 // to satisfy code that expects this of isBitcast() instructions.
1001 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1002 EVT RetVT = TLI.getValueType(DL, I->getType());
1003 if (!VT.isSimple() || !RetVT.isSimple())
1004 return false;
Dan Gohman33e694a2016-05-12 04:19:09 +00001005
1006 if (VT == RetVT) {
1007 // No-op bitcast.
1008 updateValueMap(I, getRegForValue(I->getOperand(0)));
1009 return true;
1010 }
1011
Dan Gohman2e644382016-05-10 17:39:48 +00001012 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1013 getRegForValue(I->getOperand(0)),
1014 I->getOperand(0)->hasOneUse());
1015 if (!Reg)
1016 return false;
1017 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1018 --Iter;
1019 assert(Iter->isBitcast());
1020 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1021 updateValueMap(I, Reg);
1022 return true;
1023}
1024
1025bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1026 const LoadInst *Load = cast<LoadInst>(I);
1027 if (Load->isAtomic())
1028 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001029 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1030 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001031
1032 Address Addr;
1033 if (!computeAddress(Load->getPointerOperand(), Addr))
1034 return false;
1035
1036 // TODO: Fold a following sign-/zero-extend into the load instruction.
1037
1038 unsigned Opc;
1039 const TargetRegisterClass *RC;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001040 switch (getSimpleType(Load->getType())) {
1041 case MVT::i1:
1042 case MVT::i8:
1043 Opc = WebAssembly::LOAD8_U_I32;
1044 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +00001045 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001046 case MVT::i16:
1047 Opc = WebAssembly::LOAD16_U_I32;
1048 RC = &WebAssembly::I32RegClass;
1049 break;
1050 case MVT::i32:
1051 Opc = WebAssembly::LOAD_I32;
1052 RC = &WebAssembly::I32RegClass;
1053 break;
1054 case MVT::i64:
1055 Opc = WebAssembly::LOAD_I64;
1056 RC = &WebAssembly::I64RegClass;
1057 break;
1058 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001059 Opc = WebAssembly::LOAD_F32;
1060 RC = &WebAssembly::F32RegClass;
1061 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001062 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001063 Opc = WebAssembly::LOAD_F64;
1064 RC = &WebAssembly::F64RegClass;
1065 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001066 default:
1067 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001068 }
1069
1070 materializeLoadStoreOperands(Addr);
1071
1072 unsigned ResultReg = createResultReg(RC);
1073 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1074 ResultReg);
1075
1076 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1077
1078 updateValueMap(Load, ResultReg);
1079 return true;
1080}
1081
1082bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1083 const StoreInst *Store = cast<StoreInst>(I);
1084 if (Store->isAtomic())
1085 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001086 if (!Subtarget->hasSIMD128() &&
1087 Store->getValueOperand()->getType()->isVectorTy())
1088 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001089
1090 Address Addr;
1091 if (!computeAddress(Store->getPointerOperand(), Addr))
1092 return false;
1093
1094 unsigned Opc;
Dan Gohman2e644382016-05-10 17:39:48 +00001095 bool VTIsi1 = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001096 switch (getSimpleType(Store->getValueOperand()->getType())) {
1097 case MVT::i1:
1098 VTIsi1 = true;
1099 case MVT::i8:
1100 Opc = WebAssembly::STORE8_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001101 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001102 case MVT::i16:
1103 Opc = WebAssembly::STORE16_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001104 break;
1105 case MVT::i32:
1106 Opc = WebAssembly::STORE_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001107 break;
1108 case MVT::i64:
1109 Opc = WebAssembly::STORE_I64;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001110 break;
1111 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001112 Opc = WebAssembly::STORE_F32;
Dan Gohman2e644382016-05-10 17:39:48 +00001113 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001114 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001115 Opc = WebAssembly::STORE_F64;
Dan Gohman2e644382016-05-10 17:39:48 +00001116 break;
1117 default: return false;
1118 }
1119
1120 materializeLoadStoreOperands(Addr);
1121
1122 unsigned ValueReg = getRegForValue(Store->getValueOperand());
Derek Schuff732636d2016-08-04 18:01:52 +00001123 if (ValueReg == 0)
1124 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001125 if (VTIsi1)
Dan Gohman3a5ce732016-05-11 16:32:42 +00001126 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
Dan Gohman2e644382016-05-10 17:39:48 +00001127
Dan Gohman7f1bdb22016-10-06 22:08:28 +00001128 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
Dan Gohman2e644382016-05-10 17:39:48 +00001129
1130 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1131
1132 MIB.addReg(ValueReg);
1133 return true;
1134}
1135
1136bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1137 const BranchInst *Br = cast<BranchInst>(I);
1138 if (Br->isUnconditional()) {
1139 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1140 fastEmitBranch(MSucc, Br->getDebugLoc());
1141 return true;
1142 }
1143
1144 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1145 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1146
Dan Gohman33e694a2016-05-12 04:19:09 +00001147 bool Not;
1148 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
Derek Schuff732636d2016-08-04 18:01:52 +00001149 if (CondReg == 0)
1150 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001151
Dan Gohman33e694a2016-05-12 04:19:09 +00001152 unsigned Opc = WebAssembly::BR_IF;
1153 if (Not)
1154 Opc = WebAssembly::BR_UNLESS;
1155
Dan Gohman2e644382016-05-10 17:39:48 +00001156 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1157 .addMBB(TBB)
1158 .addReg(CondReg);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001159
Dan Gohman2e644382016-05-10 17:39:48 +00001160 finishCondBranch(Br->getParent(), TBB, FBB);
1161 return true;
1162}
1163
1164bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1165 if (!FuncInfo.CanLowerReturn)
1166 return false;
1167
1168 const ReturnInst *Ret = cast<ReturnInst>(I);
1169
1170 if (Ret->getNumOperands() == 0) {
1171 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1172 TII.get(WebAssembly::RETURN_VOID));
1173 return true;
1174 }
1175
1176 Value *RV = Ret->getOperand(0);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001177 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1178 return false;
1179
Dan Gohman2e644382016-05-10 17:39:48 +00001180 unsigned Opc;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001181 switch (getSimpleType(RV->getType())) {
1182 case MVT::i1: case MVT::i8:
1183 case MVT::i16: case MVT::i32:
1184 Opc = WebAssembly::RETURN_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001185 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001186 case MVT::i64:
1187 Opc = WebAssembly::RETURN_I64;
1188 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001189 case MVT::f32:
1190 Opc = WebAssembly::RETURN_F32;
1191 break;
1192 case MVT::f64:
1193 Opc = WebAssembly::RETURN_F64;
1194 break;
1195 case MVT::v16i8:
1196 Opc = WebAssembly::RETURN_v16i8;
1197 break;
1198 case MVT::v8i16:
1199 Opc = WebAssembly::RETURN_v8i16;
1200 break;
1201 case MVT::v4i32:
1202 Opc = WebAssembly::RETURN_v4i32;
1203 break;
1204 case MVT::v4f32:
1205 Opc = WebAssembly::RETURN_v4f32;
1206 break;
Dan Gohman2e644382016-05-10 17:39:48 +00001207 default: return false;
1208 }
1209
Dan Gohman33e694a2016-05-12 04:19:09 +00001210 unsigned Reg;
1211 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1212 Reg = getRegForSignedValue(RV);
1213 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1214 Reg = getRegForUnsignedValue(RV);
1215 else
1216 Reg = getRegForValue(RV);
1217
Derek Schuff732636d2016-08-04 18:01:52 +00001218 if (Reg == 0)
1219 return false;
1220
Dan Gohman2e644382016-05-10 17:39:48 +00001221 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1222 return true;
1223}
1224
1225bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1226 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1227 TII.get(WebAssembly::UNREACHABLE));
1228 return true;
1229}
1230
1231bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1232 switch (I->getOpcode()) {
Dan Gohman33e694a2016-05-12 04:19:09 +00001233 case Instruction::Call:
1234 if (selectCall(I))
1235 return true;
1236 break;
1237 case Instruction::Select: return selectSelect(I);
1238 case Instruction::Trunc: return selectTrunc(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001239 case Instruction::ZExt: return selectZExt(I);
1240 case Instruction::SExt: return selectSExt(I);
1241 case Instruction::ICmp: return selectICmp(I);
1242 case Instruction::FCmp: return selectFCmp(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001243 case Instruction::BitCast: return selectBitCast(I);
1244 case Instruction::Load: return selectLoad(I);
1245 case Instruction::Store: return selectStore(I);
1246 case Instruction::Br: return selectBr(I);
1247 case Instruction::Ret: return selectRet(I);
1248 case Instruction::Unreachable: return selectUnreachable(I);
1249 default: break;
Dan Gohman7b634842015-08-24 18:44:37 +00001250 }
1251
1252 // Fall back to target-independent instruction selection.
1253 return selectOperator(I, I->getOpcode());
1254}
1255
1256FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1257 const TargetLibraryInfo *LibInfo) {
1258 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1259}