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