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