blob: f516a6b260d13927bd0a8809337bc8faabc690fc [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
Dan Gohman7b634842015-08-24 18:44:37 +000019#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000020#include "WebAssembly.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; }
Jacob Gravellea31ec612017-06-22 21:26:08 +000066 void setKind(BaseKind K) {
67 assert(!isSet() && "Can't change kind with non-zero base");
68 Kind = K;
69 }
Dan Gohman2e644382016-05-10 17:39:48 +000070 BaseKind getKind() const { return Kind; }
71 bool isRegBase() const { return Kind == RegBase; }
72 bool isFIBase() const { return Kind == FrameIndexBase; }
73 void setReg(unsigned Reg) {
74 assert(isRegBase() && "Invalid base register access!");
Jacob Gravellea31ec612017-06-22 21:26:08 +000075 assert(Base.Reg == 0 && "Overwriting non-zero register");
Dan Gohman2e644382016-05-10 17:39:48 +000076 Base.Reg = Reg;
77 }
78 unsigned getReg() const {
79 assert(isRegBase() && "Invalid base register access!");
80 return Base.Reg;
81 }
82 void setFI(unsigned FI) {
83 assert(isFIBase() && "Invalid base frame index access!");
Jacob Gravellea31ec612017-06-22 21:26:08 +000084 assert(Base.FI == 0 && "Overwriting non-zero frame index");
Dan Gohman2e644382016-05-10 17:39:48 +000085 Base.FI = FI;
86 }
87 unsigned getFI() const {
88 assert(isFIBase() && "Invalid base frame index access!");
89 return Base.FI;
90 }
91
Dan Gohman728926a2016-12-22 15:15:10 +000092 void setOffset(int64_t Offset_) {
93 assert(Offset_ >= 0 && "Offsets must be non-negative");
94 Offset = Offset_;
95 }
Dan Gohman2e644382016-05-10 17:39:48 +000096 int64_t getOffset() const { return Offset; }
97 void setGlobalValue(const GlobalValue *G) { GV = G; }
98 const GlobalValue *getGlobalValue() const { return GV; }
Jacob Gravellea31ec612017-06-22 21:26:08 +000099 bool isSet() const {
100 if (isRegBase()) {
101 return Base.Reg != 0;
102 } else {
103 return Base.FI != 0;
104 }
105 }
Dan Gohman2e644382016-05-10 17:39:48 +0000106 };
107
Dan Gohman7b634842015-08-24 18:44:37 +0000108 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
109 /// right decision when generating code for different targets.
110 const WebAssemblySubtarget *Subtarget;
111 LLVMContext *Context;
112
Dan Gohman7b634842015-08-24 18:44:37 +0000113private:
Dan Gohman2e644382016-05-10 17:39:48 +0000114 // Utility helper routines
Dan Gohman3a5ce732016-05-11 16:32:42 +0000115 MVT::SimpleValueType getSimpleType(Type *Ty) {
116 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
117 return VT.isSimple() ? VT.getSimpleVT().SimpleTy :
118 MVT::INVALID_SIMPLE_VALUE_TYPE;
119 }
120 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
121 switch (VT) {
122 case MVT::i1:
123 case MVT::i8:
124 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000125 return MVT::i32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000126 case MVT::i32:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000127 case MVT::i64:
Dan Gohman33e694a2016-05-12 04:19:09 +0000128 case MVT::f32:
129 case MVT::f64:
130 return VT;
Dan Gohman6999c4f2017-02-24 21:05:35 +0000131 case MVT::f16:
132 return MVT::f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000133 case MVT::v16i8:
134 case MVT::v8i16:
135 case MVT::v4i32:
136 case MVT::v4f32:
137 if (Subtarget->hasSIMD128())
138 return VT;
139 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000140 default:
141 break;
142 }
143 return MVT::INVALID_SIMPLE_VALUE_TYPE;
144 }
Dan Gohman2e644382016-05-10 17:39:48 +0000145 bool computeAddress(const Value *Obj, Address &Addr);
146 void materializeLoadStoreOperands(Address &Addr);
147 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
148 MachineMemOperand *MMO);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000149 unsigned maskI1Value(unsigned Reg, const Value *V);
Dan Gohman33e694a2016-05-12 04:19:09 +0000150 unsigned getRegForI1Value(const Value *V, bool &Not);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000151 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
152 MVT::SimpleValueType From);
153 unsigned signExtendToI32(unsigned Reg, const Value *V,
154 MVT::SimpleValueType From);
155 unsigned zeroExtend(unsigned Reg, const Value *V,
156 MVT::SimpleValueType From,
157 MVT::SimpleValueType To);
158 unsigned signExtend(unsigned Reg, const Value *V,
159 MVT::SimpleValueType From,
160 MVT::SimpleValueType To);
161 unsigned getRegForUnsignedValue(const Value *V);
162 unsigned getRegForSignedValue(const Value *V);
163 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
164 unsigned notValue(unsigned Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000165 unsigned copyValue(unsigned Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000166
167 // Backend specific FastISel code.
168 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
169 unsigned fastMaterializeConstant(const Constant *C) override;
Dan Gohman33e694a2016-05-12 04:19:09 +0000170 bool fastLowerArguments() override;
Dan Gohman2e644382016-05-10 17:39:48 +0000171
172 // Selection routines.
Dan Gohman33e694a2016-05-12 04:19:09 +0000173 bool selectCall(const Instruction *I);
174 bool selectSelect(const Instruction *I);
175 bool selectTrunc(const Instruction *I);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000176 bool selectZExt(const Instruction *I);
177 bool selectSExt(const Instruction *I);
178 bool selectICmp(const Instruction *I);
179 bool selectFCmp(const Instruction *I);
Dan Gohman2e644382016-05-10 17:39:48 +0000180 bool selectBitCast(const Instruction *I);
181 bool selectLoad(const Instruction *I);
182 bool selectStore(const Instruction *I);
183 bool selectBr(const Instruction *I);
184 bool selectRet(const Instruction *I);
185 bool selectUnreachable(const Instruction *I);
186
Dan Gohman7b634842015-08-24 18:44:37 +0000187public:
188 // Backend specific FastISel code.
189 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
190 const TargetLibraryInfo *LibInfo)
191 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
192 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
193 Context = &FuncInfo.Fn->getContext();
194 }
195
196 bool fastSelectInstruction(const Instruction *I) override;
197
198#include "WebAssemblyGenFastISel.inc"
199};
200
201} // end anonymous namespace
202
Dan Gohman2e644382016-05-10 17:39:48 +0000203bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
204
205 const User *U = nullptr;
206 unsigned Opcode = Instruction::UserOp1;
207 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
208 // Don't walk into other basic blocks unless the object is an alloca from
209 // another block, otherwise it may not have a virtual register assigned.
210 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
211 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
212 Opcode = I->getOpcode();
213 U = I;
214 }
215 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
216 Opcode = C->getOpcode();
217 U = C;
218 }
219
220 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
221 if (Ty->getAddressSpace() > 255)
222 // Fast instruction selection doesn't support the special
223 // address spaces.
224 return false;
225
226 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
227 if (Addr.getGlobalValue())
228 return false;
229 Addr.setGlobalValue(GV);
230 return true;
231 }
232
233 switch (Opcode) {
Dan Gohman7b634842015-08-24 18:44:37 +0000234 default:
235 break;
Dan Gohman2e644382016-05-10 17:39:48 +0000236 case Instruction::BitCast: {
237 // Look through bitcasts.
238 return computeAddress(U->getOperand(0), Addr);
239 }
240 case Instruction::IntToPtr: {
241 // Look past no-op inttoptrs.
242 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
243 TLI.getPointerTy(DL))
244 return computeAddress(U->getOperand(0), Addr);
245 break;
246 }
247 case Instruction::PtrToInt: {
248 // Look past no-op ptrtoints.
249 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
250 return computeAddress(U->getOperand(0), Addr);
251 break;
252 }
253 case Instruction::GetElementPtr: {
254 Address SavedAddr = Addr;
255 uint64_t TmpOffset = Addr.getOffset();
Dan Gohman728926a2016-12-22 15:15:10 +0000256 // Non-inbounds geps can wrap; wasm's offsets can't.
257 if (!cast<GEPOperator>(U)->isInBounds())
258 goto unsupported_gep;
Dan Gohman2e644382016-05-10 17:39:48 +0000259 // Iterate through the GEP folding the constants into offsets where
260 // we can.
Dan Gohman33e694a2016-05-12 04:19:09 +0000261 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
Dan Gohman2e644382016-05-10 17:39:48 +0000262 GTI != E; ++GTI) {
263 const Value *Op = GTI.getOperand();
Peter Collingbourneab85225b2016-12-02 02:24:42 +0000264 if (StructType *STy = GTI.getStructTypeOrNull()) {
Dan Gohman2e644382016-05-10 17:39:48 +0000265 const StructLayout *SL = DL.getStructLayout(STy);
266 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
267 TmpOffset += SL->getElementOffset(Idx);
268 } else {
269 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
270 for (;;) {
271 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
272 // Constant-offset addressing.
273 TmpOffset += CI->getSExtValue() * S;
274 break;
275 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000276 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
277 // An unscaled add of a register. Set it as the new base.
278 Addr.setReg(getRegForValue(Op));
279 break;
280 }
Dan Gohman2e644382016-05-10 17:39:48 +0000281 if (canFoldAddIntoGEP(U, Op)) {
282 // A compatible add with a constant operand. Fold the constant.
283 ConstantInt *CI =
284 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
285 TmpOffset += CI->getSExtValue() * S;
286 // Iterate on the other operand.
287 Op = cast<AddOperator>(Op)->getOperand(0);
288 continue;
289 }
290 // Unsupported
291 goto unsupported_gep;
292 }
293 }
294 }
Dan Gohman728926a2016-12-22 15:15:10 +0000295 // Don't fold in negative offsets.
296 if (int64_t(TmpOffset) >= 0) {
297 // Try to grab the base operand now.
298 Addr.setOffset(TmpOffset);
299 if (computeAddress(U->getOperand(0), Addr))
300 return true;
301 }
Dan Gohman2e644382016-05-10 17:39:48 +0000302 // We failed, restore everything and try the other options.
303 Addr = SavedAddr;
304 unsupported_gep:
305 break;
306 }
307 case Instruction::Alloca: {
308 const AllocaInst *AI = cast<AllocaInst>(Obj);
309 DenseMap<const AllocaInst *, int>::iterator SI =
310 FuncInfo.StaticAllocaMap.find(AI);
311 if (SI != FuncInfo.StaticAllocaMap.end()) {
Jacob Gravellea31ec612017-06-22 21:26:08 +0000312 if (Addr.isSet()) {
313 return false;
314 }
Dan Gohman2e644382016-05-10 17:39:48 +0000315 Addr.setKind(Address::FrameIndexBase);
316 Addr.setFI(SI->second);
317 return true;
318 }
319 break;
320 }
321 case Instruction::Add: {
322 // Adds of constants are common and easy enough.
323 const Value *LHS = U->getOperand(0);
324 const Value *RHS = U->getOperand(1);
325
326 if (isa<ConstantInt>(LHS))
327 std::swap(LHS, RHS);
328
329 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000330 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
331 if (int64_t(TmpOffset) >= 0) {
332 Addr.setOffset(TmpOffset);
333 return computeAddress(LHS, Addr);
334 }
Dan Gohman2e644382016-05-10 17:39:48 +0000335 }
336
337 Address Backup = Addr;
338 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
339 return true;
340 Addr = Backup;
341
342 break;
343 }
344 case Instruction::Sub: {
345 // Subs of constants are common and easy enough.
346 const Value *LHS = U->getOperand(0);
347 const Value *RHS = U->getOperand(1);
348
349 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000350 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
351 if (TmpOffset >= 0) {
352 Addr.setOffset(TmpOffset);
353 return computeAddress(LHS, Addr);
354 }
Dan Gohman2e644382016-05-10 17:39:48 +0000355 }
356 break;
357 }
358 }
Jacob Gravellea31ec612017-06-22 21:26:08 +0000359 if (Addr.isSet()) {
360 return false;
361 }
Dan Gohman2e644382016-05-10 17:39:48 +0000362 Addr.setReg(getRegForValue(Obj));
363 return Addr.getReg() != 0;
364}
365
366void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
367 if (Addr.isRegBase()) {
368 unsigned Reg = Addr.getReg();
369 if (Reg == 0) {
370 Reg = createResultReg(Subtarget->hasAddr64() ?
371 &WebAssembly::I64RegClass :
372 &WebAssembly::I32RegClass);
373 unsigned Opc = Subtarget->hasAddr64() ?
374 WebAssembly::CONST_I64 :
375 WebAssembly::CONST_I32;
376 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
377 .addImm(0);
378 Addr.setReg(Reg);
379 }
380 }
381}
382
383void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
384 const MachineInstrBuilder &MIB,
385 MachineMemOperand *MMO) {
Dan Gohman48abaa92016-10-25 00:17:11 +0000386 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
387 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
388 MIB.addImm(0);
389
Dan Gohman2e644382016-05-10 17:39:48 +0000390 if (const GlobalValue *GV = Addr.getGlobalValue())
391 MIB.addGlobalAddress(GV, Addr.getOffset());
392 else
393 MIB.addImm(Addr.getOffset());
394
395 if (Addr.isRegBase())
396 MIB.addReg(Addr.getReg());
397 else
398 MIB.addFrameIndex(Addr.getFI());
399
Dan Gohman2e644382016-05-10 17:39:48 +0000400 MIB.addMemOperand(MMO);
401}
402
Dan Gohman3a5ce732016-05-11 16:32:42 +0000403unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
404 return zeroExtendToI32(Reg, V, MVT::i1);
Dan Gohman2e644382016-05-10 17:39:48 +0000405}
406
Dan Gohman33e694a2016-05-12 04:19:09 +0000407unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
408 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
409 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
410 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
411 Not = ICmp->isTrueWhenEqual();
412 return getRegForValue(ICmp->getOperand(0));
413 }
414
415 if (BinaryOperator::isNot(V)) {
416 Not = true;
417 return getRegForValue(BinaryOperator::getNotArgument(V));
418 }
419
420 Not = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000421 return maskI1Value(getRegForValue(V), V);
422}
423
424unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
425 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000426 if (Reg == 0)
427 return 0;
428
Dan Gohman3a5ce732016-05-11 16:32:42 +0000429 switch (From) {
430 case MVT::i1:
431 // If the value is naturally an i1, we don't need to mask it.
432 // TODO: Recursively examine selects, phis, and, or, xor, constants.
Dan Gohman33e694a2016-05-12 04:19:09 +0000433 if (From == MVT::i1 && V != nullptr) {
434 if (isa<CmpInst>(V) ||
435 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
436 return copyValue(Reg);
437 }
438 case MVT::i8:
439 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000440 break;
441 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000442 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000443 default:
444 return 0;
445 }
446
447 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
448 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
449 TII.get(WebAssembly::CONST_I32), Imm)
450 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
451
452 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
453 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
454 TII.get(WebAssembly::AND_I32), Result)
455 .addReg(Reg)
456 .addReg(Imm);
457
458 return Result;
459}
460
461unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
462 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000463 if (Reg == 0)
464 return 0;
465
Dan Gohman3a5ce732016-05-11 16:32:42 +0000466 switch (From) {
467 case MVT::i1:
468 case MVT::i8:
469 case MVT::i16:
470 break;
471 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000472 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000473 default:
Dan Gohman33e694a2016-05-12 04:19:09 +0000474 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000475 }
476
477 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
478 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
479 TII.get(WebAssembly::CONST_I32), Imm)
480 .addImm(32 - MVT(From).getSizeInBits());
481
482 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
483 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
484 TII.get(WebAssembly::SHL_I32), Left)
485 .addReg(Reg)
486 .addReg(Imm);
487
488 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
489 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
490 TII.get(WebAssembly::SHR_S_I32), Right)
491 .addReg(Left)
492 .addReg(Imm);
493
494 return Right;
495}
496
497unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
498 MVT::SimpleValueType From,
499 MVT::SimpleValueType To) {
500 if (To == MVT::i64) {
501 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000502 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000503
504 Reg = zeroExtendToI32(Reg, V, From);
505
506 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
507 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
508 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
509 .addReg(Reg);
510 return Result;
511 }
512
Dan Gohman3a5ce732016-05-11 16:32:42 +0000513 return zeroExtendToI32(Reg, V, From);
514}
515
516unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
517 MVT::SimpleValueType From,
518 MVT::SimpleValueType To) {
519 if (To == MVT::i64) {
520 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000521 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000522
523 Reg = signExtendToI32(Reg, V, From);
524
525 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
526 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
527 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
528 .addReg(Reg);
529 return Result;
530 }
531
Dan Gohman3a5ce732016-05-11 16:32:42 +0000532 return signExtendToI32(Reg, V, From);
533}
534
535unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
536 MVT::SimpleValueType From = getSimpleType(V->getType());
537 MVT::SimpleValueType To = getLegalType(From);
538 return zeroExtend(getRegForValue(V), V, From, To);
539}
540
541unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
542 MVT::SimpleValueType From = getSimpleType(V->getType());
543 MVT::SimpleValueType To = getLegalType(From);
544 return zeroExtend(getRegForValue(V), V, From, To);
545}
546
547unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
548 bool IsSigned) {
549 return IsSigned ? getRegForSignedValue(V) :
550 getRegForUnsignedValue(V);
551}
552
553unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000554 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
555
Dan Gohman3a5ce732016-05-11 16:32:42 +0000556 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
557 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
558 TII.get(WebAssembly::EQZ_I32), NotReg)
559 .addReg(Reg);
560 return NotReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000561}
562
Dan Gohman33e694a2016-05-12 04:19:09 +0000563unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
564 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
565 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
566 TII.get(WebAssembly::COPY), ResultReg)
567 .addReg(Reg);
568 return ResultReg;
569}
570
Dan Gohman2e644382016-05-10 17:39:48 +0000571unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
572 DenseMap<const AllocaInst *, int>::iterator SI =
573 FuncInfo.StaticAllocaMap.find(AI);
574
575 if (SI != FuncInfo.StaticAllocaMap.end()) {
576 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
577 &WebAssembly::I64RegClass :
578 &WebAssembly::I32RegClass);
579 unsigned Opc = Subtarget->hasAddr64() ?
Dan Gohman4fc4e422016-10-24 19:49:43 +0000580 WebAssembly::COPY_I64 :
581 WebAssembly::COPY_I32;
Dan Gohman2e644382016-05-10 17:39:48 +0000582 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
583 .addFrameIndex(SI->second);
584 return ResultReg;
585 }
586
587 return 0;
588}
589
590unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
591 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000592 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
593 &WebAssembly::I64RegClass :
594 &WebAssembly::I32RegClass);
Dan Gohman2e644382016-05-10 17:39:48 +0000595 unsigned Opc = Subtarget->hasAddr64() ?
596 WebAssembly::CONST_I64 :
597 WebAssembly::CONST_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000598 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Dan Gohman2e644382016-05-10 17:39:48 +0000599 .addGlobalAddress(GV);
Dan Gohman33e694a2016-05-12 04:19:09 +0000600 return ResultReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000601 }
602
603 // Let target-independent code handle it.
604 return 0;
605}
606
Dan Gohman33e694a2016-05-12 04:19:09 +0000607bool WebAssemblyFastISel::fastLowerArguments() {
608 if (!FuncInfo.CanLowerReturn)
609 return false;
610
611 const Function *F = FuncInfo.Fn;
612 if (F->isVarArg())
613 return false;
614
615 unsigned i = 0;
616 for (auto const &Arg : F->args()) {
Reid Klecknerb5180542017-03-21 16:57:19 +0000617 const AttributeList &Attrs = F->getAttributes();
Reid Klecknerf021fab2017-04-13 23:12:13 +0000618 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
619 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
620 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
621 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
622 Attrs.hasParamAttribute(i, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000623 return false;
624
625 Type *ArgTy = Arg.getType();
Derek Schuff39bf39f2016-08-02 23:16:09 +0000626 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
627 return false;
628 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
Dan Gohman33e694a2016-05-12 04:19:09 +0000629 return false;
630
631 unsigned Opc;
632 const TargetRegisterClass *RC;
633 switch (getSimpleType(ArgTy)) {
634 case MVT::i1:
635 case MVT::i8:
636 case MVT::i16:
637 case MVT::i32:
638 Opc = WebAssembly::ARGUMENT_I32;
639 RC = &WebAssembly::I32RegClass;
640 break;
641 case MVT::i64:
642 Opc = WebAssembly::ARGUMENT_I64;
643 RC = &WebAssembly::I64RegClass;
644 break;
645 case MVT::f32:
646 Opc = WebAssembly::ARGUMENT_F32;
647 RC = &WebAssembly::F32RegClass;
648 break;
649 case MVT::f64:
650 Opc = WebAssembly::ARGUMENT_F64;
651 RC = &WebAssembly::F64RegClass;
652 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000653 case MVT::v16i8:
654 Opc = WebAssembly::ARGUMENT_v16i8;
655 RC = &WebAssembly::V128RegClass;
656 break;
657 case MVT::v8i16:
658 Opc = WebAssembly::ARGUMENT_v8i16;
659 RC = &WebAssembly::V128RegClass;
660 break;
661 case MVT::v4i32:
662 Opc = WebAssembly::ARGUMENT_v4i32;
663 RC = &WebAssembly::V128RegClass;
664 break;
665 case MVT::v4f32:
666 Opc = WebAssembly::ARGUMENT_v4f32;
667 RC = &WebAssembly::V128RegClass;
668 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000669 default:
670 return false;
671 }
672 unsigned ResultReg = createResultReg(RC);
673 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
674 .addImm(i);
675 updateValueMap(&Arg, ResultReg);
676
677 ++i;
678 }
679
680 MRI.addLiveIn(WebAssembly::ARGUMENTS);
681
682 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
683 for (auto const &Arg : F->args())
684 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
685
Dan Gohman6055fba2017-01-09 23:09:38 +0000686 if (!F->getReturnType()->isVoidTy())
687 MFI->addResult(getLegalType(getSimpleType(F->getReturnType())));
688
Dan Gohman33e694a2016-05-12 04:19:09 +0000689 return true;
690}
691
692bool WebAssemblyFastISel::selectCall(const Instruction *I) {
693 const CallInst *Call = cast<CallInst>(I);
694
695 if (Call->isMustTailCall() || Call->isInlineAsm() ||
696 Call->getFunctionType()->isVarArg())
697 return false;
698
699 Function *Func = Call->getCalledFunction();
700 if (Func && Func->isIntrinsic())
701 return false;
702
Jacob Gravelle690b76e2017-08-24 19:53:44 +0000703 bool IsDirect = Func != nullptr;
704 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
705 return false;
706
Dan Gohman33e694a2016-05-12 04:19:09 +0000707 FunctionType *FuncTy = Call->getFunctionType();
708 unsigned Opc;
Dan Gohman33e694a2016-05-12 04:19:09 +0000709 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
710 unsigned ResultReg;
711 if (IsVoid) {
Derek Schuff6f697832016-10-21 16:38:07 +0000712 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
Dan Gohman33e694a2016-05-12 04:19:09 +0000713 } else {
Derek Schuff39bf39f2016-08-02 23:16:09 +0000714 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
715 return false;
716
Dan Gohman33e694a2016-05-12 04:19:09 +0000717 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
718 switch (RetTy) {
719 case MVT::i1:
720 case MVT::i8:
721 case MVT::i16:
722 case MVT::i32:
Derek Schuff6f697832016-10-21 16:38:07 +0000723 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000724 ResultReg = createResultReg(&WebAssembly::I32RegClass);
725 break;
726 case MVT::i64:
Derek Schuff6f697832016-10-21 16:38:07 +0000727 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000728 ResultReg = createResultReg(&WebAssembly::I64RegClass);
729 break;
730 case MVT::f32:
Derek Schuff6f697832016-10-21 16:38:07 +0000731 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000732 ResultReg = createResultReg(&WebAssembly::F32RegClass);
733 break;
734 case MVT::f64:
Derek Schuff6f697832016-10-21 16:38:07 +0000735 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000736 ResultReg = createResultReg(&WebAssembly::F64RegClass);
737 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000738 case MVT::v16i8:
739 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000740 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000741 ResultReg = createResultReg(&WebAssembly::V128RegClass);
742 break;
743 case MVT::v8i16:
744 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000745 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000746 ResultReg = createResultReg(&WebAssembly::V128RegClass);
747 break;
748 case MVT::v4i32:
749 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000750 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000751 ResultReg = createResultReg(&WebAssembly::V128RegClass);
752 break;
753 case MVT::v4f32:
754 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000755 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000756 ResultReg = createResultReg(&WebAssembly::V128RegClass);
757 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000758 default:
759 return false;
760 }
761 }
762
763 SmallVector<unsigned, 8> Args;
764 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
765 Value *V = Call->getArgOperand(i);
766 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
767 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
768 return false;
769
Reid Klecknerb5180542017-03-21 16:57:19 +0000770 const AttributeList &Attrs = Call->getAttributes();
Reid Klecknerf021fab2017-04-13 23:12:13 +0000771 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
772 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
773 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
774 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
775 Attrs.hasParamAttribute(i, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000776 return false;
777
778 unsigned Reg;
779
Reid Klecknerf021fab2017-04-13 23:12:13 +0000780 if (Attrs.hasParamAttribute(i, Attribute::SExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000781 Reg = getRegForSignedValue(V);
Reid Klecknerf021fab2017-04-13 23:12:13 +0000782 else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000783 Reg = getRegForUnsignedValue(V);
784 else
785 Reg = getRegForValue(V);
786
787 if (Reg == 0)
788 return false;
789
790 Args.push_back(Reg);
791 }
792
793 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
794
795 if (!IsVoid)
796 MIB.addReg(ResultReg, RegState::Define);
797
798 if (IsDirect)
799 MIB.addGlobalAddress(Func);
800 else
801 MIB.addReg(getRegForValue(Call->getCalledValue()));
802
803 for (unsigned ArgReg : Args)
804 MIB.addReg(ArgReg);
805
806 if (!IsVoid)
807 updateValueMap(Call, ResultReg);
808 return true;
809}
810
811bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
812 const SelectInst *Select = cast<SelectInst>(I);
813
814 bool Not;
815 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
816 if (CondReg == 0)
817 return false;
818
819 unsigned TrueReg = getRegForValue(Select->getTrueValue());
820 if (TrueReg == 0)
821 return false;
822
823 unsigned FalseReg = getRegForValue(Select->getFalseValue());
824 if (FalseReg == 0)
825 return false;
826
827 if (Not)
828 std::swap(TrueReg, FalseReg);
829
830 unsigned Opc;
831 const TargetRegisterClass *RC;
832 switch (getSimpleType(Select->getType())) {
833 case MVT::i1:
834 case MVT::i8:
835 case MVT::i16:
836 case MVT::i32:
837 Opc = WebAssembly::SELECT_I32;
838 RC = &WebAssembly::I32RegClass;
839 break;
840 case MVT::i64:
841 Opc = WebAssembly::SELECT_I64;
842 RC = &WebAssembly::I64RegClass;
843 break;
844 case MVT::f32:
845 Opc = WebAssembly::SELECT_F32;
846 RC = &WebAssembly::F32RegClass;
847 break;
848 case MVT::f64:
849 Opc = WebAssembly::SELECT_F64;
850 RC = &WebAssembly::F64RegClass;
851 break;
852 default:
853 return false;
854 }
855
856 unsigned ResultReg = createResultReg(RC);
857 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
858 .addReg(TrueReg)
859 .addReg(FalseReg)
860 .addReg(CondReg);
861
862 updateValueMap(Select, ResultReg);
863 return true;
864}
865
866bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
867 const TruncInst *Trunc = cast<TruncInst>(I);
868
869 unsigned Reg = getRegForValue(Trunc->getOperand(0));
870 if (Reg == 0)
871 return false;
872
873 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
874 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
875 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
876 TII.get(WebAssembly::I32_WRAP_I64), Result)
877 .addReg(Reg);
878 Reg = Result;
879 }
880
881 updateValueMap(Trunc, Reg);
882 return true;
883}
884
Dan Gohman3a5ce732016-05-11 16:32:42 +0000885bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
886 const ZExtInst *ZExt = cast<ZExtInst>(I);
887
Dan Gohman33e694a2016-05-12 04:19:09 +0000888 const Value *Op = ZExt->getOperand(0);
889 MVT::SimpleValueType From = getSimpleType(Op->getType());
890 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
891 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000892 if (Reg == 0)
893 return false;
894
895 updateValueMap(ZExt, Reg);
896 return true;
897}
898
899bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
900 const SExtInst *SExt = cast<SExtInst>(I);
901
Dan Gohman33e694a2016-05-12 04:19:09 +0000902 const Value *Op = SExt->getOperand(0);
903 MVT::SimpleValueType From = getSimpleType(Op->getType());
904 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
905 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000906 if (Reg == 0)
907 return false;
908
909 updateValueMap(SExt, Reg);
910 return true;
911}
912
913bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
914 const ICmpInst *ICmp = cast<ICmpInst>(I);
915
916 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
917 unsigned Opc;
918 bool isSigned = false;
919 switch (ICmp->getPredicate()) {
920 case ICmpInst::ICMP_EQ:
921 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
922 break;
923 case ICmpInst::ICMP_NE:
924 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
925 break;
926 case ICmpInst::ICMP_UGT:
927 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
928 break;
929 case ICmpInst::ICMP_UGE:
930 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
931 break;
932 case ICmpInst::ICMP_ULT:
933 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
934 break;
935 case ICmpInst::ICMP_ULE:
936 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
937 break;
938 case ICmpInst::ICMP_SGT:
939 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
940 isSigned = true;
941 break;
942 case ICmpInst::ICMP_SGE:
943 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
944 isSigned = true;
945 break;
946 case ICmpInst::ICMP_SLT:
947 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
948 isSigned = true;
949 break;
950 case ICmpInst::ICMP_SLE:
951 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
952 isSigned = true;
953 break;
954 default: return false;
955 }
956
957 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
958 if (LHS == 0)
959 return false;
960
961 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
962 if (RHS == 0)
963 return false;
964
965 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
966 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
967 .addReg(LHS)
968 .addReg(RHS);
969 updateValueMap(ICmp, ResultReg);
970 return true;
971}
972
973bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
974 const FCmpInst *FCmp = cast<FCmpInst>(I);
975
976 unsigned LHS = getRegForValue(FCmp->getOperand(0));
977 if (LHS == 0)
978 return false;
979
980 unsigned RHS = getRegForValue(FCmp->getOperand(1));
981 if (RHS == 0)
982 return false;
983
984 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
985 unsigned Opc;
986 bool Not = false;
987 switch (FCmp->getPredicate()) {
988 case FCmpInst::FCMP_OEQ:
989 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
990 break;
991 case FCmpInst::FCMP_UNE:
992 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
993 break;
994 case FCmpInst::FCMP_OGT:
995 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
996 break;
997 case FCmpInst::FCMP_OGE:
998 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
999 break;
1000 case FCmpInst::FCMP_OLT:
1001 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1002 break;
1003 case FCmpInst::FCMP_OLE:
1004 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1005 break;
1006 case FCmpInst::FCMP_UGT:
1007 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1008 Not = true;
1009 break;
1010 case FCmpInst::FCMP_UGE:
1011 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1012 Not = true;
1013 break;
1014 case FCmpInst::FCMP_ULT:
1015 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1016 Not = true;
1017 break;
1018 case FCmpInst::FCMP_ULE:
1019 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1020 Not = true;
1021 break;
1022 default:
1023 return false;
1024 }
1025
1026 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1027 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1028 .addReg(LHS)
1029 .addReg(RHS);
1030
1031 if (Not)
1032 ResultReg = notValue(ResultReg);
1033
1034 updateValueMap(FCmp, ResultReg);
1035 return true;
1036}
1037
Dan Gohman2e644382016-05-10 17:39:48 +00001038bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1039 // Target-independent code can handle this, except it doesn't set the dead
1040 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1041 // to satisfy code that expects this of isBitcast() instructions.
1042 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1043 EVT RetVT = TLI.getValueType(DL, I->getType());
1044 if (!VT.isSimple() || !RetVT.isSimple())
1045 return false;
Dan Gohman33e694a2016-05-12 04:19:09 +00001046
1047 if (VT == RetVT) {
1048 // No-op bitcast.
1049 updateValueMap(I, getRegForValue(I->getOperand(0)));
1050 return true;
1051 }
1052
Dan Gohman2e644382016-05-10 17:39:48 +00001053 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1054 getRegForValue(I->getOperand(0)),
1055 I->getOperand(0)->hasOneUse());
1056 if (!Reg)
1057 return false;
1058 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1059 --Iter;
1060 assert(Iter->isBitcast());
1061 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1062 updateValueMap(I, Reg);
1063 return true;
1064}
1065
1066bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1067 const LoadInst *Load = cast<LoadInst>(I);
1068 if (Load->isAtomic())
1069 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001070 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1071 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001072
1073 Address Addr;
1074 if (!computeAddress(Load->getPointerOperand(), Addr))
1075 return false;
1076
1077 // TODO: Fold a following sign-/zero-extend into the load instruction.
1078
1079 unsigned Opc;
1080 const TargetRegisterClass *RC;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001081 switch (getSimpleType(Load->getType())) {
1082 case MVT::i1:
1083 case MVT::i8:
1084 Opc = WebAssembly::LOAD8_U_I32;
1085 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +00001086 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001087 case MVT::i16:
1088 Opc = WebAssembly::LOAD16_U_I32;
1089 RC = &WebAssembly::I32RegClass;
1090 break;
1091 case MVT::i32:
1092 Opc = WebAssembly::LOAD_I32;
1093 RC = &WebAssembly::I32RegClass;
1094 break;
1095 case MVT::i64:
1096 Opc = WebAssembly::LOAD_I64;
1097 RC = &WebAssembly::I64RegClass;
1098 break;
1099 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001100 Opc = WebAssembly::LOAD_F32;
1101 RC = &WebAssembly::F32RegClass;
1102 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001103 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001104 Opc = WebAssembly::LOAD_F64;
1105 RC = &WebAssembly::F64RegClass;
1106 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001107 default:
1108 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001109 }
1110
1111 materializeLoadStoreOperands(Addr);
1112
1113 unsigned ResultReg = createResultReg(RC);
1114 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1115 ResultReg);
1116
1117 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1118
1119 updateValueMap(Load, ResultReg);
1120 return true;
1121}
1122
1123bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1124 const StoreInst *Store = cast<StoreInst>(I);
1125 if (Store->isAtomic())
1126 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001127 if (!Subtarget->hasSIMD128() &&
1128 Store->getValueOperand()->getType()->isVectorTy())
1129 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001130
1131 Address Addr;
1132 if (!computeAddress(Store->getPointerOperand(), Addr))
1133 return false;
1134
1135 unsigned Opc;
Dan Gohman2e644382016-05-10 17:39:48 +00001136 bool VTIsi1 = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001137 switch (getSimpleType(Store->getValueOperand()->getType())) {
1138 case MVT::i1:
1139 VTIsi1 = true;
1140 case MVT::i8:
1141 Opc = WebAssembly::STORE8_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001142 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001143 case MVT::i16:
1144 Opc = WebAssembly::STORE16_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001145 break;
1146 case MVT::i32:
1147 Opc = WebAssembly::STORE_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001148 break;
1149 case MVT::i64:
1150 Opc = WebAssembly::STORE_I64;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001151 break;
1152 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001153 Opc = WebAssembly::STORE_F32;
Dan Gohman2e644382016-05-10 17:39:48 +00001154 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001155 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001156 Opc = WebAssembly::STORE_F64;
Dan Gohman2e644382016-05-10 17:39:48 +00001157 break;
1158 default: return false;
1159 }
1160
1161 materializeLoadStoreOperands(Addr);
1162
1163 unsigned ValueReg = getRegForValue(Store->getValueOperand());
Derek Schuff732636d2016-08-04 18:01:52 +00001164 if (ValueReg == 0)
1165 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001166 if (VTIsi1)
Dan Gohman3a5ce732016-05-11 16:32:42 +00001167 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
Dan Gohman2e644382016-05-10 17:39:48 +00001168
Dan Gohman7f1bdb22016-10-06 22:08:28 +00001169 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
Dan Gohman2e644382016-05-10 17:39:48 +00001170
1171 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1172
1173 MIB.addReg(ValueReg);
1174 return true;
1175}
1176
1177bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1178 const BranchInst *Br = cast<BranchInst>(I);
1179 if (Br->isUnconditional()) {
1180 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1181 fastEmitBranch(MSucc, Br->getDebugLoc());
1182 return true;
1183 }
1184
1185 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1186 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1187
Dan Gohman33e694a2016-05-12 04:19:09 +00001188 bool Not;
1189 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
Derek Schuff732636d2016-08-04 18:01:52 +00001190 if (CondReg == 0)
1191 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001192
Dan Gohman33e694a2016-05-12 04:19:09 +00001193 unsigned Opc = WebAssembly::BR_IF;
1194 if (Not)
1195 Opc = WebAssembly::BR_UNLESS;
1196
Dan Gohman2e644382016-05-10 17:39:48 +00001197 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1198 .addMBB(TBB)
1199 .addReg(CondReg);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001200
Dan Gohman2e644382016-05-10 17:39:48 +00001201 finishCondBranch(Br->getParent(), TBB, FBB);
1202 return true;
1203}
1204
1205bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1206 if (!FuncInfo.CanLowerReturn)
1207 return false;
1208
1209 const ReturnInst *Ret = cast<ReturnInst>(I);
1210
1211 if (Ret->getNumOperands() == 0) {
1212 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1213 TII.get(WebAssembly::RETURN_VOID));
1214 return true;
1215 }
1216
1217 Value *RV = Ret->getOperand(0);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001218 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1219 return false;
1220
Dan Gohman2e644382016-05-10 17:39:48 +00001221 unsigned Opc;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001222 switch (getSimpleType(RV->getType())) {
1223 case MVT::i1: case MVT::i8:
1224 case MVT::i16: case MVT::i32:
1225 Opc = WebAssembly::RETURN_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001226 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001227 case MVT::i64:
1228 Opc = WebAssembly::RETURN_I64;
1229 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001230 case MVT::f32:
1231 Opc = WebAssembly::RETURN_F32;
1232 break;
1233 case MVT::f64:
1234 Opc = WebAssembly::RETURN_F64;
1235 break;
1236 case MVT::v16i8:
1237 Opc = WebAssembly::RETURN_v16i8;
1238 break;
1239 case MVT::v8i16:
1240 Opc = WebAssembly::RETURN_v8i16;
1241 break;
1242 case MVT::v4i32:
1243 Opc = WebAssembly::RETURN_v4i32;
1244 break;
1245 case MVT::v4f32:
1246 Opc = WebAssembly::RETURN_v4f32;
1247 break;
Dan Gohman2e644382016-05-10 17:39:48 +00001248 default: return false;
1249 }
1250
Dan Gohman33e694a2016-05-12 04:19:09 +00001251 unsigned Reg;
1252 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1253 Reg = getRegForSignedValue(RV);
1254 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1255 Reg = getRegForUnsignedValue(RV);
1256 else
1257 Reg = getRegForValue(RV);
1258
Derek Schuff732636d2016-08-04 18:01:52 +00001259 if (Reg == 0)
1260 return false;
1261
Dan Gohman2e644382016-05-10 17:39:48 +00001262 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1263 return true;
1264}
1265
1266bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1267 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1268 TII.get(WebAssembly::UNREACHABLE));
1269 return true;
1270}
1271
1272bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1273 switch (I->getOpcode()) {
Dan Gohman33e694a2016-05-12 04:19:09 +00001274 case Instruction::Call:
1275 if (selectCall(I))
1276 return true;
1277 break;
1278 case Instruction::Select: return selectSelect(I);
1279 case Instruction::Trunc: return selectTrunc(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001280 case Instruction::ZExt: return selectZExt(I);
1281 case Instruction::SExt: return selectSExt(I);
1282 case Instruction::ICmp: return selectICmp(I);
1283 case Instruction::FCmp: return selectFCmp(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001284 case Instruction::BitCast: return selectBitCast(I);
1285 case Instruction::Load: return selectLoad(I);
1286 case Instruction::Store: return selectStore(I);
1287 case Instruction::Br: return selectBr(I);
1288 case Instruction::Ret: return selectRet(I);
1289 case Instruction::Unreachable: return selectUnreachable(I);
1290 default: break;
Dan Gohman7b634842015-08-24 18:44:37 +00001291 }
1292
1293 // Fall back to target-independent instruction selection.
1294 return selectOperator(I, I->getOpcode());
1295}
1296
1297FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1298 const TargetLibraryInfo *LibInfo) {
1299 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1300}