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