blob: f3ee6e70822010a66fa182c237ba35c391cc9acb [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:
Heejin Ahn0de58722018-03-08 04:05:37 +0000130 case MVT::ExceptRef:
Dan Gohman33e694a2016-05-12 04:19:09 +0000131 return VT;
Dan Gohman6999c4f2017-02-24 21:05:35 +0000132 case MVT::f16:
133 return MVT::f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000134 case MVT::v16i8:
135 case MVT::v8i16:
136 case MVT::v4i32:
137 case MVT::v4f32:
138 if (Subtarget->hasSIMD128())
139 return VT;
140 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000141 default:
142 break;
143 }
144 return MVT::INVALID_SIMPLE_VALUE_TYPE;
145 }
Dan Gohman2e644382016-05-10 17:39:48 +0000146 bool computeAddress(const Value *Obj, Address &Addr);
147 void materializeLoadStoreOperands(Address &Addr);
148 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
149 MachineMemOperand *MMO);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000150 unsigned maskI1Value(unsigned Reg, const Value *V);
Dan Gohman33e694a2016-05-12 04:19:09 +0000151 unsigned getRegForI1Value(const Value *V, bool &Not);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000152 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
153 MVT::SimpleValueType From);
154 unsigned signExtendToI32(unsigned Reg, const Value *V,
155 MVT::SimpleValueType From);
156 unsigned zeroExtend(unsigned Reg, const Value *V,
157 MVT::SimpleValueType From,
158 MVT::SimpleValueType To);
159 unsigned signExtend(unsigned Reg, const Value *V,
160 MVT::SimpleValueType From,
161 MVT::SimpleValueType To);
162 unsigned getRegForUnsignedValue(const Value *V);
163 unsigned getRegForSignedValue(const Value *V);
164 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
165 unsigned notValue(unsigned Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000166 unsigned copyValue(unsigned Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000167
168 // Backend specific FastISel code.
169 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
170 unsigned fastMaterializeConstant(const Constant *C) override;
Dan Gohman33e694a2016-05-12 04:19:09 +0000171 bool fastLowerArguments() override;
Dan Gohman2e644382016-05-10 17:39:48 +0000172
173 // Selection routines.
Dan Gohman33e694a2016-05-12 04:19:09 +0000174 bool selectCall(const Instruction *I);
175 bool selectSelect(const Instruction *I);
176 bool selectTrunc(const Instruction *I);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000177 bool selectZExt(const Instruction *I);
178 bool selectSExt(const Instruction *I);
179 bool selectICmp(const Instruction *I);
180 bool selectFCmp(const Instruction *I);
Dan Gohman2e644382016-05-10 17:39:48 +0000181 bool selectBitCast(const Instruction *I);
182 bool selectLoad(const Instruction *I);
183 bool selectStore(const Instruction *I);
184 bool selectBr(const Instruction *I);
185 bool selectRet(const Instruction *I);
186 bool selectUnreachable(const Instruction *I);
187
Dan Gohman7b634842015-08-24 18:44:37 +0000188public:
189 // Backend specific FastISel code.
190 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
191 const TargetLibraryInfo *LibInfo)
192 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
193 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
194 Context = &FuncInfo.Fn->getContext();
195 }
196
197 bool fastSelectInstruction(const Instruction *I) override;
198
199#include "WebAssemblyGenFastISel.inc"
200};
201
202} // end anonymous namespace
203
Dan Gohman2e644382016-05-10 17:39:48 +0000204bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
205
206 const User *U = nullptr;
207 unsigned Opcode = Instruction::UserOp1;
208 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
209 // Don't walk into other basic blocks unless the object is an alloca from
210 // another block, otherwise it may not have a virtual register assigned.
211 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
212 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
213 Opcode = I->getOpcode();
214 U = I;
215 }
216 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
217 Opcode = C->getOpcode();
218 U = C;
219 }
220
221 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
222 if (Ty->getAddressSpace() > 255)
223 // Fast instruction selection doesn't support the special
224 // address spaces.
225 return false;
226
227 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
228 if (Addr.getGlobalValue())
229 return false;
230 Addr.setGlobalValue(GV);
231 return true;
232 }
233
234 switch (Opcode) {
Dan Gohman7b634842015-08-24 18:44:37 +0000235 default:
236 break;
Dan Gohman2e644382016-05-10 17:39:48 +0000237 case Instruction::BitCast: {
238 // Look through bitcasts.
239 return computeAddress(U->getOperand(0), Addr);
240 }
241 case Instruction::IntToPtr: {
242 // Look past no-op inttoptrs.
243 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
244 TLI.getPointerTy(DL))
245 return computeAddress(U->getOperand(0), Addr);
246 break;
247 }
248 case Instruction::PtrToInt: {
249 // Look past no-op ptrtoints.
250 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
251 return computeAddress(U->getOperand(0), Addr);
252 break;
253 }
254 case Instruction::GetElementPtr: {
255 Address SavedAddr = Addr;
256 uint64_t TmpOffset = Addr.getOffset();
Dan Gohman728926a2016-12-22 15:15:10 +0000257 // Non-inbounds geps can wrap; wasm's offsets can't.
258 if (!cast<GEPOperator>(U)->isInBounds())
259 goto unsupported_gep;
Dan Gohman2e644382016-05-10 17:39:48 +0000260 // Iterate through the GEP folding the constants into offsets where
261 // we can.
Dan Gohman33e694a2016-05-12 04:19:09 +0000262 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
Dan Gohman2e644382016-05-10 17:39:48 +0000263 GTI != E; ++GTI) {
264 const Value *Op = GTI.getOperand();
Peter Collingbourneab85225b2016-12-02 02:24:42 +0000265 if (StructType *STy = GTI.getStructTypeOrNull()) {
Dan Gohman2e644382016-05-10 17:39:48 +0000266 const StructLayout *SL = DL.getStructLayout(STy);
267 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
268 TmpOffset += SL->getElementOffset(Idx);
269 } else {
270 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
271 for (;;) {
272 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
273 // Constant-offset addressing.
274 TmpOffset += CI->getSExtValue() * S;
275 break;
276 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000277 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
278 // An unscaled add of a register. Set it as the new base.
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000279 unsigned Reg = getRegForValue(Op);
280 if (Reg == 0)
281 return false;
282 Addr.setReg(Reg);
Dan Gohman33e694a2016-05-12 04:19:09 +0000283 break;
284 }
Dan Gohman2e644382016-05-10 17:39:48 +0000285 if (canFoldAddIntoGEP(U, Op)) {
286 // A compatible add with a constant operand. Fold the constant.
287 ConstantInt *CI =
288 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
289 TmpOffset += CI->getSExtValue() * S;
290 // Iterate on the other operand.
291 Op = cast<AddOperator>(Op)->getOperand(0);
292 continue;
293 }
294 // Unsupported
295 goto unsupported_gep;
296 }
297 }
298 }
Dan Gohman728926a2016-12-22 15:15:10 +0000299 // Don't fold in negative offsets.
300 if (int64_t(TmpOffset) >= 0) {
301 // Try to grab the base operand now.
302 Addr.setOffset(TmpOffset);
303 if (computeAddress(U->getOperand(0), Addr))
304 return true;
305 }
Dan Gohman2e644382016-05-10 17:39:48 +0000306 // We failed, restore everything and try the other options.
307 Addr = SavedAddr;
308 unsupported_gep:
309 break;
310 }
311 case Instruction::Alloca: {
312 const AllocaInst *AI = cast<AllocaInst>(Obj);
313 DenseMap<const AllocaInst *, int>::iterator SI =
314 FuncInfo.StaticAllocaMap.find(AI);
315 if (SI != FuncInfo.StaticAllocaMap.end()) {
Jacob Gravellea31ec612017-06-22 21:26:08 +0000316 if (Addr.isSet()) {
317 return false;
318 }
Dan Gohman2e644382016-05-10 17:39:48 +0000319 Addr.setKind(Address::FrameIndexBase);
320 Addr.setFI(SI->second);
321 return true;
322 }
323 break;
324 }
325 case Instruction::Add: {
326 // Adds of constants are common and easy enough.
327 const Value *LHS = U->getOperand(0);
328 const Value *RHS = U->getOperand(1);
329
330 if (isa<ConstantInt>(LHS))
331 std::swap(LHS, RHS);
332
333 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000334 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
335 if (int64_t(TmpOffset) >= 0) {
336 Addr.setOffset(TmpOffset);
337 return computeAddress(LHS, Addr);
338 }
Dan Gohman2e644382016-05-10 17:39:48 +0000339 }
340
341 Address Backup = Addr;
342 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
343 return true;
344 Addr = Backup;
345
346 break;
347 }
348 case Instruction::Sub: {
349 // Subs of constants are common and easy enough.
350 const Value *LHS = U->getOperand(0);
351 const Value *RHS = U->getOperand(1);
352
353 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Dan Gohman728926a2016-12-22 15:15:10 +0000354 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
355 if (TmpOffset >= 0) {
356 Addr.setOffset(TmpOffset);
357 return computeAddress(LHS, Addr);
358 }
Dan Gohman2e644382016-05-10 17:39:48 +0000359 }
360 break;
361 }
362 }
Jacob Gravellea31ec612017-06-22 21:26:08 +0000363 if (Addr.isSet()) {
364 return false;
365 }
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000366 unsigned Reg = getRegForValue(Obj);
367 if (Reg == 0)
368 return false;
369 Addr.setReg(Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000370 return Addr.getReg() != 0;
371}
372
373void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
374 if (Addr.isRegBase()) {
375 unsigned Reg = Addr.getReg();
376 if (Reg == 0) {
377 Reg = createResultReg(Subtarget->hasAddr64() ?
378 &WebAssembly::I64RegClass :
379 &WebAssembly::I32RegClass);
380 unsigned Opc = Subtarget->hasAddr64() ?
381 WebAssembly::CONST_I64 :
382 WebAssembly::CONST_I32;
383 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
384 .addImm(0);
385 Addr.setReg(Reg);
386 }
387 }
388}
389
390void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
391 const MachineInstrBuilder &MIB,
392 MachineMemOperand *MMO) {
Dan Gohman48abaa92016-10-25 00:17:11 +0000393 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
394 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
395 MIB.addImm(0);
396
Dan Gohman2e644382016-05-10 17:39:48 +0000397 if (const GlobalValue *GV = Addr.getGlobalValue())
398 MIB.addGlobalAddress(GV, Addr.getOffset());
399 else
400 MIB.addImm(Addr.getOffset());
401
402 if (Addr.isRegBase())
403 MIB.addReg(Addr.getReg());
404 else
405 MIB.addFrameIndex(Addr.getFI());
406
Dan Gohman2e644382016-05-10 17:39:48 +0000407 MIB.addMemOperand(MMO);
408}
409
Dan Gohman3a5ce732016-05-11 16:32:42 +0000410unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
411 return zeroExtendToI32(Reg, V, MVT::i1);
Dan Gohman2e644382016-05-10 17:39:48 +0000412}
413
Dan Gohman33e694a2016-05-12 04:19:09 +0000414unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
415 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
416 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
417 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
418 Not = ICmp->isTrueWhenEqual();
419 return getRegForValue(ICmp->getOperand(0));
420 }
421
422 if (BinaryOperator::isNot(V)) {
423 Not = true;
424 return getRegForValue(BinaryOperator::getNotArgument(V));
425 }
426
427 Not = false;
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000428 unsigned Reg = getRegForValue(V);
429 if (Reg == 0)
430 return 0;
431 return maskI1Value(Reg, V);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000432}
433
434unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
435 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000436 if (Reg == 0)
437 return 0;
438
Dan Gohman3a5ce732016-05-11 16:32:42 +0000439 switch (From) {
440 case MVT::i1:
441 // If the value is naturally an i1, we don't need to mask it.
442 // TODO: Recursively examine selects, phis, and, or, xor, constants.
Dan Gohman33e694a2016-05-12 04:19:09 +0000443 if (From == MVT::i1 && V != nullptr) {
444 if (isa<CmpInst>(V) ||
445 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
446 return copyValue(Reg);
447 }
448 case MVT::i8:
449 case MVT::i16:
Dan Gohman3a5ce732016-05-11 16:32:42 +0000450 break;
451 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000452 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000453 default:
454 return 0;
455 }
456
457 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
458 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
459 TII.get(WebAssembly::CONST_I32), Imm)
460 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
461
462 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
463 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
464 TII.get(WebAssembly::AND_I32), Result)
465 .addReg(Reg)
466 .addReg(Imm);
467
468 return Result;
469}
470
471unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
472 MVT::SimpleValueType From) {
Derek Schuff732636d2016-08-04 18:01:52 +0000473 if (Reg == 0)
474 return 0;
475
Dan Gohman3a5ce732016-05-11 16:32:42 +0000476 switch (From) {
477 case MVT::i1:
478 case MVT::i8:
479 case MVT::i16:
480 break;
481 case MVT::i32:
Dan Gohman33e694a2016-05-12 04:19:09 +0000482 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000483 default:
Dan Gohman33e694a2016-05-12 04:19:09 +0000484 return 0;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000485 }
486
487 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
488 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
489 TII.get(WebAssembly::CONST_I32), Imm)
490 .addImm(32 - MVT(From).getSizeInBits());
491
492 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
493 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
494 TII.get(WebAssembly::SHL_I32), Left)
495 .addReg(Reg)
496 .addReg(Imm);
497
498 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
499 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
500 TII.get(WebAssembly::SHR_S_I32), Right)
501 .addReg(Left)
502 .addReg(Imm);
503
504 return Right;
505}
506
507unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
508 MVT::SimpleValueType From,
509 MVT::SimpleValueType To) {
510 if (To == MVT::i64) {
511 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000512 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000513
514 Reg = zeroExtendToI32(Reg, V, From);
515
516 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
517 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
518 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
519 .addReg(Reg);
520 return Result;
521 }
522
Dan Gohman3a5ce732016-05-11 16:32:42 +0000523 return zeroExtendToI32(Reg, V, From);
524}
525
526unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
527 MVT::SimpleValueType From,
528 MVT::SimpleValueType To) {
529 if (To == MVT::i64) {
530 if (From == MVT::i64)
Dan Gohman33e694a2016-05-12 04:19:09 +0000531 return copyValue(Reg);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000532
533 Reg = signExtendToI32(Reg, V, From);
534
535 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
536 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
537 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
538 .addReg(Reg);
539 return Result;
540 }
541
Dan Gohman3a5ce732016-05-11 16:32:42 +0000542 return signExtendToI32(Reg, V, From);
543}
544
545unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
546 MVT::SimpleValueType From = getSimpleType(V->getType());
547 MVT::SimpleValueType To = getLegalType(From);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000548 unsigned VReg = getRegForValue(V);
549 if (VReg == 0)
550 return 0;
551 return zeroExtend(VReg, V, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000552}
553
554unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
555 MVT::SimpleValueType From = getSimpleType(V->getType());
556 MVT::SimpleValueType To = getLegalType(From);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000557 unsigned VReg = getRegForValue(V);
558 if (VReg == 0)
559 return 0;
560 return signExtend(VReg, V, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000561}
562
563unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
564 bool IsSigned) {
565 return IsSigned ? getRegForSignedValue(V) :
566 getRegForUnsignedValue(V);
567}
568
569unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000570 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
571
Dan Gohman3a5ce732016-05-11 16:32:42 +0000572 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
573 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
574 TII.get(WebAssembly::EQZ_I32), NotReg)
575 .addReg(Reg);
576 return NotReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000577}
578
Dan Gohman33e694a2016-05-12 04:19:09 +0000579unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
580 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
581 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
582 TII.get(WebAssembly::COPY), ResultReg)
583 .addReg(Reg);
584 return ResultReg;
585}
586
Dan Gohman2e644382016-05-10 17:39:48 +0000587unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
588 DenseMap<const AllocaInst *, int>::iterator SI =
589 FuncInfo.StaticAllocaMap.find(AI);
590
591 if (SI != FuncInfo.StaticAllocaMap.end()) {
592 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
593 &WebAssembly::I64RegClass :
594 &WebAssembly::I32RegClass);
595 unsigned Opc = Subtarget->hasAddr64() ?
Dan Gohman4fc4e422016-10-24 19:49:43 +0000596 WebAssembly::COPY_I64 :
597 WebAssembly::COPY_I32;
Dan Gohman2e644382016-05-10 17:39:48 +0000598 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
599 .addFrameIndex(SI->second);
600 return ResultReg;
601 }
602
603 return 0;
604}
605
606unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
607 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
Dan Gohman33e694a2016-05-12 04:19:09 +0000608 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
609 &WebAssembly::I64RegClass :
610 &WebAssembly::I32RegClass);
Dan Gohman2e644382016-05-10 17:39:48 +0000611 unsigned Opc = Subtarget->hasAddr64() ?
612 WebAssembly::CONST_I64 :
613 WebAssembly::CONST_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000614 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
Dan Gohman2e644382016-05-10 17:39:48 +0000615 .addGlobalAddress(GV);
Dan Gohman33e694a2016-05-12 04:19:09 +0000616 return ResultReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000617 }
618
619 // Let target-independent code handle it.
620 return 0;
621}
622
Dan Gohman33e694a2016-05-12 04:19:09 +0000623bool WebAssemblyFastISel::fastLowerArguments() {
624 if (!FuncInfo.CanLowerReturn)
625 return false;
626
627 const Function *F = FuncInfo.Fn;
628 if (F->isVarArg())
629 return false;
630
631 unsigned i = 0;
632 for (auto const &Arg : F->args()) {
Reid Klecknerb5180542017-03-21 16:57:19 +0000633 const AttributeList &Attrs = F->getAttributes();
Reid Klecknerf021fab2017-04-13 23:12:13 +0000634 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
635 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
636 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
637 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
638 Attrs.hasParamAttribute(i, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000639 return false;
640
641 Type *ArgTy = Arg.getType();
Derek Schuff39bf39f2016-08-02 23:16:09 +0000642 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
643 return false;
644 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
Dan Gohman33e694a2016-05-12 04:19:09 +0000645 return false;
646
647 unsigned Opc;
648 const TargetRegisterClass *RC;
649 switch (getSimpleType(ArgTy)) {
650 case MVT::i1:
651 case MVT::i8:
652 case MVT::i16:
653 case MVT::i32:
654 Opc = WebAssembly::ARGUMENT_I32;
655 RC = &WebAssembly::I32RegClass;
656 break;
657 case MVT::i64:
658 Opc = WebAssembly::ARGUMENT_I64;
659 RC = &WebAssembly::I64RegClass;
660 break;
661 case MVT::f32:
662 Opc = WebAssembly::ARGUMENT_F32;
663 RC = &WebAssembly::F32RegClass;
664 break;
665 case MVT::f64:
666 Opc = WebAssembly::ARGUMENT_F64;
667 RC = &WebAssembly::F64RegClass;
668 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000669 case MVT::v16i8:
670 Opc = WebAssembly::ARGUMENT_v16i8;
671 RC = &WebAssembly::V128RegClass;
672 break;
673 case MVT::v8i16:
674 Opc = WebAssembly::ARGUMENT_v8i16;
675 RC = &WebAssembly::V128RegClass;
676 break;
677 case MVT::v4i32:
678 Opc = WebAssembly::ARGUMENT_v4i32;
679 RC = &WebAssembly::V128RegClass;
680 break;
681 case MVT::v4f32:
682 Opc = WebAssembly::ARGUMENT_v4f32;
683 RC = &WebAssembly::V128RegClass;
684 break;
Heejin Ahn0de58722018-03-08 04:05:37 +0000685 case MVT::ExceptRef:
686 Opc = WebAssembly::ARGUMENT_EXCEPT_REF;
687 RC = &WebAssembly::EXCEPT_REFRegClass;
688 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000689 default:
690 return false;
691 }
692 unsigned ResultReg = createResultReg(RC);
693 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
694 .addImm(i);
695 updateValueMap(&Arg, ResultReg);
696
697 ++i;
698 }
699
700 MRI.addLiveIn(WebAssembly::ARGUMENTS);
701
702 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
703 for (auto const &Arg : F->args())
704 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
705
Dan Gohman6055fba2017-01-09 23:09:38 +0000706 if (!F->getReturnType()->isVoidTy())
707 MFI->addResult(getLegalType(getSimpleType(F->getReturnType())));
708
Dan Gohman33e694a2016-05-12 04:19:09 +0000709 return true;
710}
711
712bool WebAssemblyFastISel::selectCall(const Instruction *I) {
713 const CallInst *Call = cast<CallInst>(I);
714
715 if (Call->isMustTailCall() || Call->isInlineAsm() ||
716 Call->getFunctionType()->isVarArg())
717 return false;
718
719 Function *Func = Call->getCalledFunction();
720 if (Func && Func->isIntrinsic())
721 return false;
722
Jacob Gravelle690b76e2017-08-24 19:53:44 +0000723 bool IsDirect = Func != nullptr;
724 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
725 return false;
726
Dan Gohman33e694a2016-05-12 04:19:09 +0000727 FunctionType *FuncTy = Call->getFunctionType();
728 unsigned Opc;
Dan Gohman33e694a2016-05-12 04:19:09 +0000729 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
730 unsigned ResultReg;
731 if (IsVoid) {
Derek Schuff6f697832016-10-21 16:38:07 +0000732 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
Dan Gohman33e694a2016-05-12 04:19:09 +0000733 } else {
Derek Schuff39bf39f2016-08-02 23:16:09 +0000734 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
735 return false;
736
Dan Gohman33e694a2016-05-12 04:19:09 +0000737 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
738 switch (RetTy) {
739 case MVT::i1:
740 case MVT::i8:
741 case MVT::i16:
742 case MVT::i32:
Derek Schuff6f697832016-10-21 16:38:07 +0000743 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000744 ResultReg = createResultReg(&WebAssembly::I32RegClass);
745 break;
746 case MVT::i64:
Derek Schuff6f697832016-10-21 16:38:07 +0000747 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000748 ResultReg = createResultReg(&WebAssembly::I64RegClass);
749 break;
750 case MVT::f32:
Derek Schuff6f697832016-10-21 16:38:07 +0000751 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
Dan Gohman33e694a2016-05-12 04:19:09 +0000752 ResultReg = createResultReg(&WebAssembly::F32RegClass);
753 break;
754 case MVT::f64:
Derek Schuff6f697832016-10-21 16:38:07 +0000755 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
Dan Gohman33e694a2016-05-12 04:19:09 +0000756 ResultReg = createResultReg(&WebAssembly::F64RegClass);
757 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000758 case MVT::v16i8:
759 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000760 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000761 ResultReg = createResultReg(&WebAssembly::V128RegClass);
762 break;
763 case MVT::v8i16:
764 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000765 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000766 ResultReg = createResultReg(&WebAssembly::V128RegClass);
767 break;
768 case MVT::v4i32:
769 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000770 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000771 ResultReg = createResultReg(&WebAssembly::V128RegClass);
772 break;
773 case MVT::v4f32:
774 Opc =
Derek Schuff6f697832016-10-21 16:38:07 +0000775 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
Derek Schuff39bf39f2016-08-02 23:16:09 +0000776 ResultReg = createResultReg(&WebAssembly::V128RegClass);
777 break;
Heejin Ahn0de58722018-03-08 04:05:37 +0000778 case MVT::ExceptRef:
779 Opc = IsDirect ? WebAssembly::CALL_EXCEPT_REF
780 : WebAssembly::PCALL_INDIRECT_EXCEPT_REF;
781 ResultReg = createResultReg(&WebAssembly::EXCEPT_REFRegClass);
782 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000783 default:
784 return false;
785 }
786 }
787
788 SmallVector<unsigned, 8> Args;
789 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
790 Value *V = Call->getArgOperand(i);
791 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
792 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
793 return false;
794
Reid Klecknerb5180542017-03-21 16:57:19 +0000795 const AttributeList &Attrs = Call->getAttributes();
Reid Klecknerf021fab2017-04-13 23:12:13 +0000796 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
797 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
798 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
799 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
800 Attrs.hasParamAttribute(i, Attribute::Nest))
Dan Gohman33e694a2016-05-12 04:19:09 +0000801 return false;
802
803 unsigned Reg;
804
Reid Klecknerf021fab2017-04-13 23:12:13 +0000805 if (Attrs.hasParamAttribute(i, Attribute::SExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000806 Reg = getRegForSignedValue(V);
Reid Klecknerf021fab2017-04-13 23:12:13 +0000807 else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
Dan Gohman33e694a2016-05-12 04:19:09 +0000808 Reg = getRegForUnsignedValue(V);
809 else
810 Reg = getRegForValue(V);
811
812 if (Reg == 0)
813 return false;
814
815 Args.push_back(Reg);
816 }
817
818 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
819
820 if (!IsVoid)
821 MIB.addReg(ResultReg, RegState::Define);
822
823 if (IsDirect)
824 MIB.addGlobalAddress(Func);
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000825 else {
826 unsigned Reg = getRegForValue(Call->getCalledValue());
827 if (Reg == 0)
828 return false;
829 MIB.addReg(Reg);
830 }
Dan Gohman33e694a2016-05-12 04:19:09 +0000831
832 for (unsigned ArgReg : Args)
833 MIB.addReg(ArgReg);
834
835 if (!IsVoid)
836 updateValueMap(Call, ResultReg);
837 return true;
838}
839
840bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
841 const SelectInst *Select = cast<SelectInst>(I);
842
843 bool Not;
844 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
845 if (CondReg == 0)
846 return false;
847
848 unsigned TrueReg = getRegForValue(Select->getTrueValue());
849 if (TrueReg == 0)
850 return false;
851
852 unsigned FalseReg = getRegForValue(Select->getFalseValue());
853 if (FalseReg == 0)
854 return false;
855
856 if (Not)
857 std::swap(TrueReg, FalseReg);
858
859 unsigned Opc;
860 const TargetRegisterClass *RC;
861 switch (getSimpleType(Select->getType())) {
862 case MVT::i1:
863 case MVT::i8:
864 case MVT::i16:
865 case MVT::i32:
866 Opc = WebAssembly::SELECT_I32;
867 RC = &WebAssembly::I32RegClass;
868 break;
869 case MVT::i64:
870 Opc = WebAssembly::SELECT_I64;
871 RC = &WebAssembly::I64RegClass;
872 break;
873 case MVT::f32:
874 Opc = WebAssembly::SELECT_F32;
875 RC = &WebAssembly::F32RegClass;
876 break;
877 case MVT::f64:
878 Opc = WebAssembly::SELECT_F64;
879 RC = &WebAssembly::F64RegClass;
880 break;
Heejin Ahn0de58722018-03-08 04:05:37 +0000881 case MVT::ExceptRef:
882 Opc = WebAssembly::SELECT_EXCEPT_REF;
883 RC = &WebAssembly::EXCEPT_REFRegClass;
884 break;
Dan Gohman33e694a2016-05-12 04:19:09 +0000885 default:
886 return false;
887 }
888
889 unsigned ResultReg = createResultReg(RC);
890 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
891 .addReg(TrueReg)
892 .addReg(FalseReg)
893 .addReg(CondReg);
894
895 updateValueMap(Select, ResultReg);
896 return true;
897}
898
899bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
900 const TruncInst *Trunc = cast<TruncInst>(I);
901
902 unsigned Reg = getRegForValue(Trunc->getOperand(0));
903 if (Reg == 0)
904 return false;
905
906 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
907 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
908 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
909 TII.get(WebAssembly::I32_WRAP_I64), Result)
910 .addReg(Reg);
911 Reg = Result;
912 }
913
914 updateValueMap(Trunc, Reg);
915 return true;
916}
917
Dan Gohman3a5ce732016-05-11 16:32:42 +0000918bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
919 const ZExtInst *ZExt = cast<ZExtInst>(I);
920
Dan Gohman33e694a2016-05-12 04:19:09 +0000921 const Value *Op = ZExt->getOperand(0);
922 MVT::SimpleValueType From = getSimpleType(Op->getType());
923 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000924 unsigned In = getRegForValue(Op);
925 if (In == 0)
926 return false;
927 unsigned Reg = zeroExtend(In, Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000928 if (Reg == 0)
929 return false;
930
931 updateValueMap(ZExt, Reg);
932 return true;
933}
934
935bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
936 const SExtInst *SExt = cast<SExtInst>(I);
937
Dan Gohman33e694a2016-05-12 04:19:09 +0000938 const Value *Op = SExt->getOperand(0);
939 MVT::SimpleValueType From = getSimpleType(Op->getType());
940 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
Dan Gohman3ff73cf2017-11-28 05:36:42 +0000941 unsigned In = getRegForValue(Op);
942 if (In == 0)
943 return false;
944 unsigned Reg = signExtend(In, Op, From, To);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000945 if (Reg == 0)
946 return false;
947
948 updateValueMap(SExt, Reg);
949 return true;
950}
951
952bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
953 const ICmpInst *ICmp = cast<ICmpInst>(I);
954
955 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
956 unsigned Opc;
957 bool isSigned = false;
958 switch (ICmp->getPredicate()) {
959 case ICmpInst::ICMP_EQ:
960 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
961 break;
962 case ICmpInst::ICMP_NE:
963 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
964 break;
965 case ICmpInst::ICMP_UGT:
966 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
967 break;
968 case ICmpInst::ICMP_UGE:
969 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
970 break;
971 case ICmpInst::ICMP_ULT:
972 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
973 break;
974 case ICmpInst::ICMP_ULE:
975 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
976 break;
977 case ICmpInst::ICMP_SGT:
978 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
979 isSigned = true;
980 break;
981 case ICmpInst::ICMP_SGE:
982 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
983 isSigned = true;
984 break;
985 case ICmpInst::ICMP_SLT:
986 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
987 isSigned = true;
988 break;
989 case ICmpInst::ICMP_SLE:
990 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
991 isSigned = true;
992 break;
993 default: return false;
994 }
995
996 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
997 if (LHS == 0)
998 return false;
999
1000 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
1001 if (RHS == 0)
1002 return false;
1003
1004 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1005 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1006 .addReg(LHS)
1007 .addReg(RHS);
1008 updateValueMap(ICmp, ResultReg);
1009 return true;
1010}
1011
1012bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1013 const FCmpInst *FCmp = cast<FCmpInst>(I);
1014
1015 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1016 if (LHS == 0)
1017 return false;
1018
1019 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1020 if (RHS == 0)
1021 return false;
1022
1023 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1024 unsigned Opc;
1025 bool Not = false;
1026 switch (FCmp->getPredicate()) {
1027 case FCmpInst::FCMP_OEQ:
1028 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1029 break;
1030 case FCmpInst::FCMP_UNE:
1031 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1032 break;
1033 case FCmpInst::FCMP_OGT:
1034 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1035 break;
1036 case FCmpInst::FCMP_OGE:
1037 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1038 break;
1039 case FCmpInst::FCMP_OLT:
1040 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1041 break;
1042 case FCmpInst::FCMP_OLE:
1043 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1044 break;
1045 case FCmpInst::FCMP_UGT:
1046 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1047 Not = true;
1048 break;
1049 case FCmpInst::FCMP_UGE:
1050 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1051 Not = true;
1052 break;
1053 case FCmpInst::FCMP_ULT:
1054 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1055 Not = true;
1056 break;
1057 case FCmpInst::FCMP_ULE:
1058 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1059 Not = true;
1060 break;
1061 default:
1062 return false;
1063 }
1064
1065 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1066 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1067 .addReg(LHS)
1068 .addReg(RHS);
1069
1070 if (Not)
1071 ResultReg = notValue(ResultReg);
1072
1073 updateValueMap(FCmp, ResultReg);
1074 return true;
1075}
1076
Dan Gohman2e644382016-05-10 17:39:48 +00001077bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1078 // Target-independent code can handle this, except it doesn't set the dead
1079 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1080 // to satisfy code that expects this of isBitcast() instructions.
1081 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1082 EVT RetVT = TLI.getValueType(DL, I->getType());
1083 if (!VT.isSimple() || !RetVT.isSimple())
1084 return false;
Dan Gohman33e694a2016-05-12 04:19:09 +00001085
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001086 unsigned In = getRegForValue(I->getOperand(0));
1087 if (In == 0)
1088 return false;
1089
Dan Gohman33e694a2016-05-12 04:19:09 +00001090 if (VT == RetVT) {
1091 // No-op bitcast.
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001092 updateValueMap(I, In);
Dan Gohman33e694a2016-05-12 04:19:09 +00001093 return true;
1094 }
1095
Dan Gohman2e644382016-05-10 17:39:48 +00001096 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
Dan Gohman3ff73cf2017-11-28 05:36:42 +00001097 In, I->getOperand(0)->hasOneUse());
Dan Gohman2e644382016-05-10 17:39:48 +00001098 if (!Reg)
1099 return false;
1100 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1101 --Iter;
1102 assert(Iter->isBitcast());
1103 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1104 updateValueMap(I, Reg);
1105 return true;
1106}
1107
1108bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1109 const LoadInst *Load = cast<LoadInst>(I);
1110 if (Load->isAtomic())
1111 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001112 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1113 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001114
1115 Address Addr;
1116 if (!computeAddress(Load->getPointerOperand(), Addr))
1117 return false;
1118
1119 // TODO: Fold a following sign-/zero-extend into the load instruction.
1120
1121 unsigned Opc;
1122 const TargetRegisterClass *RC;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001123 switch (getSimpleType(Load->getType())) {
1124 case MVT::i1:
1125 case MVT::i8:
1126 Opc = WebAssembly::LOAD8_U_I32;
1127 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +00001128 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001129 case MVT::i16:
1130 Opc = WebAssembly::LOAD16_U_I32;
1131 RC = &WebAssembly::I32RegClass;
1132 break;
1133 case MVT::i32:
1134 Opc = WebAssembly::LOAD_I32;
1135 RC = &WebAssembly::I32RegClass;
1136 break;
1137 case MVT::i64:
1138 Opc = WebAssembly::LOAD_I64;
1139 RC = &WebAssembly::I64RegClass;
1140 break;
1141 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001142 Opc = WebAssembly::LOAD_F32;
1143 RC = &WebAssembly::F32RegClass;
1144 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001145 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001146 Opc = WebAssembly::LOAD_F64;
1147 RC = &WebAssembly::F64RegClass;
1148 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001149 default:
1150 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001151 }
1152
1153 materializeLoadStoreOperands(Addr);
1154
1155 unsigned ResultReg = createResultReg(RC);
1156 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1157 ResultReg);
1158
1159 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1160
1161 updateValueMap(Load, ResultReg);
1162 return true;
1163}
1164
1165bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1166 const StoreInst *Store = cast<StoreInst>(I);
1167 if (Store->isAtomic())
1168 return false;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001169 if (!Subtarget->hasSIMD128() &&
1170 Store->getValueOperand()->getType()->isVectorTy())
1171 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001172
1173 Address Addr;
1174 if (!computeAddress(Store->getPointerOperand(), Addr))
1175 return false;
1176
1177 unsigned Opc;
Dan Gohman2e644382016-05-10 17:39:48 +00001178 bool VTIsi1 = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001179 switch (getSimpleType(Store->getValueOperand()->getType())) {
1180 case MVT::i1:
1181 VTIsi1 = true;
Dan Gohman861bec22018-02-09 22:59:01 +00001182 LLVM_FALLTHROUGH;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001183 case MVT::i8:
1184 Opc = WebAssembly::STORE8_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001185 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001186 case MVT::i16:
1187 Opc = WebAssembly::STORE16_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001188 break;
1189 case MVT::i32:
1190 Opc = WebAssembly::STORE_I32;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001191 break;
1192 case MVT::i64:
1193 Opc = WebAssembly::STORE_I64;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001194 break;
1195 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +00001196 Opc = WebAssembly::STORE_F32;
Dan Gohman2e644382016-05-10 17:39:48 +00001197 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001198 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +00001199 Opc = WebAssembly::STORE_F64;
Dan Gohman2e644382016-05-10 17:39:48 +00001200 break;
1201 default: return false;
1202 }
1203
1204 materializeLoadStoreOperands(Addr);
1205
1206 unsigned ValueReg = getRegForValue(Store->getValueOperand());
Derek Schuff732636d2016-08-04 18:01:52 +00001207 if (ValueReg == 0)
1208 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001209 if (VTIsi1)
Dan Gohman3a5ce732016-05-11 16:32:42 +00001210 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
Dan Gohman2e644382016-05-10 17:39:48 +00001211
Dan Gohman7f1bdb22016-10-06 22:08:28 +00001212 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
Dan Gohman2e644382016-05-10 17:39:48 +00001213
1214 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1215
1216 MIB.addReg(ValueReg);
1217 return true;
1218}
1219
1220bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1221 const BranchInst *Br = cast<BranchInst>(I);
1222 if (Br->isUnconditional()) {
1223 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1224 fastEmitBranch(MSucc, Br->getDebugLoc());
1225 return true;
1226 }
1227
1228 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1229 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1230
Dan Gohman33e694a2016-05-12 04:19:09 +00001231 bool Not;
1232 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
Derek Schuff732636d2016-08-04 18:01:52 +00001233 if (CondReg == 0)
1234 return false;
Dan Gohman2e644382016-05-10 17:39:48 +00001235
Dan Gohman33e694a2016-05-12 04:19:09 +00001236 unsigned Opc = WebAssembly::BR_IF;
1237 if (Not)
1238 Opc = WebAssembly::BR_UNLESS;
1239
Dan Gohman2e644382016-05-10 17:39:48 +00001240 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1241 .addMBB(TBB)
1242 .addReg(CondReg);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001243
Dan Gohman2e644382016-05-10 17:39:48 +00001244 finishCondBranch(Br->getParent(), TBB, FBB);
1245 return true;
1246}
1247
1248bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1249 if (!FuncInfo.CanLowerReturn)
1250 return false;
1251
1252 const ReturnInst *Ret = cast<ReturnInst>(I);
1253
1254 if (Ret->getNumOperands() == 0) {
1255 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1256 TII.get(WebAssembly::RETURN_VOID));
1257 return true;
1258 }
1259
1260 Value *RV = Ret->getOperand(0);
Derek Schuff39bf39f2016-08-02 23:16:09 +00001261 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1262 return false;
1263
Dan Gohman2e644382016-05-10 17:39:48 +00001264 unsigned Opc;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001265 switch (getSimpleType(RV->getType())) {
1266 case MVT::i1: case MVT::i8:
1267 case MVT::i16: case MVT::i32:
1268 Opc = WebAssembly::RETURN_I32;
Dan Gohman2e644382016-05-10 17:39:48 +00001269 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +00001270 case MVT::i64:
1271 Opc = WebAssembly::RETURN_I64;
1272 break;
Derek Schuff39bf39f2016-08-02 23:16:09 +00001273 case MVT::f32:
1274 Opc = WebAssembly::RETURN_F32;
1275 break;
1276 case MVT::f64:
1277 Opc = WebAssembly::RETURN_F64;
1278 break;
1279 case MVT::v16i8:
1280 Opc = WebAssembly::RETURN_v16i8;
1281 break;
1282 case MVT::v8i16:
1283 Opc = WebAssembly::RETURN_v8i16;
1284 break;
1285 case MVT::v4i32:
1286 Opc = WebAssembly::RETURN_v4i32;
1287 break;
1288 case MVT::v4f32:
1289 Opc = WebAssembly::RETURN_v4f32;
1290 break;
Heejin Ahn0de58722018-03-08 04:05:37 +00001291 case MVT::ExceptRef:
1292 Opc = WebAssembly::RETURN_EXCEPT_REF;
1293 break;
Dan Gohman2e644382016-05-10 17:39:48 +00001294 default: return false;
1295 }
1296
Dan Gohman33e694a2016-05-12 04:19:09 +00001297 unsigned Reg;
1298 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1299 Reg = getRegForSignedValue(RV);
1300 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1301 Reg = getRegForUnsignedValue(RV);
1302 else
1303 Reg = getRegForValue(RV);
1304
Derek Schuff732636d2016-08-04 18:01:52 +00001305 if (Reg == 0)
1306 return false;
1307
Dan Gohman2e644382016-05-10 17:39:48 +00001308 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1309 return true;
1310}
1311
1312bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1313 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1314 TII.get(WebAssembly::UNREACHABLE));
1315 return true;
1316}
1317
1318bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1319 switch (I->getOpcode()) {
Dan Gohman33e694a2016-05-12 04:19:09 +00001320 case Instruction::Call:
1321 if (selectCall(I))
1322 return true;
1323 break;
1324 case Instruction::Select: return selectSelect(I);
1325 case Instruction::Trunc: return selectTrunc(I);
Dan Gohman3a5ce732016-05-11 16:32:42 +00001326 case Instruction::ZExt: return selectZExt(I);
1327 case Instruction::SExt: return selectSExt(I);
1328 case Instruction::ICmp: return selectICmp(I);
1329 case Instruction::FCmp: return selectFCmp(I);
Dan Gohman2e644382016-05-10 17:39:48 +00001330 case Instruction::BitCast: return selectBitCast(I);
1331 case Instruction::Load: return selectLoad(I);
1332 case Instruction::Store: return selectStore(I);
1333 case Instruction::Br: return selectBr(I);
1334 case Instruction::Ret: return selectRet(I);
1335 case Instruction::Unreachable: return selectUnreachable(I);
1336 default: break;
Dan Gohman7b634842015-08-24 18:44:37 +00001337 }
1338
1339 // Fall back to target-independent instruction selection.
1340 return selectOperator(I, I->getOpcode());
1341}
1342
1343FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1344 const TargetLibraryInfo *LibInfo) {
1345 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1346}