1 //===-- 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 /// 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 /// TODO: kill flags
16 ///
17 //===----------------------------------------------------------------------===//
18
19 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20 #include "WebAssembly.h"
21 #include "WebAssemblyMachineFunctionInfo.h"
22 #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"
40 #include "llvm/IR/PatternMatch.h"
41
42 using namespace llvm;
43 using namespace PatternMatch;
44
45 #define DEBUG_TYPE "wasm-fastisel"
46
47 namespace {
48
49 class WebAssemblyFastISel final : public FastISel {
50 // All possible address modes.
51 class Address {
52 public:
53 typedef enum { RegBase, FrameIndexBase } BaseKind;
54
55 private:
56 BaseKind Kind;
57 union {
58 unsigned Reg;
59 int FI;
60 } Base;
61
62 int64_t Offset;
63
64 const GlobalValue *GV;
65
66 public:
67 // Innocuous defaults for our address.
Address()68 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; }
setKind(BaseKind K)69 void setKind(BaseKind K) {
70 assert(!isSet() && "Can't change kind with non-zero base");
71 Kind = K;
72 }
getKind() const73 BaseKind getKind() const { return Kind; }
isRegBase() const74 bool isRegBase() const { return Kind == RegBase; }
isFIBase() const75 bool isFIBase() const { return Kind == FrameIndexBase; }
setReg(unsigned Reg)76 void setReg(unsigned Reg) {
77 assert(isRegBase() && "Invalid base register access!");
78 assert(Base.Reg == 0 && "Overwriting non-zero register");
79 Base.Reg = Reg;
80 }
getReg() const81 unsigned getReg() const {
82 assert(isRegBase() && "Invalid base register access!");
83 return Base.Reg;
84 }
setFI(unsigned FI)85 void setFI(unsigned FI) {
86 assert(isFIBase() && "Invalid base frame index access!");
87 assert(Base.FI == 0 && "Overwriting non-zero frame index");
88 Base.FI = FI;
89 }
getFI() const90 unsigned getFI() const {
91 assert(isFIBase() && "Invalid base frame index access!");
92 return Base.FI;
93 }
94
setOffset(int64_t Offset_)95 void setOffset(int64_t Offset_) {
96 assert(Offset_ >= 0 && "Offsets must be non-negative");
97 Offset = Offset_;
98 }
getOffset() const99 int64_t getOffset() const { return Offset; }
setGlobalValue(const GlobalValue * G)100 void setGlobalValue(const GlobalValue *G) { GV = G; }
getGlobalValue() const101 const GlobalValue *getGlobalValue() const { return GV; }
isSet() const102 bool isSet() const {
103 if (isRegBase()) {
104 return Base.Reg != 0;
105 } else {
106 return Base.FI != 0;
107 }
108 }
109 };
110
111 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
112 /// right decision when generating code for different targets.
113 const WebAssemblySubtarget *Subtarget;
114 LLVMContext *Context;
115
116 private:
117 // Utility helper routines
getSimpleType(Type * Ty)118 MVT::SimpleValueType getSimpleType(Type *Ty) {
119 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
120 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
121 : MVT::INVALID_SIMPLE_VALUE_TYPE;
122 }
getLegalType(MVT::SimpleValueType VT)123 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
124 switch (VT) {
125 case MVT::i1:
126 case MVT::i8:
127 case MVT::i16:
128 return MVT::i32;
129 case MVT::i32:
130 case MVT::i64:
131 case MVT::f32:
132 case MVT::f64:
133 case MVT::ExceptRef:
134 return VT;
135 case MVT::f16:
136 return MVT::f32;
137 case MVT::v16i8:
138 case MVT::v8i16:
139 case MVT::v4i32:
140 case MVT::v4f32:
141 if (Subtarget->hasSIMD128())
142 return VT;
143 break;
144 case MVT::v2i64:
145 case MVT::v2f64:
146 if (Subtarget->hasUnimplementedSIMD128())
147 return VT;
148 break;
149 default:
150 break;
151 }
152 return MVT::INVALID_SIMPLE_VALUE_TYPE;
153 }
154 bool computeAddress(const Value *Obj, Address &Addr);
155 void materializeLoadStoreOperands(Address &Addr);
156 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
157 MachineMemOperand *MMO);
158 unsigned maskI1Value(unsigned Reg, const Value *V);
159 unsigned getRegForI1Value(const Value *V, bool &Not);
160 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
161 MVT::SimpleValueType From);
162 unsigned signExtendToI32(unsigned Reg, const Value *V,
163 MVT::SimpleValueType From);
164 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
165 MVT::SimpleValueType To);
166 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
167 MVT::SimpleValueType To);
168 unsigned getRegForUnsignedValue(const Value *V);
169 unsigned getRegForSignedValue(const Value *V);
170 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
171 unsigned notValue(unsigned Reg);
172 unsigned copyValue(unsigned Reg);
173
174 // Backend specific FastISel code.
175 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
176 unsigned fastMaterializeConstant(const Constant *C) override;
177 bool fastLowerArguments() override;
178
179 // Selection routines.
180 bool selectCall(const Instruction *I);
181 bool selectSelect(const Instruction *I);
182 bool selectTrunc(const Instruction *I);
183 bool selectZExt(const Instruction *I);
184 bool selectSExt(const Instruction *I);
185 bool selectICmp(const Instruction *I);
186 bool selectFCmp(const Instruction *I);
187 bool selectBitCast(const Instruction *I);
188 bool selectLoad(const Instruction *I);
189 bool selectStore(const Instruction *I);
190 bool selectBr(const Instruction *I);
191 bool selectRet(const Instruction *I);
192 bool selectUnreachable(const Instruction *I);
193
194 public:
195 // Backend specific FastISel code.
WebAssemblyFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)196 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
197 const TargetLibraryInfo *LibInfo)
198 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
199 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
200 Context = &FuncInfo.Fn->getContext();
201 }
202
203 bool fastSelectInstruction(const Instruction *I) override;
204
205 #include "WebAssemblyGenFastISel.inc"
206 };
207
208 } // end anonymous namespace
209
computeAddress(const Value * Obj,Address & Addr)210 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
211
212 const User *U = nullptr;
213 unsigned Opcode = Instruction::UserOp1;
214 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
215 // Don't walk into other basic blocks unless the object is an alloca from
216 // another block, otherwise it may not have a virtual register assigned.
217 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
218 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
219 Opcode = I->getOpcode();
220 U = I;
221 }
222 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
223 Opcode = C->getOpcode();
224 U = C;
225 }
226
227 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
228 if (Ty->getAddressSpace() > 255)
229 // Fast instruction selection doesn't support the special
230 // address spaces.
231 return false;
232
233 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
234 if (Addr.getGlobalValue())
235 return false;
236 Addr.setGlobalValue(GV);
237 return true;
238 }
239
240 switch (Opcode) {
241 default:
242 break;
243 case Instruction::BitCast: {
244 // Look through bitcasts.
245 return computeAddress(U->getOperand(0), Addr);
246 }
247 case Instruction::IntToPtr: {
248 // Look past no-op inttoptrs.
249 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
250 TLI.getPointerTy(DL))
251 return computeAddress(U->getOperand(0), Addr);
252 break;
253 }
254 case Instruction::PtrToInt: {
255 // Look past no-op ptrtoints.
256 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
257 return computeAddress(U->getOperand(0), Addr);
258 break;
259 }
260 case Instruction::GetElementPtr: {
261 Address SavedAddr = Addr;
262 uint64_t TmpOffset = Addr.getOffset();
263 // Non-inbounds geps can wrap; wasm's offsets can't.
264 if (!cast<GEPOperator>(U)->isInBounds())
265 goto unsupported_gep;
266 // Iterate through the GEP folding the constants into offsets where
267 // we can.
268 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
269 GTI != E; ++GTI) {
270 const Value *Op = GTI.getOperand();
271 if (StructType *STy = GTI.getStructTypeOrNull()) {
272 const StructLayout *SL = DL.getStructLayout(STy);
273 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
274 TmpOffset += SL->getElementOffset(Idx);
275 } else {
276 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
277 for (;;) {
278 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
279 // Constant-offset addressing.
280 TmpOffset += CI->getSExtValue() * S;
281 break;
282 }
283 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
284 // An unscaled add of a register. Set it as the new base.
285 unsigned Reg = getRegForValue(Op);
286 if (Reg == 0)
287 return false;
288 Addr.setReg(Reg);
289 break;
290 }
291 if (canFoldAddIntoGEP(U, Op)) {
292 // A compatible add with a constant operand. Fold the constant.
293 ConstantInt *CI =
294 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
295 TmpOffset += CI->getSExtValue() * S;
296 // Iterate on the other operand.
297 Op = cast<AddOperator>(Op)->getOperand(0);
298 continue;
299 }
300 // Unsupported
301 goto unsupported_gep;
302 }
303 }
304 }
305 // Don't fold in negative offsets.
306 if (int64_t(TmpOffset) >= 0) {
307 // Try to grab the base operand now.
308 Addr.setOffset(TmpOffset);
309 if (computeAddress(U->getOperand(0), Addr))
310 return true;
311 }
312 // We failed, restore everything and try the other options.
313 Addr = SavedAddr;
314 unsupported_gep:
315 break;
316 }
317 case Instruction::Alloca: {
318 const AllocaInst *AI = cast<AllocaInst>(Obj);
319 DenseMap<const AllocaInst *, int>::iterator SI =
320 FuncInfo.StaticAllocaMap.find(AI);
321 if (SI != FuncInfo.StaticAllocaMap.end()) {
322 if (Addr.isSet()) {
323 return false;
324 }
325 Addr.setKind(Address::FrameIndexBase);
326 Addr.setFI(SI->second);
327 return true;
328 }
329 break;
330 }
331 case Instruction::Add: {
332 // Adds of constants are common and easy enough.
333 const Value *LHS = U->getOperand(0);
334 const Value *RHS = U->getOperand(1);
335
336 if (isa<ConstantInt>(LHS))
337 std::swap(LHS, RHS);
338
339 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
340 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
341 if (int64_t(TmpOffset) >= 0) {
342 Addr.setOffset(TmpOffset);
343 return computeAddress(LHS, Addr);
344 }
345 }
346
347 Address Backup = Addr;
348 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
349 return true;
350 Addr = Backup;
351
352 break;
353 }
354 case Instruction::Sub: {
355 // Subs of constants are common and easy enough.
356 const Value *LHS = U->getOperand(0);
357 const Value *RHS = U->getOperand(1);
358
359 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
360 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
361 if (TmpOffset >= 0) {
362 Addr.setOffset(TmpOffset);
363 return computeAddress(LHS, Addr);
364 }
365 }
366 break;
367 }
368 }
369 if (Addr.isSet()) {
370 return false;
371 }
372 unsigned Reg = getRegForValue(Obj);
373 if (Reg == 0)
374 return false;
375 Addr.setReg(Reg);
376 return Addr.getReg() != 0;
377 }
378
materializeLoadStoreOperands(Address & Addr)379 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
380 if (Addr.isRegBase()) {
381 unsigned Reg = Addr.getReg();
382 if (Reg == 0) {
383 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
384 : &WebAssembly::I32RegClass);
385 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
386 : WebAssembly::CONST_I32;
387 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
388 .addImm(0);
389 Addr.setReg(Reg);
390 }
391 }
392 }
393
addLoadStoreOperands(const Address & Addr,const MachineInstrBuilder & MIB,MachineMemOperand * MMO)394 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
395 const MachineInstrBuilder &MIB,
396 MachineMemOperand *MMO) {
397 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
398 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
399 MIB.addImm(0);
400
401 if (const GlobalValue *GV = Addr.getGlobalValue())
402 MIB.addGlobalAddress(GV, Addr.getOffset());
403 else
404 MIB.addImm(Addr.getOffset());
405
406 if (Addr.isRegBase())
407 MIB.addReg(Addr.getReg());
408 else
409 MIB.addFrameIndex(Addr.getFI());
410
411 MIB.addMemOperand(MMO);
412 }
413
maskI1Value(unsigned Reg,const Value * V)414 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
415 return zeroExtendToI32(Reg, V, MVT::i1);
416 }
417
getRegForI1Value(const Value * V,bool & Not)418 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
419 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
420 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
421 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
422 Not = ICmp->isTrueWhenEqual();
423 return getRegForValue(ICmp->getOperand(0));
424 }
425
426 Value *NotV;
427 if (match(V, m_Not(m_Value(NotV))) && V->getType()->isIntegerTy(32)) {
428 Not = true;
429 return getRegForValue(NotV);
430 }
431
432 Not = false;
433 unsigned Reg = getRegForValue(V);
434 if (Reg == 0)
435 return 0;
436 return maskI1Value(Reg, V);
437 }
438
zeroExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)439 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
440 MVT::SimpleValueType From) {
441 if (Reg == 0)
442 return 0;
443
444 switch (From) {
445 case MVT::i1:
446 // If the value is naturally an i1, we don't need to mask it. We only know
447 // if a value is naturally an i1 if it is definitely lowered by FastISel,
448 // not a DAG ISel fallback.
449 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
450 return copyValue(Reg);
451 break;
452 case MVT::i8:
453 case MVT::i16:
454 break;
455 case MVT::i32:
456 return copyValue(Reg);
457 default:
458 return 0;
459 }
460
461 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
462 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
463 TII.get(WebAssembly::CONST_I32), Imm)
464 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
465
466 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
467 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
468 TII.get(WebAssembly::AND_I32), Result)
469 .addReg(Reg)
470 .addReg(Imm);
471
472 return Result;
473 }
474
signExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)475 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
476 MVT::SimpleValueType From) {
477 if (Reg == 0)
478 return 0;
479
480 switch (From) {
481 case MVT::i1:
482 case MVT::i8:
483 case MVT::i16:
484 break;
485 case MVT::i32:
486 return copyValue(Reg);
487 default:
488 return 0;
489 }
490
491 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
492 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
493 TII.get(WebAssembly::CONST_I32), Imm)
494 .addImm(32 - MVT(From).getSizeInBits());
495
496 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
497 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
498 TII.get(WebAssembly::SHL_I32), Left)
499 .addReg(Reg)
500 .addReg(Imm);
501
502 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
503 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
504 TII.get(WebAssembly::SHR_S_I32), Right)
505 .addReg(Left)
506 .addReg(Imm);
507
508 return Right;
509 }
510
zeroExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)511 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
512 MVT::SimpleValueType From,
513 MVT::SimpleValueType To) {
514 if (To == MVT::i64) {
515 if (From == MVT::i64)
516 return copyValue(Reg);
517
518 Reg = zeroExtendToI32(Reg, V, From);
519
520 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
521 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
522 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
523 .addReg(Reg);
524 return Result;
525 }
526
527 return zeroExtendToI32(Reg, V, From);
528 }
529
signExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)530 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
531 MVT::SimpleValueType From,
532 MVT::SimpleValueType To) {
533 if (To == MVT::i64) {
534 if (From == MVT::i64)
535 return copyValue(Reg);
536
537 Reg = signExtendToI32(Reg, V, From);
538
539 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
540 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
541 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
542 .addReg(Reg);
543 return Result;
544 }
545
546 return signExtendToI32(Reg, V, From);
547 }
548
getRegForUnsignedValue(const Value * V)549 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
550 MVT::SimpleValueType From = getSimpleType(V->getType());
551 MVT::SimpleValueType To = getLegalType(From);
552 unsigned VReg = getRegForValue(V);
553 if (VReg == 0)
554 return 0;
555 return zeroExtend(VReg, V, From, To);
556 }
557
getRegForSignedValue(const Value * V)558 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
559 MVT::SimpleValueType From = getSimpleType(V->getType());
560 MVT::SimpleValueType To = getLegalType(From);
561 unsigned VReg = getRegForValue(V);
562 if (VReg == 0)
563 return 0;
564 return signExtend(VReg, V, From, To);
565 }
566
getRegForPromotedValue(const Value * V,bool IsSigned)567 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
568 bool IsSigned) {
569 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
570 }
571
notValue(unsigned Reg)572 unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
573 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
574
575 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
576 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
577 TII.get(WebAssembly::EQZ_I32), NotReg)
578 .addReg(Reg);
579 return NotReg;
580 }
581
copyValue(unsigned Reg)582 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
583 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
584 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY),
585 ResultReg)
586 .addReg(Reg);
587 return ResultReg;
588 }
589
fastMaterializeAlloca(const AllocaInst * AI)590 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
591 DenseMap<const AllocaInst *, int>::iterator SI =
592 FuncInfo.StaticAllocaMap.find(AI);
593
594 if (SI != FuncInfo.StaticAllocaMap.end()) {
595 unsigned ResultReg =
596 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
597 : &WebAssembly::I32RegClass);
598 unsigned Opc =
599 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
600 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
601 .addFrameIndex(SI->second);
602 return ResultReg;
603 }
604
605 return 0;
606 }
607
fastMaterializeConstant(const Constant * C)608 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
609 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
610 unsigned ResultReg =
611 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
612 : &WebAssembly::I32RegClass);
613 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
614 : WebAssembly::CONST_I32;
615 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
616 .addGlobalAddress(GV);
617 return ResultReg;
618 }
619
620 // Let target-independent code handle it.
621 return 0;
622 }
623
fastLowerArguments()624 bool WebAssemblyFastISel::fastLowerArguments() {
625 if (!FuncInfo.CanLowerReturn)
626 return false;
627
628 const Function *F = FuncInfo.Fn;
629 if (F->isVarArg())
630 return false;
631
632 unsigned i = 0;
633 for (auto const &Arg : F->args()) {
634 const AttributeList &Attrs = F->getAttributes();
635 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
636 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
637 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
638 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
639 Attrs.hasParamAttribute(i, Attribute::Nest))
640 return false;
641
642 Type *ArgTy = Arg.getType();
643 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
644 return false;
645 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
646 return false;
647
648 unsigned Opc;
649 const TargetRegisterClass *RC;
650 switch (getSimpleType(ArgTy)) {
651 case MVT::i1:
652 case MVT::i8:
653 case MVT::i16:
654 case MVT::i32:
655 Opc = WebAssembly::ARGUMENT_i32;
656 RC = &WebAssembly::I32RegClass;
657 break;
658 case MVT::i64:
659 Opc = WebAssembly::ARGUMENT_i64;
660 RC = &WebAssembly::I64RegClass;
661 break;
662 case MVT::f32:
663 Opc = WebAssembly::ARGUMENT_f32;
664 RC = &WebAssembly::F32RegClass;
665 break;
666 case MVT::f64:
667 Opc = WebAssembly::ARGUMENT_f64;
668 RC = &WebAssembly::F64RegClass;
669 break;
670 case MVT::v16i8:
671 Opc = WebAssembly::ARGUMENT_v16i8;
672 RC = &WebAssembly::V128RegClass;
673 break;
674 case MVT::v8i16:
675 Opc = WebAssembly::ARGUMENT_v8i16;
676 RC = &WebAssembly::V128RegClass;
677 break;
678 case MVT::v4i32:
679 Opc = WebAssembly::ARGUMENT_v4i32;
680 RC = &WebAssembly::V128RegClass;
681 break;
682 case MVT::v2i64:
683 Opc = WebAssembly::ARGUMENT_v2i64;
684 RC = &WebAssembly::V128RegClass;
685 break;
686 case MVT::v4f32:
687 Opc = WebAssembly::ARGUMENT_v4f32;
688 RC = &WebAssembly::V128RegClass;
689 break;
690 case MVT::v2f64:
691 Opc = WebAssembly::ARGUMENT_v2f64;
692 RC = &WebAssembly::V128RegClass;
693 break;
694 case MVT::ExceptRef:
695 Opc = WebAssembly::ARGUMENT_ExceptRef;
696 RC = &WebAssembly::EXCEPT_REFRegClass;
697 break;
698 default:
699 return false;
700 }
701 unsigned ResultReg = createResultReg(RC);
702 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
703 .addImm(i);
704 updateValueMap(&Arg, ResultReg);
705
706 ++i;
707 }
708
709 MRI.addLiveIn(WebAssembly::ARGUMENTS);
710
711 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
712 for (auto const &Arg : F->args()) {
713 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
714 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
715 MFI->clearParamsAndResults();
716 return false;
717 }
718 MFI->addParam(ArgTy);
719 }
720
721 if (!F->getReturnType()->isVoidTy()) {
722 MVT::SimpleValueType RetTy =
723 getLegalType(getSimpleType(F->getReturnType()));
724 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
725 MFI->clearParamsAndResults();
726 return false;
727 }
728 MFI->addResult(RetTy);
729 }
730
731 return true;
732 }
733
selectCall(const Instruction * I)734 bool WebAssemblyFastISel::selectCall(const Instruction *I) {
735 const CallInst *Call = cast<CallInst>(I);
736
737 if (Call->isMustTailCall() || Call->isInlineAsm() ||
738 Call->getFunctionType()->isVarArg())
739 return false;
740
741 Function *Func = Call->getCalledFunction();
742 if (Func && Func->isIntrinsic())
743 return false;
744
745 bool IsDirect = Func != nullptr;
746 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
747 return false;
748
749 FunctionType *FuncTy = Call->getFunctionType();
750 unsigned Opc;
751 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
752 unsigned ResultReg;
753 if (IsVoid) {
754 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
755 } else {
756 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
757 return false;
758
759 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
760 switch (RetTy) {
761 case MVT::i1:
762 case MVT::i8:
763 case MVT::i16:
764 case MVT::i32:
765 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
766 ResultReg = createResultReg(&WebAssembly::I32RegClass);
767 break;
768 case MVT::i64:
769 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
770 ResultReg = createResultReg(&WebAssembly::I64RegClass);
771 break;
772 case MVT::f32:
773 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
774 ResultReg = createResultReg(&WebAssembly::F32RegClass);
775 break;
776 case MVT::f64:
777 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
778 ResultReg = createResultReg(&WebAssembly::F64RegClass);
779 break;
780 case MVT::v16i8:
781 Opc = IsDirect ? WebAssembly::CALL_v16i8
782 : WebAssembly::PCALL_INDIRECT_v16i8;
783 ResultReg = createResultReg(&WebAssembly::V128RegClass);
784 break;
785 case MVT::v8i16:
786 Opc = IsDirect ? WebAssembly::CALL_v8i16
787 : WebAssembly::PCALL_INDIRECT_v8i16;
788 ResultReg = createResultReg(&WebAssembly::V128RegClass);
789 break;
790 case MVT::v4i32:
791 Opc = IsDirect ? WebAssembly::CALL_v4i32
792 : WebAssembly::PCALL_INDIRECT_v4i32;
793 ResultReg = createResultReg(&WebAssembly::V128RegClass);
794 break;
795 case MVT::v2i64:
796 Opc = IsDirect ? WebAssembly::CALL_v2i64
797 : WebAssembly::PCALL_INDIRECT_v2i64;
798 ResultReg = createResultReg(&WebAssembly::V128RegClass);
799 break;
800 case MVT::v4f32:
801 Opc = IsDirect ? WebAssembly::CALL_v4f32
802 : WebAssembly::PCALL_INDIRECT_v4f32;
803 ResultReg = createResultReg(&WebAssembly::V128RegClass);
804 break;
805 case MVT::v2f64:
806 Opc = IsDirect ? WebAssembly::CALL_v2f64
807 : WebAssembly::PCALL_INDIRECT_v2f64;
808 ResultReg = createResultReg(&WebAssembly::V128RegClass);
809 break;
810 case MVT::ExceptRef:
811 Opc = IsDirect ? WebAssembly::CALL_EXCEPT_REF
812 : WebAssembly::PCALL_INDIRECT_EXCEPT_REF;
813 ResultReg = createResultReg(&WebAssembly::EXCEPT_REFRegClass);
814 break;
815 default:
816 return false;
817 }
818 }
819
820 SmallVector<unsigned, 8> Args;
821 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
822 Value *V = Call->getArgOperand(i);
823 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
824 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
825 return false;
826
827 const AttributeList &Attrs = Call->getAttributes();
828 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
829 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
830 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
831 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
832 Attrs.hasParamAttribute(i, Attribute::Nest))
833 return false;
834
835 unsigned Reg;
836
837 if (Attrs.hasParamAttribute(i, Attribute::SExt))
838 Reg = getRegForSignedValue(V);
839 else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
840 Reg = getRegForUnsignedValue(V);
841 else
842 Reg = getRegForValue(V);
843
844 if (Reg == 0)
845 return false;
846
847 Args.push_back(Reg);
848 }
849
850 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
851
852 if (!IsVoid)
853 MIB.addReg(ResultReg, RegState::Define);
854
855 if (IsDirect)
856 MIB.addGlobalAddress(Func);
857 else {
858 unsigned Reg = getRegForValue(Call->getCalledValue());
859 if (Reg == 0)
860 return false;
861 MIB.addReg(Reg);
862 }
863
864 for (unsigned ArgReg : Args)
865 MIB.addReg(ArgReg);
866
867 if (!IsVoid)
868 updateValueMap(Call, ResultReg);
869 return true;
870 }
871
selectSelect(const Instruction * I)872 bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
873 const SelectInst *Select = cast<SelectInst>(I);
874
875 bool Not;
876 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
877 if (CondReg == 0)
878 return false;
879
880 unsigned TrueReg = getRegForValue(Select->getTrueValue());
881 if (TrueReg == 0)
882 return false;
883
884 unsigned FalseReg = getRegForValue(Select->getFalseValue());
885 if (FalseReg == 0)
886 return false;
887
888 if (Not)
889 std::swap(TrueReg, FalseReg);
890
891 unsigned Opc;
892 const TargetRegisterClass *RC;
893 switch (getSimpleType(Select->getType())) {
894 case MVT::i1:
895 case MVT::i8:
896 case MVT::i16:
897 case MVT::i32:
898 Opc = WebAssembly::SELECT_I32;
899 RC = &WebAssembly::I32RegClass;
900 break;
901 case MVT::i64:
902 Opc = WebAssembly::SELECT_I64;
903 RC = &WebAssembly::I64RegClass;
904 break;
905 case MVT::f32:
906 Opc = WebAssembly::SELECT_F32;
907 RC = &WebAssembly::F32RegClass;
908 break;
909 case MVT::f64:
910 Opc = WebAssembly::SELECT_F64;
911 RC = &WebAssembly::F64RegClass;
912 break;
913 case MVT::ExceptRef:
914 Opc = WebAssembly::SELECT_EXCEPT_REF;
915 RC = &WebAssembly::EXCEPT_REFRegClass;
916 break;
917 default:
918 return false;
919 }
920
921 unsigned ResultReg = createResultReg(RC);
922 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
923 .addReg(TrueReg)
924 .addReg(FalseReg)
925 .addReg(CondReg);
926
927 updateValueMap(Select, ResultReg);
928 return true;
929 }
930
selectTrunc(const Instruction * I)931 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
932 const TruncInst *Trunc = cast<TruncInst>(I);
933
934 unsigned Reg = getRegForValue(Trunc->getOperand(0));
935 if (Reg == 0)
936 return false;
937
938 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
939 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
940 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
941 TII.get(WebAssembly::I32_WRAP_I64), Result)
942 .addReg(Reg);
943 Reg = Result;
944 }
945
946 updateValueMap(Trunc, Reg);
947 return true;
948 }
949
selectZExt(const Instruction * I)950 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
951 const ZExtInst *ZExt = cast<ZExtInst>(I);
952
953 const Value *Op = ZExt->getOperand(0);
954 MVT::SimpleValueType From = getSimpleType(Op->getType());
955 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
956 unsigned In = getRegForValue(Op);
957 if (In == 0)
958 return false;
959 unsigned Reg = zeroExtend(In, Op, From, To);
960 if (Reg == 0)
961 return false;
962
963 updateValueMap(ZExt, Reg);
964 return true;
965 }
966
selectSExt(const Instruction * I)967 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
968 const SExtInst *SExt = cast<SExtInst>(I);
969
970 const Value *Op = SExt->getOperand(0);
971 MVT::SimpleValueType From = getSimpleType(Op->getType());
972 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
973 unsigned In = getRegForValue(Op);
974 if (In == 0)
975 return false;
976 unsigned Reg = signExtend(In, Op, From, To);
977 if (Reg == 0)
978 return false;
979
980 updateValueMap(SExt, Reg);
981 return true;
982 }
983
selectICmp(const Instruction * I)984 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
985 const ICmpInst *ICmp = cast<ICmpInst>(I);
986
987 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
988 unsigned Opc;
989 bool isSigned = false;
990 switch (ICmp->getPredicate()) {
991 case ICmpInst::ICMP_EQ:
992 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
993 break;
994 case ICmpInst::ICMP_NE:
995 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
996 break;
997 case ICmpInst::ICMP_UGT:
998 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
999 break;
1000 case ICmpInst::ICMP_UGE:
1001 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1002 break;
1003 case ICmpInst::ICMP_ULT:
1004 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1005 break;
1006 case ICmpInst::ICMP_ULE:
1007 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1008 break;
1009 case ICmpInst::ICMP_SGT:
1010 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1011 isSigned = true;
1012 break;
1013 case ICmpInst::ICMP_SGE:
1014 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1015 isSigned = true;
1016 break;
1017 case ICmpInst::ICMP_SLT:
1018 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1019 isSigned = true;
1020 break;
1021 case ICmpInst::ICMP_SLE:
1022 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1023 isSigned = true;
1024 break;
1025 default:
1026 return false;
1027 }
1028
1029 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
1030 if (LHS == 0)
1031 return false;
1032
1033 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
1034 if (RHS == 0)
1035 return false;
1036
1037 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1038 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1039 .addReg(LHS)
1040 .addReg(RHS);
1041 updateValueMap(ICmp, ResultReg);
1042 return true;
1043 }
1044
selectFCmp(const Instruction * I)1045 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1046 const FCmpInst *FCmp = cast<FCmpInst>(I);
1047
1048 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1049 if (LHS == 0)
1050 return false;
1051
1052 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1053 if (RHS == 0)
1054 return false;
1055
1056 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1057 unsigned Opc;
1058 bool Not = false;
1059 switch (FCmp->getPredicate()) {
1060 case FCmpInst::FCMP_OEQ:
1061 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1062 break;
1063 case FCmpInst::FCMP_UNE:
1064 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1065 break;
1066 case FCmpInst::FCMP_OGT:
1067 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1068 break;
1069 case FCmpInst::FCMP_OGE:
1070 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1071 break;
1072 case FCmpInst::FCMP_OLT:
1073 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1074 break;
1075 case FCmpInst::FCMP_OLE:
1076 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1077 break;
1078 case FCmpInst::FCMP_UGT:
1079 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1080 Not = true;
1081 break;
1082 case FCmpInst::FCMP_UGE:
1083 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1084 Not = true;
1085 break;
1086 case FCmpInst::FCMP_ULT:
1087 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1088 Not = true;
1089 break;
1090 case FCmpInst::FCMP_ULE:
1091 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1092 Not = true;
1093 break;
1094 default:
1095 return false;
1096 }
1097
1098 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1099 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1100 .addReg(LHS)
1101 .addReg(RHS);
1102
1103 if (Not)
1104 ResultReg = notValue(ResultReg);
1105
1106 updateValueMap(FCmp, ResultReg);
1107 return true;
1108 }
1109
selectBitCast(const Instruction * I)1110 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1111 // Target-independent code can handle this, except it doesn't set the dead
1112 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1113 // to satisfy code that expects this of isBitcast() instructions.
1114 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1115 EVT RetVT = TLI.getValueType(DL, I->getType());
1116 if (!VT.isSimple() || !RetVT.isSimple())
1117 return false;
1118
1119 unsigned In = getRegForValue(I->getOperand(0));
1120 if (In == 0)
1121 return false;
1122
1123 if (VT == RetVT) {
1124 // No-op bitcast.
1125 updateValueMap(I, In);
1126 return true;
1127 }
1128
1129 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1130 In, I->getOperand(0)->hasOneUse());
1131 if (!Reg)
1132 return false;
1133 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1134 --Iter;
1135 assert(Iter->isBitcast());
1136 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1137 updateValueMap(I, Reg);
1138 return true;
1139 }
1140
selectLoad(const Instruction * I)1141 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1142 const LoadInst *Load = cast<LoadInst>(I);
1143 if (Load->isAtomic())
1144 return false;
1145 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1146 return false;
1147
1148 Address Addr;
1149 if (!computeAddress(Load->getPointerOperand(), Addr))
1150 return false;
1151
1152 // TODO: Fold a following sign-/zero-extend into the load instruction.
1153
1154 unsigned Opc;
1155 const TargetRegisterClass *RC;
1156 switch (getSimpleType(Load->getType())) {
1157 case MVT::i1:
1158 case MVT::i8:
1159 Opc = WebAssembly::LOAD8_U_I32;
1160 RC = &WebAssembly::I32RegClass;
1161 break;
1162 case MVT::i16:
1163 Opc = WebAssembly::LOAD16_U_I32;
1164 RC = &WebAssembly::I32RegClass;
1165 break;
1166 case MVT::i32:
1167 Opc = WebAssembly::LOAD_I32;
1168 RC = &WebAssembly::I32RegClass;
1169 break;
1170 case MVT::i64:
1171 Opc = WebAssembly::LOAD_I64;
1172 RC = &WebAssembly::I64RegClass;
1173 break;
1174 case MVT::f32:
1175 Opc = WebAssembly::LOAD_F32;
1176 RC = &WebAssembly::F32RegClass;
1177 break;
1178 case MVT::f64:
1179 Opc = WebAssembly::LOAD_F64;
1180 RC = &WebAssembly::F64RegClass;
1181 break;
1182 default:
1183 return false;
1184 }
1185
1186 materializeLoadStoreOperands(Addr);
1187
1188 unsigned ResultReg = createResultReg(RC);
1189 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1190 ResultReg);
1191
1192 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1193
1194 updateValueMap(Load, ResultReg);
1195 return true;
1196 }
1197
selectStore(const Instruction * I)1198 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1199 const StoreInst *Store = cast<StoreInst>(I);
1200 if (Store->isAtomic())
1201 return false;
1202 if (!Subtarget->hasSIMD128() &&
1203 Store->getValueOperand()->getType()->isVectorTy())
1204 return false;
1205
1206 Address Addr;
1207 if (!computeAddress(Store->getPointerOperand(), Addr))
1208 return false;
1209
1210 unsigned Opc;
1211 bool VTIsi1 = false;
1212 switch (getSimpleType(Store->getValueOperand()->getType())) {
1213 case MVT::i1:
1214 VTIsi1 = true;
1215 LLVM_FALLTHROUGH;
1216 case MVT::i8:
1217 Opc = WebAssembly::STORE8_I32;
1218 break;
1219 case MVT::i16:
1220 Opc = WebAssembly::STORE16_I32;
1221 break;
1222 case MVT::i32:
1223 Opc = WebAssembly::STORE_I32;
1224 break;
1225 case MVT::i64:
1226 Opc = WebAssembly::STORE_I64;
1227 break;
1228 case MVT::f32:
1229 Opc = WebAssembly::STORE_F32;
1230 break;
1231 case MVT::f64:
1232 Opc = WebAssembly::STORE_F64;
1233 break;
1234 default:
1235 return false;
1236 }
1237
1238 materializeLoadStoreOperands(Addr);
1239
1240 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1241 if (ValueReg == 0)
1242 return false;
1243 if (VTIsi1)
1244 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1245
1246 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1247
1248 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1249
1250 MIB.addReg(ValueReg);
1251 return true;
1252 }
1253
selectBr(const Instruction * I)1254 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1255 const BranchInst *Br = cast<BranchInst>(I);
1256 if (Br->isUnconditional()) {
1257 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1258 fastEmitBranch(MSucc, Br->getDebugLoc());
1259 return true;
1260 }
1261
1262 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1263 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1264
1265 bool Not;
1266 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1267 if (CondReg == 0)
1268 return false;
1269
1270 unsigned Opc = WebAssembly::BR_IF;
1271 if (Not)
1272 Opc = WebAssembly::BR_UNLESS;
1273
1274 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1275 .addMBB(TBB)
1276 .addReg(CondReg);
1277
1278 finishCondBranch(Br->getParent(), TBB, FBB);
1279 return true;
1280 }
1281
selectRet(const Instruction * I)1282 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1283 if (!FuncInfo.CanLowerReturn)
1284 return false;
1285
1286 const ReturnInst *Ret = cast<ReturnInst>(I);
1287
1288 if (Ret->getNumOperands() == 0) {
1289 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1290 TII.get(WebAssembly::RETURN_VOID));
1291 return true;
1292 }
1293
1294 Value *RV = Ret->getOperand(0);
1295 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1296 return false;
1297
1298 unsigned Opc;
1299 switch (getSimpleType(RV->getType())) {
1300 case MVT::i1:
1301 case MVT::i8:
1302 case MVT::i16:
1303 case MVT::i32:
1304 Opc = WebAssembly::RETURN_I32;
1305 break;
1306 case MVT::i64:
1307 Opc = WebAssembly::RETURN_I64;
1308 break;
1309 case MVT::f32:
1310 Opc = WebAssembly::RETURN_F32;
1311 break;
1312 case MVT::f64:
1313 Opc = WebAssembly::RETURN_F64;
1314 break;
1315 case MVT::v16i8:
1316 Opc = WebAssembly::RETURN_v16i8;
1317 break;
1318 case MVT::v8i16:
1319 Opc = WebAssembly::RETURN_v8i16;
1320 break;
1321 case MVT::v4i32:
1322 Opc = WebAssembly::RETURN_v4i32;
1323 break;
1324 case MVT::v2i64:
1325 Opc = WebAssembly::RETURN_v2i64;
1326 break;
1327 case MVT::v4f32:
1328 Opc = WebAssembly::RETURN_v4f32;
1329 break;
1330 case MVT::v2f64:
1331 Opc = WebAssembly::RETURN_v2f64;
1332 break;
1333 case MVT::ExceptRef:
1334 Opc = WebAssembly::RETURN_EXCEPT_REF;
1335 break;
1336 default:
1337 return false;
1338 }
1339
1340 unsigned Reg;
1341 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1342 Reg = getRegForSignedValue(RV);
1343 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1344 Reg = getRegForUnsignedValue(RV);
1345 else
1346 Reg = getRegForValue(RV);
1347
1348 if (Reg == 0)
1349 return false;
1350
1351 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1352 return true;
1353 }
1354
selectUnreachable(const Instruction * I)1355 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1356 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1357 TII.get(WebAssembly::UNREACHABLE));
1358 return true;
1359 }
1360
fastSelectInstruction(const Instruction * I)1361 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1362 switch (I->getOpcode()) {
1363 case Instruction::Call:
1364 if (selectCall(I))
1365 return true;
1366 break;
1367 case Instruction::Select:
1368 return selectSelect(I);
1369 case Instruction::Trunc:
1370 return selectTrunc(I);
1371 case Instruction::ZExt:
1372 return selectZExt(I);
1373 case Instruction::SExt:
1374 return selectSExt(I);
1375 case Instruction::ICmp:
1376 return selectICmp(I);
1377 case Instruction::FCmp:
1378 return selectFCmp(I);
1379 case Instruction::BitCast:
1380 return selectBitCast(I);
1381 case Instruction::Load:
1382 return selectLoad(I);
1383 case Instruction::Store:
1384 return selectStore(I);
1385 case Instruction::Br:
1386 return selectBr(I);
1387 case Instruction::Ret:
1388 return selectRet(I);
1389 case Instruction::Unreachable:
1390 return selectUnreachable(I);
1391 default:
1392 break;
1393 }
1394
1395 // Fall back to target-independent instruction selection.
1396 return selectOperator(I, I->getOpcode());
1397 }
1398
createFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)1399 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1400 const TargetLibraryInfo *LibInfo) {
1401 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1402 }
1403