blob: 59bf1ad2d89969e8d004b9670d1e42f0495550e7 [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.
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000278 unsigned Reg = getRegForValue(Op);
279 if (Reg == 0)
280 return false;
281 Addr.setReg(Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000282 break;
283 }
Dan Gohman2e644382016-05-10 17:39:48 +0000284 if (canFoldAddIntoGEP(U, Op)) {
285 // A compatible add with a constant operand. Fold the constant.
286 ConstantInt *CI =
287 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
288 TmpOffset += CI->getSExtValue() * S;
289 // Iterate on the other operand.
290 Op = cast<AddOperator>(Op)->getOperand(0);
291 continue;
292 }
293 // Unsupported
294 goto unsupported_gep;
295 }
296 }
297 }
Dan Gohman728926a2016-12-22 15:15:10 +0000298 // Don't fold in negative offsets.
299 if (int64_t(TmpOffset) >= 0) {
300 // Try to grab the base operand now.
301 Addr.setOffset(TmpOffset);
302 if (computeAddress(U->getOperand(0), Addr))
303 return true;
304 }
Dan Gohman2e644382016-05-10 17:39:48 +0000305 // We failed, restore everything and try the other options.
306 Addr = SavedAddr;
307 unsupported_gep:
308 break;
309 }
310 case Instruction::Alloca: {
311 const AllocaInst *AI = cast<AllocaInst>(Obj);
312 DenseMap<const AllocaInst *, int>::iterator SI =
313 FuncInfo.StaticAllocaMap.find(AI);
314 if (SI != FuncInfo.StaticAllocaMap.end()) {
Jacob Gravellea31ec612017-06-22 21:26:08 +0000315 if (Addr.isSet()) {
316 return false;
317 }
Dan Gohman2e644382016-05-10 17:39:48 +0000318 Addr.setKind(Address::FrameIndexBase);
319 Addr.setFI(SI->second);
320 return true;
321 }
322 break;
323 }
324 case Instruction::Add: {
325 // Adds of constants are common and easy enough.
326 const Value *LHS = U->getOperand(0);
327 const Value *RHS = U->getOperand(1);
328
329 if (isa<ConstantInt>(LHS))
330 std::swap(LHS, RHS);
331
332 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000333 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
334 if (int64_t(TmpOffset) >= 0) {
335 Addr.setOffset(TmpOffset);
336 return computeAddress(LHS, Addr);
337 }
Dan Gohman2e644382016-05-10 17:39:48 +0000338 }
339
340 Address Backup = Addr;
341 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
342 return true;
343 Addr = Backup;
344
345 break;
346 }
347 case Instruction::Sub: {
348 // Subs of constants are common and easy enough.
349 const Value *LHS = U->getOperand(0);
350 const Value *RHS = U->getOperand(1);
351
352 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000353 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
354 if (TmpOffset >= 0) {
355 Addr.setOffset(TmpOffset);
356 return computeAddress(LHS, Addr);
357 }
Dan Gohman2e644382016-05-10 17:39:48 +0000358 }
359 break;
360 }
361 }
Jacob Gravellea31ec612017-06-22 21:26:08 +0000362 if (Addr.isSet()) {
363 return false;
364 }
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000365 unsigned Reg = getRegForValue(Obj);
366 if (Reg == 0)
367 return false;
368 Addr.setReg(Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000369 return Addr.getReg() != 0;
370}
371
372void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
373 if (Addr.isRegBase()) {
374 unsigned Reg = Addr.getReg();
375 if (Reg == 0) {
376 Reg = createResultReg(Subtarget->hasAddr64() ?
377 &WebAssembly::I64RegClass :
378 &WebAssembly::I32RegClass);
379 unsigned Opc = Subtarget->hasAddr64() ?
380 WebAssembly::CONST_I64 :
381 WebAssembly::CONST_I32;
382 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
383 .addImm(0);
384 Addr.setReg(Reg);
385 }
386 }
387}
388
389void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
390 const MachineInstrBuilder &MIB,
391 MachineMemOperand *MMO) {
Dan Gohman48abaa92016-10-25 00:17:11 +0000392 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
393 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
394 MIB.addImm(0);
395
Dan Gohman2e644382016-05-10 17:39:48 +0000396 if (const GlobalValue *GV = Addr.getGlobalValue())
397 MIB.addGlobalAddress(GV, Addr.getOffset());
398 else
399 MIB.addImm(Addr.getOffset());
400
401 if (Addr.isRegBase())
402 MIB.addReg(Addr.getReg());
403 else
404 MIB.addFrameIndex(Addr.getFI());
405
Dan Gohman2e644382016-05-10 17:39:48 +0000406 MIB.addMemOperand(MMO);
407}
408
Dan Gohman3a5ce732016-05-11 16:32:42 +0000409unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
410 return zeroExtendToI32(Reg, V, MVT::i1);
Dan Gohman2e644382016-05-10 17:39:48 +0000411}
412
Dan Gohman33e694a2016-05-12 04:19:09 +0000413unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
414 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
415 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
416 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
417 Not = ICmp->isTrueWhenEqual();
418 return getRegForValue(ICmp->getOperand(0));
419 }
420
421 if (BinaryOperator::isNot(V)) {
422 Not = true;
423 return getRegForValue(BinaryOperator::getNotArgument(V));
424 }
425
426 Not = false;
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000427 unsigned Reg = getRegForValue(V);
428 if (Reg == 0)
429 return 0;
430 return maskI1Value(Reg, V);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000431}
432
433unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
434 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000435 if (Reg == 0)
436 return 0;
437
Dan Gohman3a5ce732016-05-11 16:32:42 +0000438 switch (From) {
439 case MVT::i1:
440 // If the value is naturally an i1, we don't need to mask it.
441 // TODO: Recursively examine selects, phis, and, or, xor, constants.
Dan Gohman33e694a2016-05-12 04:19:09 +0000442 if (From == MVT::i1 && V != nullptr) {
443 if (isa<CmpInst>(V) ||
444 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
445 return copyValue(Reg);
446 }
447 case MVT::i8:
448 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000449 break;
450 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000451 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000452 default:
453 return 0;
454 }
455
456 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
457 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
458 TII.get(WebAssembly::CONST_I32), Imm)
459 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
460
461 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
462 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
463 TII.get(WebAssembly::AND_I32), Result)
464 .addReg(Reg)
465 .addReg(Imm);
466
467 return Result;
468}
469
470unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
471 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000472 if (Reg == 0)
473 return 0;
474
Dan Gohman3a5ce732016-05-11 16:32:42 +0000475 switch (From) {
476 case MVT::i1:
477 case MVT::i8:
478 case MVT::i16:
479 break;
480 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000481 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000482 default:
Dan Gohman33e694a2016-05-12 04:19:09 +0000483 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000484 }
485
486 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
487 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
488 TII.get(WebAssembly::CONST_I32), Imm)
489 .addImm(32 - MVT(From).getSizeInBits());
490
491 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
492 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
493 TII.get(WebAssembly::SHL_I32), Left)
494 .addReg(Reg)
495 .addReg(Imm);
496
497 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
499 TII.get(WebAssembly::SHR_S_I32), Right)
500 .addReg(Left)
501 .addReg(Imm);
502
503 return Right;
504}
505
506unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
507 MVT::SimpleValueType From,
508 MVT::SimpleValueType To) {
509 if (To == MVT::i64) {
510 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000511 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000512
513 Reg = zeroExtendToI32(Reg, V, From);
514
515 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
516 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
517 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
518 .addReg(Reg);
519 return Result;
520 }
521
Dan Gohman3a5ce732016-05-11 16:32:42 +0000522 return zeroExtendToI32(Reg, V, From);
523}
524
525unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
526 MVT::SimpleValueType From,
527 MVT::SimpleValueType To) {
528 if (To == MVT::i64) {
529 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000530 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000531
532 Reg = signExtendToI32(Reg, V, From);
533
534 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
535 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
536 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
537 .addReg(Reg);
538 return Result;
539 }
540
Dan Gohman3a5ce732016-05-11 16:32:42 +0000541 return signExtendToI32(Reg, V, From);
542}
543
544unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
545 MVT::SimpleValueType From = getSimpleType(V->getType());
546 MVT::SimpleValueType To = getLegalType(From);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000547 unsigned VReg = getRegForValue(V);
548 if (VReg == 0)
549 return 0;
550 return zeroExtend(VReg, V, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000551}
552
553unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
554 MVT::SimpleValueType From = getSimpleType(V->getType());
555 MVT::SimpleValueType To = getLegalType(From);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000556 unsigned VReg = getRegForValue(V);
557 if (VReg == 0)
558 return 0;
559 return signExtend(VReg, V, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000560}
561
562unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
563 bool IsSigned) {
564 return IsSigned ? getRegForSignedValue(V) :
565 getRegForUnsignedValue(V);
566}
567
568unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000569 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
570
Dan Gohman3a5ce732016-05-11 16:32:42 +0000571 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
572 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
573 TII.get(WebAssembly::EQZ_I32), NotReg)
574 .addReg(Reg);
575 return NotReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000576}
577
Dan Gohman33e694a2016-05-12 04:19:09 +0000578unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
579 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
580 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
581 TII.get(WebAssembly::COPY), ResultReg)
582 .addReg(Reg);
583 return ResultReg;
584}
585
Dan Gohman2e644382016-05-10 17:39:48 +0000586unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
587 DenseMap<const AllocaInst *, int>::iterator SI =
588 FuncInfo.StaticAllocaMap.find(AI);
589
590 if (SI != FuncInfo.StaticAllocaMap.end()) {
591 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
592 &WebAssembly::I64RegClass :
593 &WebAssembly::I32RegClass);
594 unsigned Opc = Subtarget->hasAddr64() ?
Dan Gohman4fc4e422016-10-24 19:49:43 +0000595 WebAssembly::COPY_I64 :
596 WebAssembly::COPY_I32;
Dan Gohman2e644382016-05-10 17:39:48 +0000597 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
598 .addFrameIndex(SI->second);
599 return ResultReg;
600 }
601
602 return 0;
603}
604
605unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
606 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000607 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
608 &WebAssembly::I64RegClass :
609 &WebAssembly::I32RegClass);
Dan Gohman2e644382016-05-10 17:39:48 +0000610 unsigned Opc = Subtarget->hasAddr64() ?
611 WebAssembly::CONST_I64 :
612 WebAssembly::CONST_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000613 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Dan Gohman2e644382016-05-10 17:39:48 +0000614 .addGlobalAddress(GV);
Dan Gohman33e694a2016-05-12 04:19:09 +0000615 return ResultReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000616 }
617
618 // Let target-independent code handle it.
619 return 0;
620}
621
Dan Gohman33e694a2016-05-12 04:19:09 +0000622bool WebAssemblyFastISel::fastLowerArguments() {
623 if (!FuncInfo.CanLowerReturn)
624 return false;
625
626 const Function *F = FuncInfo.Fn;
627 if (F->isVarArg())
628 return false;
629
630 unsigned i = 0;
631 for (auto const &Arg : F->args()) {
Reid Klecknerb5180542017-03-21 16:57:19 +0000632 const AttributeList &Attrs = F->getAttributes();
Reid Klecknerf021fab2017-04-13 23:12:13 +0000633 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
634 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
635 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
636 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
637 Attrs.hasParamAttribute(i, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000638 return false;
639
640 Type *ArgTy = Arg.getType();
Derek Schuff39bf39f2016-08-02 23:16:09 +0000641 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
642 return false;
643 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
Dan Gohman33e694a2016-05-12 04:19:09 +0000644 return false;
645
646 unsigned Opc;
647 const TargetRegisterClass *RC;
648 switch (getSimpleType(ArgTy)) {
649 case MVT::i1:
650 case MVT::i8:
651 case MVT::i16:
652 case MVT::i32:
653 Opc = WebAssembly::ARGUMENT_I32;
654 RC = &WebAssembly::I32RegClass;
655 break;
656 case MVT::i64:
657 Opc = WebAssembly::ARGUMENT_I64;
658 RC = &WebAssembly::I64RegClass;
659 break;
660 case MVT::f32:
661 Opc = WebAssembly::ARGUMENT_F32;
662 RC = &WebAssembly::F32RegClass;
663 break;
664 case MVT::f64:
665 Opc = WebAssembly::ARGUMENT_F64;
666 RC = &WebAssembly::F64RegClass;
667 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000668 case MVT::v16i8:
669 Opc = WebAssembly::ARGUMENT_v16i8;
670 RC = &WebAssembly::V128RegClass;
671 break;
672 case MVT::v8i16:
673 Opc = WebAssembly::ARGUMENT_v8i16;
674 RC = &WebAssembly::V128RegClass;
675 break;
676 case MVT::v4i32:
677 Opc = WebAssembly::ARGUMENT_v4i32;
678 RC = &WebAssembly::V128RegClass;
679 break;
680 case MVT::v4f32:
681 Opc = WebAssembly::ARGUMENT_v4f32;
682 RC = &WebAssembly::V128RegClass;
683 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000684 default:
685 return false;
686 }
687 unsigned ResultReg = createResultReg(RC);
688 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
689 .addImm(i);
690 updateValueMap(&Arg, ResultReg);
691
692 ++i;
693 }
694
695 MRI.addLiveIn(WebAssembly::ARGUMENTS);
696
697 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
698 for (auto const &Arg : F->args())
699 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
700
Dan Gohman6055fba2017-01-09 23:09:38 +0000701 if (!F->getReturnType()->isVoidTy())
702 MFI->addResult(getLegalType(getSimpleType(F->getReturnType())));
703
Dan Gohman33e694a2016-05-12 04:19:09 +0000704 return true;
705}
706
707bool WebAssemblyFastISel::selectCall(const Instruction *I) {
708 const CallInst *Call = cast<CallInst>(I);
709
710 if (Call->isMustTailCall() || Call->isInlineAsm() ||
711 Call->getFunctionType()->isVarArg())
712 return false;
713
714 Function *Func = Call->getCalledFunction();
715 if (Func && Func->isIntrinsic())
716 return false;
717
Jacob Gravelle690b76e2017-08-24 19:53:44 +0000718 bool IsDirect = Func != nullptr;
719 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
720 return false;
721
Dan Gohman33e694a2016-05-12 04:19:09 +0000722 FunctionType *FuncTy = Call->getFunctionType();
723 unsigned Opc;
Dan Gohman33e694a2016-05-12 04:19:09 +0000724 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
725 unsigned ResultReg;
726 if (IsVoid) {
Derek Schuff6f697832016-10-21 16:38:07 +0000727 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
Dan Gohman33e694a2016-05-12 04:19:09 +0000728 } else {
Derek Schuff39bf39f2016-08-02 23:16:09 +0000729 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
730 return false;
731
Dan Gohman33e694a2016-05-12 04:19:09 +0000732 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
733 switch (RetTy) {
734 case MVT::i1:
735 case MVT::i8:
736 case MVT::i16:
737 case MVT::i32:
Derek Schuff6f697832016-10-21 16:38:07 +0000738 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000739 ResultReg = createResultReg(&WebAssembly::I32RegClass);
740 break;
741 case MVT::i64:
Derek Schuff6f697832016-10-21 16:38:07 +0000742 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000743 ResultReg = createResultReg(&WebAssembly::I64RegClass);
744 break;
745 case MVT::f32:
Derek Schuff6f697832016-10-21 16:38:07 +0000746 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000747 ResultReg = createResultReg(&WebAssembly::F32RegClass);
748 break;
749 case MVT::f64:
Derek Schuff6f697832016-10-21 16:38:07 +0000750 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000751 ResultReg = createResultReg(&WebAssembly::F64RegClass);
752 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000753 case MVT::v16i8:
754 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000755 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000756 ResultReg = createResultReg(&WebAssembly::V128RegClass);
757 break;
758 case MVT::v8i16:
759 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000760 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000761 ResultReg = createResultReg(&WebAssembly::V128RegClass);
762 break;
763 case MVT::v4i32:
764 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000765 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000766 ResultReg = createResultReg(&WebAssembly::V128RegClass);
767 break;
768 case MVT::v4f32:
769 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000770 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000771 ResultReg = createResultReg(&WebAssembly::V128RegClass);
772 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000773 default:
774 return false;
775 }
776 }
777
778 SmallVector<unsigned, 8> Args;
779 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
780 Value *V = Call->getArgOperand(i);
781 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
782 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
783 return false;
784
Reid Klecknerb5180542017-03-21 16:57:19 +0000785 const AttributeList &Attrs = Call->getAttributes();
Reid Klecknerf021fab2017-04-13 23:12:13 +0000786 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
787 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
788 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
789 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
790 Attrs.hasParamAttribute(i, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000791 return false;
792
793 unsigned Reg;
794
Reid Klecknerf021fab2017-04-13 23:12:13 +0000795 if (Attrs.hasParamAttribute(i, Attribute::SExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000796 Reg = getRegForSignedValue(V);
Reid Klecknerf021fab2017-04-13 23:12:13 +0000797 else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000798 Reg = getRegForUnsignedValue(V);
799 else
800 Reg = getRegForValue(V);
801
802 if (Reg == 0)
803 return false;
804
805 Args.push_back(Reg);
806 }
807
808 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
809
810 if (!IsVoid)
811 MIB.addReg(ResultReg, RegState::Define);
812
813 if (IsDirect)
814 MIB.addGlobalAddress(Func);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000815 else {
816 unsigned Reg = getRegForValue(Call->getCalledValue());
817 if (Reg == 0)
818 return false;
819 MIB.addReg(Reg);
820 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000821
822 for (unsigned ArgReg : Args)
823 MIB.addReg(ArgReg);
824
825 if (!IsVoid)
826 updateValueMap(Call, ResultReg);
827 return true;
828}
829
830bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
831 const SelectInst *Select = cast<SelectInst>(I);
832
833 bool Not;
834 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
835 if (CondReg == 0)
836 return false;
837
838 unsigned TrueReg = getRegForValue(Select->getTrueValue());
839 if (TrueReg == 0)
840 return false;
841
842 unsigned FalseReg = getRegForValue(Select->getFalseValue());
843 if (FalseReg == 0)
844 return false;
845
846 if (Not)
847 std::swap(TrueReg, FalseReg);
848
849 unsigned Opc;
850 const TargetRegisterClass *RC;
851 switch (getSimpleType(Select->getType())) {
852 case MVT::i1:
853 case MVT::i8:
854 case MVT::i16:
855 case MVT::i32:
856 Opc = WebAssembly::SELECT_I32;
857 RC = &WebAssembly::I32RegClass;
858 break;
859 case MVT::i64:
860 Opc = WebAssembly::SELECT_I64;
861 RC = &WebAssembly::I64RegClass;
862 break;
863 case MVT::f32:
864 Opc = WebAssembly::SELECT_F32;
865 RC = &WebAssembly::F32RegClass;
866 break;
867 case MVT::f64:
868 Opc = WebAssembly::SELECT_F64;
869 RC = &WebAssembly::F64RegClass;
870 break;
871 default:
872 return false;
873 }
874
875 unsigned ResultReg = createResultReg(RC);
876 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
877 .addReg(TrueReg)
878 .addReg(FalseReg)
879 .addReg(CondReg);
880
881 updateValueMap(Select, ResultReg);
882 return true;
883}
884
885bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
886 const TruncInst *Trunc = cast<TruncInst>(I);
887
888 unsigned Reg = getRegForValue(Trunc->getOperand(0));
889 if (Reg == 0)
890 return false;
891
892 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
893 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
894 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
895 TII.get(WebAssembly::I32_WRAP_I64), Result)
896 .addReg(Reg);
897 Reg = Result;
898 }
899
900 updateValueMap(Trunc, Reg);
901 return true;
902}
903
Dan Gohman3a5ce732016-05-11 16:32:42 +0000904bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
905 const ZExtInst *ZExt = cast<ZExtInst>(I);
906
Dan Gohman33e694a2016-05-12 04:19:09 +0000907 const Value *Op = ZExt->getOperand(0);
908 MVT::SimpleValueType From = getSimpleType(Op->getType());
909 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000910 unsigned In = getRegForValue(Op);
911 if (In == 0)
912 return false;
913 unsigned Reg = zeroExtend(In, Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000914 if (Reg == 0)
915 return false;
916
917 updateValueMap(ZExt, Reg);
918 return true;
919}
920
921bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
922 const SExtInst *SExt = cast<SExtInst>(I);
923
Dan Gohman33e694a2016-05-12 04:19:09 +0000924 const Value *Op = SExt->getOperand(0);
925 MVT::SimpleValueType From = getSimpleType(Op->getType());
926 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000927 unsigned In = getRegForValue(Op);
928 if (In == 0)
929 return false;
930 unsigned Reg = signExtend(In, Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000931 if (Reg == 0)
932 return false;
933
934 updateValueMap(SExt, Reg);
935 return true;
936}
937
938bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
939 const ICmpInst *ICmp = cast<ICmpInst>(I);
940
941 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
942 unsigned Opc;
943 bool isSigned = false;
944 switch (ICmp->getPredicate()) {
945 case ICmpInst::ICMP_EQ:
946 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
947 break;
948 case ICmpInst::ICMP_NE:
949 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
950 break;
951 case ICmpInst::ICMP_UGT:
952 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
953 break;
954 case ICmpInst::ICMP_UGE:
955 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
956 break;
957 case ICmpInst::ICMP_ULT:
958 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
959 break;
960 case ICmpInst::ICMP_ULE:
961 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
962 break;
963 case ICmpInst::ICMP_SGT:
964 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
965 isSigned = true;
966 break;
967 case ICmpInst::ICMP_SGE:
968 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
969 isSigned = true;
970 break;
971 case ICmpInst::ICMP_SLT:
972 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
973 isSigned = true;
974 break;
975 case ICmpInst::ICMP_SLE:
976 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
977 isSigned = true;
978 break;
979 default: return false;
980 }
981
982 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
983 if (LHS == 0)
984 return false;
985
986 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
987 if (RHS == 0)
988 return false;
989
990 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
991 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
992 .addReg(LHS)
993 .addReg(RHS);
994 updateValueMap(ICmp, ResultReg);
995 return true;
996}
997
998bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
999 const FCmpInst *FCmp = cast<FCmpInst>(I);
1000
1001 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1002 if (LHS == 0)
1003 return false;
1004
1005 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1006 if (RHS == 0)
1007 return false;
1008
1009 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1010 unsigned Opc;
1011 bool Not = false;
1012 switch (FCmp->getPredicate()) {
1013 case FCmpInst::FCMP_OEQ:
1014 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1015 break;
1016 case FCmpInst::FCMP_UNE:
1017 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1018 break;
1019 case FCmpInst::FCMP_OGT:
1020 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1021 break;
1022 case FCmpInst::FCMP_OGE:
1023 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1024 break;
1025 case FCmpInst::FCMP_OLT:
1026 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1027 break;
1028 case FCmpInst::FCMP_OLE:
1029 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1030 break;
1031 case FCmpInst::FCMP_UGT:
1032 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1033 Not = true;
1034 break;
1035 case FCmpInst::FCMP_UGE:
1036 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1037 Not = true;
1038 break;
1039 case FCmpInst::FCMP_ULT:
1040 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1041 Not = true;
1042 break;
1043 case FCmpInst::FCMP_ULE:
1044 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1045 Not = true;
1046 break;
1047 default:
1048 return false;
1049 }
1050
1051 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1052 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1053 .addReg(LHS)
1054 .addReg(RHS);
1055
1056 if (Not)
1057 ResultReg = notValue(ResultReg);
1058
1059 updateValueMap(FCmp, ResultReg);
1060 return true;
1061}
1062
Dan Gohman2e644382016-05-10 17:39:48 +00001063bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1064 // Target-independent code can handle this, except it doesn't set the dead
1065 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1066 // to satisfy code that expects this of isBitcast() instructions.
1067 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1068 EVT RetVT = TLI.getValueType(DL, I->getType());
1069 if (!VT.isSimple() || !RetVT.isSimple())
1070 return false;
Dan Gohman33e694a2016-05-12 04:19:09 +00001071
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001072 unsigned In = getRegForValue(I->getOperand(0));
1073 if (In == 0)
1074 return false;
1075
Dan Gohman33e694a2016-05-12 04:19:09 +00001076 if (VT == RetVT) {
1077 // No-op bitcast.
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001078 updateValueMap(I, In);
Dan Gohman33e694a2016-05-12 04:19:09 +00001079 return true;
1080 }
1081
Dan Gohman2e644382016-05-10 17:39:48 +00001082 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001083 In, I->getOperand(0)->hasOneUse());
Dan Gohman2e644382016-05-10 17:39:48 +00001084 if (!Reg)
1085 return false;
1086 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1087 --Iter;
1088 assert(Iter->isBitcast());
1089 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1090 updateValueMap(I, Reg);
1091 return true;
1092}
1093
1094bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1095 const LoadInst *Load = cast<LoadInst>(I);
1096 if (Load->isAtomic())
1097 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001098 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1099 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001100
1101 Address Addr;
1102 if (!computeAddress(Load->getPointerOperand(), Addr))
1103 return false;
1104
1105 // TODO: Fold a following sign-/zero-extend into the load instruction.
1106
1107 unsigned Opc;
1108 const TargetRegisterClass *RC;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001109 switch (getSimpleType(Load->getType())) {
1110 case MVT::i1:
1111 case MVT::i8:
1112 Opc = WebAssembly::LOAD8_U_I32;
1113 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +00001114 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001115 case MVT::i16:
1116 Opc = WebAssembly::LOAD16_U_I32;
1117 RC = &WebAssembly::I32RegClass;
1118 break;
1119 case MVT::i32:
1120 Opc = WebAssembly::LOAD_I32;
1121 RC = &WebAssembly::I32RegClass;
1122 break;
1123 case MVT::i64:
1124 Opc = WebAssembly::LOAD_I64;
1125 RC = &WebAssembly::I64RegClass;
1126 break;
1127 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001128 Opc = WebAssembly::LOAD_F32;
1129 RC = &WebAssembly::F32RegClass;
1130 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001131 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001132 Opc = WebAssembly::LOAD_F64;
1133 RC = &WebAssembly::F64RegClass;
1134 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001135 default:
1136 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001137 }
1138
1139 materializeLoadStoreOperands(Addr);
1140
1141 unsigned ResultReg = createResultReg(RC);
1142 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1143 ResultReg);
1144
1145 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1146
1147 updateValueMap(Load, ResultReg);
1148 return true;
1149}
1150
1151bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1152 const StoreInst *Store = cast<StoreInst>(I);
1153 if (Store->isAtomic())
1154 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001155 if (!Subtarget->hasSIMD128() &&
1156 Store->getValueOperand()->getType()->isVectorTy())
1157 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001158
1159 Address Addr;
1160 if (!computeAddress(Store->getPointerOperand(), Addr))
1161 return false;
1162
1163 unsigned Opc;
Dan Gohman2e644382016-05-10 17:39:48 +00001164 bool VTIsi1 = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001165 switch (getSimpleType(Store->getValueOperand()->getType())) {
1166 case MVT::i1:
1167 VTIsi1 = true;
Dan Gohman861bec22018-02-09 22:59:01 +00001168 LLVM_FALLTHROUGH;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001169 case MVT::i8:
1170 Opc = WebAssembly::STORE8_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001171 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001172 case MVT::i16:
1173 Opc = WebAssembly::STORE16_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001174 break;
1175 case MVT::i32:
1176 Opc = WebAssembly::STORE_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001177 break;
1178 case MVT::i64:
1179 Opc = WebAssembly::STORE_I64;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001180 break;
1181 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001182 Opc = WebAssembly::STORE_F32;
Dan Gohman2e644382016-05-10 17:39:48 +00001183 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001184 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001185 Opc = WebAssembly::STORE_F64;
Dan Gohman2e644382016-05-10 17:39:48 +00001186 break;
1187 default: return false;
1188 }
1189
1190 materializeLoadStoreOperands(Addr);
1191
1192 unsigned ValueReg = getRegForValue(Store->getValueOperand());
Derek Schuff732636d2016-08-04 18:01:52 +00001193 if (ValueReg == 0)
1194 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001195 if (VTIsi1)
Dan Gohman3a5ce732016-05-11 16:32:42 +00001196 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
Dan Gohman2e644382016-05-10 17:39:48 +00001197
Dan Gohman7f1bdb22016-10-06 22:08:28 +00001198 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
Dan Gohman2e644382016-05-10 17:39:48 +00001199
1200 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1201
1202 MIB.addReg(ValueReg);
1203 return true;
1204}
1205
1206bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1207 const BranchInst *Br = cast<BranchInst>(I);
1208 if (Br->isUnconditional()) {
1209 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1210 fastEmitBranch(MSucc, Br->getDebugLoc());
1211 return true;
1212 }
1213
1214 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1215 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1216
Dan Gohman33e694a2016-05-12 04:19:09 +00001217 bool Not;
1218 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
Derek Schuff732636d2016-08-04 18:01:52 +00001219 if (CondReg == 0)
1220 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001221
Dan Gohman33e694a2016-05-12 04:19:09 +00001222 unsigned Opc = WebAssembly::BR_IF;
1223 if (Not)
1224 Opc = WebAssembly::BR_UNLESS;
1225
Dan Gohman2e644382016-05-10 17:39:48 +00001226 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1227 .addMBB(TBB)
1228 .addReg(CondReg);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001229
Dan Gohman2e644382016-05-10 17:39:48 +00001230 finishCondBranch(Br->getParent(), TBB, FBB);
1231 return true;
1232}
1233
1234bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1235 if (!FuncInfo.CanLowerReturn)
1236 return false;
1237
1238 const ReturnInst *Ret = cast<ReturnInst>(I);
1239
1240 if (Ret->getNumOperands() == 0) {
1241 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1242 TII.get(WebAssembly::RETURN_VOID));
1243 return true;
1244 }
1245
1246 Value *RV = Ret->getOperand(0);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001247 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1248 return false;
1249
Dan Gohman2e644382016-05-10 17:39:48 +00001250 unsigned Opc;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001251 switch (getSimpleType(RV->getType())) {
1252 case MVT::i1: case MVT::i8:
1253 case MVT::i16: case MVT::i32:
1254 Opc = WebAssembly::RETURN_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001255 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001256 case MVT::i64:
1257 Opc = WebAssembly::RETURN_I64;
1258 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001259 case MVT::f32:
1260 Opc = WebAssembly::RETURN_F32;
1261 break;
1262 case MVT::f64:
1263 Opc = WebAssembly::RETURN_F64;
1264 break;
1265 case MVT::v16i8:
1266 Opc = WebAssembly::RETURN_v16i8;
1267 break;
1268 case MVT::v8i16:
1269 Opc = WebAssembly::RETURN_v8i16;
1270 break;
1271 case MVT::v4i32:
1272 Opc = WebAssembly::RETURN_v4i32;
1273 break;
1274 case MVT::v4f32:
1275 Opc = WebAssembly::RETURN_v4f32;
1276 break;
Dan Gohman2e644382016-05-10 17:39:48 +00001277 default: return false;
1278 }
1279
Dan Gohman33e694a2016-05-12 04:19:09 +00001280 unsigned Reg;
1281 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1282 Reg = getRegForSignedValue(RV);
1283 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1284 Reg = getRegForUnsignedValue(RV);
1285 else
1286 Reg = getRegForValue(RV);
1287
Derek Schuff732636d2016-08-04 18:01:52 +00001288 if (Reg == 0)
1289 return false;
1290
Dan Gohman2e644382016-05-10 17:39:48 +00001291 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1292 return true;
1293}
1294
1295bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1296 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1297 TII.get(WebAssembly::UNREACHABLE));
1298 return true;
1299}
1300
1301bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1302 switch (I->getOpcode()) {
Dan Gohman33e694a2016-05-12 04:19:09 +00001303 case Instruction::Call:
1304 if (selectCall(I))
1305 return true;
1306 break;
1307 case Instruction::Select: return selectSelect(I);
1308 case Instruction::Trunc: return selectTrunc(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001309 case Instruction::ZExt: return selectZExt(I);
1310 case Instruction::SExt: return selectSExt(I);
1311 case Instruction::ICmp: return selectICmp(I);
1312 case Instruction::FCmp: return selectFCmp(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001313 case Instruction::BitCast: return selectBitCast(I);
1314 case Instruction::Load: return selectLoad(I);
1315 case Instruction::Store: return selectStore(I);
1316 case Instruction::Br: return selectBr(I);
1317 case Instruction::Ret: return selectRet(I);
1318 case Instruction::Unreachable: return selectUnreachable(I);
1319 default: break;
Dan Gohman7b634842015-08-24 18:44:37 +00001320 }
1321
1322 // Fall back to target-independent instruction selection.
1323 return selectOperator(I, I->getOpcode());
1324}
1325
1326FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1327 const TargetLibraryInfo *LibInfo) {
1328 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1329}