blob: ee87e1bb4f02a0bb0e5ad870da47eaea729b856f [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///
15//===----------------------------------------------------------------------===//
16
17#include "WebAssembly.h"
18#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19#include "WebAssemblySubtarget.h"
20#include "WebAssemblyTargetMachine.h"
21#include "llvm/Analysis/BranchProbabilityInfo.h"
22#include "llvm/CodeGen/FastISel.h"
23#include "llvm/CodeGen/FunctionLoweringInfo.h"
24#include "llvm/CodeGen/MachineConstantPool.h"
25#include "llvm/CodeGen/MachineFrameInfo.h"
26#include "llvm/CodeGen/MachineInstrBuilder.h"
27#include "llvm/CodeGen/MachineRegisterInfo.h"
28#include "llvm/IR/DataLayout.h"
29#include "llvm/IR/DerivedTypes.h"
30#include "llvm/IR/Function.h"
31#include "llvm/IR/GetElementPtrTypeIterator.h"
32#include "llvm/IR/GlobalAlias.h"
33#include "llvm/IR/GlobalVariable.h"
34#include "llvm/IR/Instructions.h"
35#include "llvm/IR/IntrinsicInst.h"
36#include "llvm/IR/Operator.h"
37using namespace llvm;
38
39#define DEBUG_TYPE "wasm-fastisel"
40
41namespace {
42
43class WebAssemblyFastISel final : public FastISel {
Dan Gohman2e644382016-05-10 17:39:48 +000044 // All possible address modes.
45 class Address {
46 public:
47 typedef enum { RegBase, FrameIndexBase } BaseKind;
48
49 private:
50 BaseKind Kind;
51 union {
52 unsigned Reg;
53 int FI;
54 } Base;
55
56 int64_t Offset;
57
58 const GlobalValue *GV;
59
60 public:
61 // Innocuous defaults for our address.
62 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; }
63 void setKind(BaseKind K) { Kind = K; }
64 BaseKind getKind() const { return Kind; }
65 bool isRegBase() const { return Kind == RegBase; }
66 bool isFIBase() const { return Kind == FrameIndexBase; }
67 void setReg(unsigned Reg) {
68 assert(isRegBase() && "Invalid base register access!");
69 Base.Reg = Reg;
70 }
71 unsigned getReg() const {
72 assert(isRegBase() && "Invalid base register access!");
73 return Base.Reg;
74 }
75 void setFI(unsigned FI) {
76 assert(isFIBase() && "Invalid base frame index access!");
77 Base.FI = FI;
78 }
79 unsigned getFI() const {
80 assert(isFIBase() && "Invalid base frame index access!");
81 return Base.FI;
82 }
83
84 void setOffset(int64_t Offset_) { Offset = Offset_; }
85 int64_t getOffset() const { return Offset; }
86 void setGlobalValue(const GlobalValue *G) { GV = G; }
87 const GlobalValue *getGlobalValue() const { return GV; }
88 };
89
Dan Gohman7b634842015-08-24 18:44:37 +000090 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
91 /// right decision when generating code for different targets.
92 const WebAssemblySubtarget *Subtarget;
93 LLVMContext *Context;
94
Dan Gohman7b634842015-08-24 18:44:37 +000095private:
Dan Gohman2e644382016-05-10 17:39:48 +000096 // Utility helper routines
Dan Gohman3a5ce732016-05-11 16:32:42 +000097 MVT::SimpleValueType getSimpleType(Type *Ty) {
98 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
99 return VT.isSimple() ? VT.getSimpleVT().SimpleTy :
100 MVT::INVALID_SIMPLE_VALUE_TYPE;
101 }
102 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
103 switch (VT) {
104 case MVT::i1:
105 case MVT::i8:
106 case MVT::i16:
107 case MVT::i32:
108 return MVT::i32;
109 case MVT::i64:
110 return MVT::i64;
111 default:
112 break;
113 }
114 return MVT::INVALID_SIMPLE_VALUE_TYPE;
115 }
Dan Gohman2e644382016-05-10 17:39:48 +0000116 bool computeAddress(const Value *Obj, Address &Addr);
117 void materializeLoadStoreOperands(Address &Addr);
118 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
119 MachineMemOperand *MMO);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000120 unsigned maskI1Value(unsigned Reg, const Value *V);
Dan Gohman2e644382016-05-10 17:39:48 +0000121 unsigned getRegForI1Value(const Value *V);
Dan Gohman3a5ce732016-05-11 16:32:42 +0000122 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
123 MVT::SimpleValueType From);
124 unsigned signExtendToI32(unsigned Reg, const Value *V,
125 MVT::SimpleValueType From);
126 unsigned zeroExtend(unsigned Reg, const Value *V,
127 MVT::SimpleValueType From,
128 MVT::SimpleValueType To);
129 unsigned signExtend(unsigned Reg, const Value *V,
130 MVT::SimpleValueType From,
131 MVT::SimpleValueType To);
132 unsigned getRegForUnsignedValue(const Value *V);
133 unsigned getRegForSignedValue(const Value *V);
134 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
135 unsigned notValue(unsigned Reg);
Dan Gohman2e644382016-05-10 17:39:48 +0000136
137 // Backend specific FastISel code.
138 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
139 unsigned fastMaterializeConstant(const Constant *C) override;
140
141 // Selection routines.
Dan Gohman3a5ce732016-05-11 16:32:42 +0000142 bool selectZExt(const Instruction *I);
143 bool selectSExt(const Instruction *I);
144 bool selectICmp(const Instruction *I);
145 bool selectFCmp(const Instruction *I);
Dan Gohman2e644382016-05-10 17:39:48 +0000146 bool selectBitCast(const Instruction *I);
147 bool selectLoad(const Instruction *I);
148 bool selectStore(const Instruction *I);
149 bool selectBr(const Instruction *I);
150 bool selectRet(const Instruction *I);
151 bool selectUnreachable(const Instruction *I);
152
Dan Gohman7b634842015-08-24 18:44:37 +0000153public:
154 // Backend specific FastISel code.
155 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
156 const TargetLibraryInfo *LibInfo)
157 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
158 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
159 Context = &FuncInfo.Fn->getContext();
160 }
161
162 bool fastSelectInstruction(const Instruction *I) override;
163
164#include "WebAssemblyGenFastISel.inc"
165};
166
167} // end anonymous namespace
168
Dan Gohman2e644382016-05-10 17:39:48 +0000169bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
170
171 const User *U = nullptr;
172 unsigned Opcode = Instruction::UserOp1;
173 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
174 // Don't walk into other basic blocks unless the object is an alloca from
175 // another block, otherwise it may not have a virtual register assigned.
176 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
177 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
178 Opcode = I->getOpcode();
179 U = I;
180 }
181 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
182 Opcode = C->getOpcode();
183 U = C;
184 }
185
186 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
187 if (Ty->getAddressSpace() > 255)
188 // Fast instruction selection doesn't support the special
189 // address spaces.
190 return false;
191
192 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
193 if (Addr.getGlobalValue())
194 return false;
195 Addr.setGlobalValue(GV);
196 return true;
197 }
198
199 switch (Opcode) {
Dan Gohman7b634842015-08-24 18:44:37 +0000200 default:
201 break;
Dan Gohman2e644382016-05-10 17:39:48 +0000202 case Instruction::BitCast: {
203 // Look through bitcasts.
204 return computeAddress(U->getOperand(0), Addr);
205 }
206 case Instruction::IntToPtr: {
207 // Look past no-op inttoptrs.
208 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
209 TLI.getPointerTy(DL))
210 return computeAddress(U->getOperand(0), Addr);
211 break;
212 }
213 case Instruction::PtrToInt: {
214 // Look past no-op ptrtoints.
215 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
216 return computeAddress(U->getOperand(0), Addr);
217 break;
218 }
219 case Instruction::GetElementPtr: {
220 Address SavedAddr = Addr;
221 uint64_t TmpOffset = Addr.getOffset();
222 // Iterate through the GEP folding the constants into offsets where
223 // we can.
224 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
225 GTI != E; ++GTI) {
226 const Value *Op = GTI.getOperand();
227 if (StructType *STy = dyn_cast<StructType>(*GTI)) {
228 const StructLayout *SL = DL.getStructLayout(STy);
229 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
230 TmpOffset += SL->getElementOffset(Idx);
231 } else {
232 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
233 for (;;) {
234 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
235 // Constant-offset addressing.
236 TmpOffset += CI->getSExtValue() * S;
237 break;
238 }
239 if (canFoldAddIntoGEP(U, Op)) {
240 // A compatible add with a constant operand. Fold the constant.
241 ConstantInt *CI =
242 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
243 TmpOffset += CI->getSExtValue() * S;
244 // Iterate on the other operand.
245 Op = cast<AddOperator>(Op)->getOperand(0);
246 continue;
247 }
248 // Unsupported
249 goto unsupported_gep;
250 }
251 }
252 }
253 // Try to grab the base operand now.
254 Addr.setOffset(TmpOffset);
255 if (computeAddress(U->getOperand(0), Addr))
256 return true;
257 // We failed, restore everything and try the other options.
258 Addr = SavedAddr;
259 unsupported_gep:
260 break;
261 }
262 case Instruction::Alloca: {
263 const AllocaInst *AI = cast<AllocaInst>(Obj);
264 DenseMap<const AllocaInst *, int>::iterator SI =
265 FuncInfo.StaticAllocaMap.find(AI);
266 if (SI != FuncInfo.StaticAllocaMap.end()) {
267 Addr.setKind(Address::FrameIndexBase);
268 Addr.setFI(SI->second);
269 return true;
270 }
271 break;
272 }
273 case Instruction::Add: {
274 // Adds of constants are common and easy enough.
275 const Value *LHS = U->getOperand(0);
276 const Value *RHS = U->getOperand(1);
277
278 if (isa<ConstantInt>(LHS))
279 std::swap(LHS, RHS);
280
281 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
282 Addr.setOffset(Addr.getOffset() + CI->getSExtValue());
283 return computeAddress(LHS, Addr);
284 }
285
286 Address Backup = Addr;
287 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
288 return true;
289 Addr = Backup;
290
291 break;
292 }
293 case Instruction::Sub: {
294 // Subs of constants are common and easy enough.
295 const Value *LHS = U->getOperand(0);
296 const Value *RHS = U->getOperand(1);
297
298 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
299 Addr.setOffset(Addr.getOffset() - CI->getSExtValue());
300 return computeAddress(LHS, Addr);
301 }
302 break;
303 }
304 }
305 Addr.setReg(getRegForValue(Obj));
306 return Addr.getReg() != 0;
307}
308
309void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
310 if (Addr.isRegBase()) {
311 unsigned Reg = Addr.getReg();
312 if (Reg == 0) {
313 Reg = createResultReg(Subtarget->hasAddr64() ?
314 &WebAssembly::I64RegClass :
315 &WebAssembly::I32RegClass);
316 unsigned Opc = Subtarget->hasAddr64() ?
317 WebAssembly::CONST_I64 :
318 WebAssembly::CONST_I32;
319 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
320 .addImm(0);
321 Addr.setReg(Reg);
322 }
323 }
324}
325
326void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
327 const MachineInstrBuilder &MIB,
328 MachineMemOperand *MMO) {
329 if (const GlobalValue *GV = Addr.getGlobalValue())
330 MIB.addGlobalAddress(GV, Addr.getOffset());
331 else
332 MIB.addImm(Addr.getOffset());
333
334 if (Addr.isRegBase())
335 MIB.addReg(Addr.getReg());
336 else
337 MIB.addFrameIndex(Addr.getFI());
338
339 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
340 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
341 MIB.addImm(0);
342
343 MIB.addMemOperand(MMO);
344}
345
Dan Gohman3a5ce732016-05-11 16:32:42 +0000346unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
347 return zeroExtendToI32(Reg, V, MVT::i1);
Dan Gohman2e644382016-05-10 17:39:48 +0000348}
349
350unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V) {
Dan Gohman3a5ce732016-05-11 16:32:42 +0000351 return maskI1Value(getRegForValue(V), V);
352}
353
354unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
355 MVT::SimpleValueType From) {
356 switch (From) {
357 case MVT::i1:
358 // If the value is naturally an i1, we don't need to mask it.
359 // TODO: Recursively examine selects, phis, and, or, xor, constants.
360 if (From == MVT::i1 && V != nullptr && isa<CmpInst>(V))
361 return Reg;
362 break;
363 case MVT::i32:
364 return Reg;
365 default:
366 return 0;
367 }
368
369 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
370 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
371 TII.get(WebAssembly::CONST_I32), Imm)
372 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
373
374 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
375 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
376 TII.get(WebAssembly::AND_I32), Result)
377 .addReg(Reg)
378 .addReg(Imm);
379
380 return Result;
381}
382
383unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
384 MVT::SimpleValueType From) {
385 switch (From) {
386 case MVT::i1:
387 case MVT::i8:
388 case MVT::i16:
389 break;
390 case MVT::i32:
391 return Reg;
392 default:
393 return false;
394 }
395
396 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
397 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
398 TII.get(WebAssembly::CONST_I32), Imm)
399 .addImm(32 - MVT(From).getSizeInBits());
400
401 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
402 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
403 TII.get(WebAssembly::SHL_I32), Left)
404 .addReg(Reg)
405 .addReg(Imm);
406
407 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
408 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
409 TII.get(WebAssembly::SHR_S_I32), Right)
410 .addReg(Left)
411 .addReg(Imm);
412
413 return Right;
414}
415
416unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
417 MVT::SimpleValueType From,
418 MVT::SimpleValueType To) {
419 if (To == MVT::i64) {
420 if (From == MVT::i64)
421 return Reg;
422
423 Reg = zeroExtendToI32(Reg, V, From);
424
425 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
426 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
427 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
428 .addReg(Reg);
429 return Result;
430 }
431
432 switch (From) {
433 case MVT::i1:
434 // If the value is naturally an i1, we don't need to mask it.
435 // TODO: Recursively examine selects, phis, and, or, xor, constants.
436 if (From == MVT::i1 && V != nullptr && isa<CmpInst>(V))
437 return Reg;
438 case MVT::i8:
439 case MVT::i16:
440 break;
441 case MVT::i32:
442 return Reg;
443 default:
444 return 0;
445 }
446
447 return zeroExtendToI32(Reg, V, From);
448}
449
450unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
451 MVT::SimpleValueType From,
452 MVT::SimpleValueType To) {
453 if (To == MVT::i64) {
454 if (From == MVT::i64)
455 return Reg;
456
457 Reg = signExtendToI32(Reg, V, From);
458
459 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
460 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
461 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
462 .addReg(Reg);
463 return Result;
464 }
465
466 switch (From) {
467 case MVT::i1:
468 case MVT::i8:
469 case MVT::i16:
470 break;
471 case MVT::i32:
472 return Reg;
473 default:
474 return false;
475 }
476
477 return signExtendToI32(Reg, V, From);
478}
479
480unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
481 MVT::SimpleValueType From = getSimpleType(V->getType());
482 MVT::SimpleValueType To = getLegalType(From);
483 return zeroExtend(getRegForValue(V), V, From, To);
484}
485
486unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
487 MVT::SimpleValueType From = getSimpleType(V->getType());
488 MVT::SimpleValueType To = getLegalType(From);
489 return zeroExtend(getRegForValue(V), V, From, To);
490}
491
492unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
493 bool IsSigned) {
494 return IsSigned ? getRegForSignedValue(V) :
495 getRegForUnsignedValue(V);
496}
497
498unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
499 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
500 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
501 TII.get(WebAssembly::EQZ_I32), NotReg)
502 .addReg(Reg);
503 return NotReg;
Dan Gohman2e644382016-05-10 17:39:48 +0000504}
505
506unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
507 DenseMap<const AllocaInst *, int>::iterator SI =
508 FuncInfo.StaticAllocaMap.find(AI);
509
510 if (SI != FuncInfo.StaticAllocaMap.end()) {
511 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
512 &WebAssembly::I64RegClass :
513 &WebAssembly::I32RegClass);
514 unsigned Opc = Subtarget->hasAddr64() ?
515 WebAssembly::COPY_LOCAL_I64 :
516 WebAssembly::COPY_LOCAL_I32;
517 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
518 .addFrameIndex(SI->second);
519 return ResultReg;
520 }
521
522 return 0;
523}
524
525unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
526 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
527 unsigned Reg = createResultReg(Subtarget->hasAddr64() ?
528 &WebAssembly::I64RegClass :
529 &WebAssembly::I32RegClass);
530 unsigned Opc = Subtarget->hasAddr64() ?
531 WebAssembly::CONST_I64 :
532 WebAssembly::CONST_I32;
533 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
534 .addGlobalAddress(GV);
535 return Reg;
536 }
537
538 // Let target-independent code handle it.
539 return 0;
540}
541
Dan Gohman3a5ce732016-05-11 16:32:42 +0000542bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
543 const ZExtInst *ZExt = cast<ZExtInst>(I);
544
545 unsigned Reg = getRegForUnsignedValue(ZExt->getOperand(0));
546 if (Reg == 0)
547 return false;
548
549 updateValueMap(ZExt, Reg);
550 return true;
551}
552
553bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
554 const SExtInst *SExt = cast<SExtInst>(I);
555
556 unsigned Reg = getRegForSignedValue(SExt->getOperand(0));
557 if (Reg == 0)
558 return false;
559
560 updateValueMap(SExt, Reg);
561 return true;
562}
563
564bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
565 const ICmpInst *ICmp = cast<ICmpInst>(I);
566
567 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
568 unsigned Opc;
569 bool isSigned = false;
570 switch (ICmp->getPredicate()) {
571 case ICmpInst::ICMP_EQ:
572 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
573 break;
574 case ICmpInst::ICMP_NE:
575 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
576 break;
577 case ICmpInst::ICMP_UGT:
578 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
579 break;
580 case ICmpInst::ICMP_UGE:
581 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
582 break;
583 case ICmpInst::ICMP_ULT:
584 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
585 break;
586 case ICmpInst::ICMP_ULE:
587 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
588 break;
589 case ICmpInst::ICMP_SGT:
590 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
591 isSigned = true;
592 break;
593 case ICmpInst::ICMP_SGE:
594 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
595 isSigned = true;
596 break;
597 case ICmpInst::ICMP_SLT:
598 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
599 isSigned = true;
600 break;
601 case ICmpInst::ICMP_SLE:
602 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
603 isSigned = true;
604 break;
605 default: return false;
606 }
607
608 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
609 if (LHS == 0)
610 return false;
611
612 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
613 if (RHS == 0)
614 return false;
615
616 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
617 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
618 .addReg(LHS)
619 .addReg(RHS);
620 updateValueMap(ICmp, ResultReg);
621 return true;
622}
623
624bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
625 const FCmpInst *FCmp = cast<FCmpInst>(I);
626
627 unsigned LHS = getRegForValue(FCmp->getOperand(0));
628 if (LHS == 0)
629 return false;
630
631 unsigned RHS = getRegForValue(FCmp->getOperand(1));
632 if (RHS == 0)
633 return false;
634
635 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
636 unsigned Opc;
637 bool Not = false;
638 switch (FCmp->getPredicate()) {
639 case FCmpInst::FCMP_OEQ:
640 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
641 break;
642 case FCmpInst::FCMP_UNE:
643 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
644 break;
645 case FCmpInst::FCMP_OGT:
646 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
647 break;
648 case FCmpInst::FCMP_OGE:
649 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
650 break;
651 case FCmpInst::FCMP_OLT:
652 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
653 break;
654 case FCmpInst::FCMP_OLE:
655 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
656 break;
657 case FCmpInst::FCMP_UGT:
658 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
659 Not = true;
660 break;
661 case FCmpInst::FCMP_UGE:
662 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
663 Not = true;
664 break;
665 case FCmpInst::FCMP_ULT:
666 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
667 Not = true;
668 break;
669 case FCmpInst::FCMP_ULE:
670 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
671 Not = true;
672 break;
673 default:
674 return false;
675 }
676
677 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
678 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
679 .addReg(LHS)
680 .addReg(RHS);
681
682 if (Not)
683 ResultReg = notValue(ResultReg);
684
685 updateValueMap(FCmp, ResultReg);
686 return true;
687}
688
Dan Gohman2e644382016-05-10 17:39:48 +0000689bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
690 // Target-independent code can handle this, except it doesn't set the dead
691 // flag on the ARGUMENTS clobber, so we have to do that manually in order
692 // to satisfy code that expects this of isBitcast() instructions.
693 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
694 EVT RetVT = TLI.getValueType(DL, I->getType());
695 if (!VT.isSimple() || !RetVT.isSimple())
696 return false;
697 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
698 getRegForValue(I->getOperand(0)),
699 I->getOperand(0)->hasOneUse());
700 if (!Reg)
701 return false;
702 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
703 --Iter;
704 assert(Iter->isBitcast());
705 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
706 updateValueMap(I, Reg);
707 return true;
708}
709
710bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
711 const LoadInst *Load = cast<LoadInst>(I);
712 if (Load->isAtomic())
713 return false;
714
715 Address Addr;
716 if (!computeAddress(Load->getPointerOperand(), Addr))
717 return false;
718
719 // TODO: Fold a following sign-/zero-extend into the load instruction.
720
721 unsigned Opc;
722 const TargetRegisterClass *RC;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000723 switch (getSimpleType(Load->getType())) {
724 case MVT::i1:
725 case MVT::i8:
726 Opc = WebAssembly::LOAD8_U_I32;
727 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +0000728 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000729 case MVT::i16:
730 Opc = WebAssembly::LOAD16_U_I32;
731 RC = &WebAssembly::I32RegClass;
732 break;
733 case MVT::i32:
734 Opc = WebAssembly::LOAD_I32;
735 RC = &WebAssembly::I32RegClass;
736 break;
737 case MVT::i64:
738 Opc = WebAssembly::LOAD_I64;
739 RC = &WebAssembly::I64RegClass;
740 break;
741 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +0000742 Opc = WebAssembly::LOAD_F32;
743 RC = &WebAssembly::F32RegClass;
744 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000745 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +0000746 Opc = WebAssembly::LOAD_F64;
747 RC = &WebAssembly::F64RegClass;
748 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000749 default:
750 return false;
Dan Gohman2e644382016-05-10 17:39:48 +0000751 }
752
753 materializeLoadStoreOperands(Addr);
754
755 unsigned ResultReg = createResultReg(RC);
756 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
757 ResultReg);
758
759 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
760
761 updateValueMap(Load, ResultReg);
762 return true;
763}
764
765bool WebAssemblyFastISel::selectStore(const Instruction *I) {
766 const StoreInst *Store = cast<StoreInst>(I);
767 if (Store->isAtomic())
768 return false;
769
770 Address Addr;
771 if (!computeAddress(Store->getPointerOperand(), Addr))
772 return false;
773
774 unsigned Opc;
775 const TargetRegisterClass *RC;
776 bool VTIsi1 = false;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000777 switch (getSimpleType(Store->getValueOperand()->getType())) {
778 case MVT::i1:
779 VTIsi1 = true;
780 case MVT::i8:
781 Opc = WebAssembly::STORE8_I32;
782 RC = &WebAssembly::I32RegClass;
Dan Gohman2e644382016-05-10 17:39:48 +0000783 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000784 case MVT::i16:
785 Opc = WebAssembly::STORE16_I32;
786 RC = &WebAssembly::I32RegClass;
787 break;
788 case MVT::i32:
789 Opc = WebAssembly::STORE_I32;
790 RC = &WebAssembly::I32RegClass;
791 break;
792 case MVT::i64:
793 Opc = WebAssembly::STORE_I64;
794 RC = &WebAssembly::I64RegClass;
795 break;
796 case MVT::f32:
Dan Gohman2e644382016-05-10 17:39:48 +0000797 Opc = WebAssembly::STORE_F32;
798 RC = &WebAssembly::F32RegClass;
799 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000800 case MVT::f64:
Dan Gohman2e644382016-05-10 17:39:48 +0000801 Opc = WebAssembly::STORE_F64;
802 RC = &WebAssembly::F64RegClass;
803 break;
804 default: return false;
805 }
806
807 materializeLoadStoreOperands(Addr);
808
809 unsigned ValueReg = getRegForValue(Store->getValueOperand());
810 if (VTIsi1)
Dan Gohman3a5ce732016-05-11 16:32:42 +0000811 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
Dan Gohman2e644382016-05-10 17:39:48 +0000812
813 unsigned ResultReg = createResultReg(RC);
814 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
815 ResultReg);
816
817 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
818
819 MIB.addReg(ValueReg);
820 return true;
821}
822
823bool WebAssemblyFastISel::selectBr(const Instruction *I) {
824 const BranchInst *Br = cast<BranchInst>(I);
825 if (Br->isUnconditional()) {
826 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
827 fastEmitBranch(MSucc, Br->getDebugLoc());
828 return true;
829 }
830
831 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
832 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
833
834 Value *Cond = Br->getCondition();
835 unsigned Opc = WebAssembly::BR_IF;
836 if (BinaryOperator::isNot(Cond)) {
837 Cond = BinaryOperator::getNotArgument(Cond);
838 Opc = WebAssembly::BR_UNLESS;
839 }
840
841 unsigned CondReg = getRegForI1Value(Cond);
842 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
843 .addMBB(TBB)
844 .addReg(CondReg);
845
846 finishCondBranch(Br->getParent(), TBB, FBB);
847 return true;
848}
849
850bool WebAssemblyFastISel::selectRet(const Instruction *I) {
851 if (!FuncInfo.CanLowerReturn)
852 return false;
853
854 const ReturnInst *Ret = cast<ReturnInst>(I);
855
856 if (Ret->getNumOperands() == 0) {
857 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
858 TII.get(WebAssembly::RETURN_VOID));
859 return true;
860 }
861
862 Value *RV = Ret->getOperand(0);
863 unsigned Opc;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000864 switch (getSimpleType(RV->getType())) {
865 case MVT::i1: case MVT::i8:
866 case MVT::i16: case MVT::i32:
867 Opc = WebAssembly::RETURN_I32;
Dan Gohman2e644382016-05-10 17:39:48 +0000868 break;
Dan Gohman3a5ce732016-05-11 16:32:42 +0000869 case MVT::i64:
870 Opc = WebAssembly::RETURN_I64;
871 break;
872 case MVT::f32: Opc = WebAssembly::RETURN_F32; break;
873 case MVT::f64: Opc = WebAssembly::RETURN_F64; break;
Dan Gohman2e644382016-05-10 17:39:48 +0000874 default: return false;
875 }
876
877 unsigned Reg = getRegForValue(RV);
878 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
879 return true;
880}
881
882bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
883 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
884 TII.get(WebAssembly::UNREACHABLE));
885 return true;
886}
887
888bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
889 switch (I->getOpcode()) {
Dan Gohman3a5ce732016-05-11 16:32:42 +0000890 case Instruction::ZExt: return selectZExt(I);
891 case Instruction::SExt: return selectSExt(I);
892 case Instruction::ICmp: return selectICmp(I);
893 case Instruction::FCmp: return selectFCmp(I);
Dan Gohman2e644382016-05-10 17:39:48 +0000894 case Instruction::BitCast: return selectBitCast(I);
895 case Instruction::Load: return selectLoad(I);
896 case Instruction::Store: return selectStore(I);
897 case Instruction::Br: return selectBr(I);
898 case Instruction::Ret: return selectRet(I);
899 case Instruction::Unreachable: return selectUnreachable(I);
900 default: break;
Dan Gohman7b634842015-08-24 18:44:37 +0000901 }
902
903 // Fall back to target-independent instruction selection.
904 return selectOperator(I, I->getOpcode());
905}
906
907FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
908 const TargetLibraryInfo *LibInfo) {
909 return new WebAssemblyFastISel(FuncInfo, LibInfo);
910}