10b57cec5SDimitry Andric //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file defines the WebAssembly-specific support for the FastISel 110b57cec5SDimitry Andric /// class. Some of the target-specific code is generated by tablegen in the file 120b57cec5SDimitry Andric /// WebAssemblyGenFastISel.inc, which is #included here. 130b57cec5SDimitry Andric /// 140b57cec5SDimitry Andric /// TODO: kill flags 150b57cec5SDimitry Andric /// 160b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 191fd87a68SDimitry Andric #include "Utils/WebAssemblyTypeUtilities.h" 200b57cec5SDimitry Andric #include "WebAssembly.h" 210b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 220b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 230b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h" 245f757f3fSDimitry Andric #include "WebAssemblyUtilities.h" 250b57cec5SDimitry Andric #include "llvm/Analysis/BranchProbabilityInfo.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/FastISel.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/FunctionLoweringInfo.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 31e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 330b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 340b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 350b57cec5SDimitry Andric #include "llvm/IR/Function.h" 360b57cec5SDimitry Andric #include "llvm/IR/GetElementPtrTypeIterator.h" 370b57cec5SDimitry Andric #include "llvm/IR/GlobalAlias.h" 380b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 390b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 400b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 410b57cec5SDimitry Andric #include "llvm/IR/Operator.h" 420b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h" 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric using namespace llvm; 450b57cec5SDimitry Andric using namespace PatternMatch; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-fastisel" 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric namespace { 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric class WebAssemblyFastISel final : public FastISel { 520b57cec5SDimitry Andric // All possible address modes. 530b57cec5SDimitry Andric class Address { 540b57cec5SDimitry Andric public: 550b57cec5SDimitry Andric using BaseKind = enum { RegBase, FrameIndexBase }; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric private: 580b57cec5SDimitry Andric BaseKind Kind = RegBase; 590b57cec5SDimitry Andric union { 600b57cec5SDimitry Andric unsigned Reg; 610b57cec5SDimitry Andric int FI; 620b57cec5SDimitry Andric } Base; 630b57cec5SDimitry Andric 64eaeb601bSDimitry Andric // Whether the base has been determined yet 65eaeb601bSDimitry Andric bool IsBaseSet = false; 66eaeb601bSDimitry Andric 670b57cec5SDimitry Andric int64_t Offset = 0; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric const GlobalValue *GV = nullptr; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric public: 720b57cec5SDimitry Andric // Innocuous defaults for our address. 730b57cec5SDimitry Andric Address() { Base.Reg = 0; } 740b57cec5SDimitry Andric void setKind(BaseKind K) { 750b57cec5SDimitry Andric assert(!isSet() && "Can't change kind with non-zero base"); 760b57cec5SDimitry Andric Kind = K; 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric BaseKind getKind() const { return Kind; } 790b57cec5SDimitry Andric bool isRegBase() const { return Kind == RegBase; } 800b57cec5SDimitry Andric bool isFIBase() const { return Kind == FrameIndexBase; } 810b57cec5SDimitry Andric void setReg(unsigned Reg) { 820b57cec5SDimitry Andric assert(isRegBase() && "Invalid base register access!"); 83eaeb601bSDimitry Andric assert(!IsBaseSet && "Base cannot be reset"); 840b57cec5SDimitry Andric Base.Reg = Reg; 85eaeb601bSDimitry Andric IsBaseSet = true; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric unsigned getReg() const { 880b57cec5SDimitry Andric assert(isRegBase() && "Invalid base register access!"); 890b57cec5SDimitry Andric return Base.Reg; 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric void setFI(unsigned FI) { 920b57cec5SDimitry Andric assert(isFIBase() && "Invalid base frame index access!"); 93eaeb601bSDimitry Andric assert(!IsBaseSet && "Base cannot be reset"); 940b57cec5SDimitry Andric Base.FI = FI; 95eaeb601bSDimitry Andric IsBaseSet = true; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric unsigned getFI() const { 980b57cec5SDimitry Andric assert(isFIBase() && "Invalid base frame index access!"); 990b57cec5SDimitry Andric return Base.FI; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric void setOffset(int64_t NewOffset) { 1030b57cec5SDimitry Andric assert(NewOffset >= 0 && "Offsets must be non-negative"); 1040b57cec5SDimitry Andric Offset = NewOffset; 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric int64_t getOffset() const { return Offset; } 1070b57cec5SDimitry Andric void setGlobalValue(const GlobalValue *G) { GV = G; } 1080b57cec5SDimitry Andric const GlobalValue *getGlobalValue() const { return GV; } 109eaeb601bSDimitry Andric bool isSet() const { return IsBaseSet; } 1100b57cec5SDimitry Andric }; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric /// Keep a pointer to the WebAssemblySubtarget around so that we can make the 1130b57cec5SDimitry Andric /// right decision when generating code for different targets. 1140b57cec5SDimitry Andric const WebAssemblySubtarget *Subtarget; 1150b57cec5SDimitry Andric LLVMContext *Context; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric private: 1180b57cec5SDimitry Andric // Utility helper routines 1190b57cec5SDimitry Andric MVT::SimpleValueType getSimpleType(Type *Ty) { 1200b57cec5SDimitry Andric EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true); 1210b57cec5SDimitry Andric return VT.isSimple() ? VT.getSimpleVT().SimpleTy 1220b57cec5SDimitry Andric : MVT::INVALID_SIMPLE_VALUE_TYPE; 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) { 1250b57cec5SDimitry Andric switch (VT) { 1260b57cec5SDimitry Andric case MVT::i1: 1270b57cec5SDimitry Andric case MVT::i8: 1280b57cec5SDimitry Andric case MVT::i16: 1290b57cec5SDimitry Andric return MVT::i32; 1300b57cec5SDimitry Andric case MVT::i32: 1310b57cec5SDimitry Andric case MVT::i64: 1320b57cec5SDimitry Andric case MVT::f32: 1330b57cec5SDimitry Andric case MVT::f64: 134fe6060f1SDimitry Andric return VT; 135e8d8bef9SDimitry Andric case MVT::funcref: 136e8d8bef9SDimitry Andric case MVT::externref: 137fe6060f1SDimitry Andric if (Subtarget->hasReferenceTypes()) 1380b57cec5SDimitry Andric return VT; 139fe6060f1SDimitry Andric break; 140*0fca6ea1SDimitry Andric case MVT::exnref: 141*0fca6ea1SDimitry Andric if (Subtarget->hasReferenceTypes() && Subtarget->hasExceptionHandling()) 142*0fca6ea1SDimitry Andric return VT; 143*0fca6ea1SDimitry Andric break; 1440b57cec5SDimitry Andric case MVT::f16: 1450b57cec5SDimitry Andric return MVT::f32; 1460b57cec5SDimitry Andric case MVT::v16i8: 1470b57cec5SDimitry Andric case MVT::v8i16: 1480b57cec5SDimitry Andric case MVT::v4i32: 1490b57cec5SDimitry Andric case MVT::v4f32: 1500b57cec5SDimitry Andric case MVT::v2i64: 1510b57cec5SDimitry Andric case MVT::v2f64: 152fe6060f1SDimitry Andric if (Subtarget->hasSIMD128()) 1530b57cec5SDimitry Andric return VT; 1540b57cec5SDimitry Andric break; 1550b57cec5SDimitry Andric default: 1560b57cec5SDimitry Andric break; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric return MVT::INVALID_SIMPLE_VALUE_TYPE; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric bool computeAddress(const Value *Obj, Address &Addr); 1610b57cec5SDimitry Andric void materializeLoadStoreOperands(Address &Addr); 1620b57cec5SDimitry Andric void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB, 1630b57cec5SDimitry Andric MachineMemOperand *MMO); 1640b57cec5SDimitry Andric unsigned maskI1Value(unsigned Reg, const Value *V); 16569ade1e0SDimitry Andric unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not); 1660b57cec5SDimitry Andric unsigned zeroExtendToI32(unsigned Reg, const Value *V, 1670b57cec5SDimitry Andric MVT::SimpleValueType From); 1680b57cec5SDimitry Andric unsigned signExtendToI32(unsigned Reg, const Value *V, 1690b57cec5SDimitry Andric MVT::SimpleValueType From); 1700b57cec5SDimitry Andric unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From, 1710b57cec5SDimitry Andric MVT::SimpleValueType To); 1720b57cec5SDimitry Andric unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From, 1730b57cec5SDimitry Andric MVT::SimpleValueType To); 1740b57cec5SDimitry Andric unsigned getRegForUnsignedValue(const Value *V); 1750b57cec5SDimitry Andric unsigned getRegForSignedValue(const Value *V); 1760b57cec5SDimitry Andric unsigned getRegForPromotedValue(const Value *V, bool IsSigned); 1770b57cec5SDimitry Andric unsigned notValue(unsigned Reg); 1780b57cec5SDimitry Andric unsigned copyValue(unsigned Reg); 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric // Backend specific FastISel code. 1810b57cec5SDimitry Andric unsigned fastMaterializeAlloca(const AllocaInst *AI) override; 1820b57cec5SDimitry Andric unsigned fastMaterializeConstant(const Constant *C) override; 1830b57cec5SDimitry Andric bool fastLowerArguments() override; 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric // Selection routines. 1860b57cec5SDimitry Andric bool selectCall(const Instruction *I); 1870b57cec5SDimitry Andric bool selectSelect(const Instruction *I); 1880b57cec5SDimitry Andric bool selectTrunc(const Instruction *I); 1890b57cec5SDimitry Andric bool selectZExt(const Instruction *I); 1900b57cec5SDimitry Andric bool selectSExt(const Instruction *I); 1910b57cec5SDimitry Andric bool selectICmp(const Instruction *I); 1920b57cec5SDimitry Andric bool selectFCmp(const Instruction *I); 1930b57cec5SDimitry Andric bool selectBitCast(const Instruction *I); 1940b57cec5SDimitry Andric bool selectLoad(const Instruction *I); 1950b57cec5SDimitry Andric bool selectStore(const Instruction *I); 1960b57cec5SDimitry Andric bool selectBr(const Instruction *I); 1970b57cec5SDimitry Andric bool selectRet(const Instruction *I); 1980b57cec5SDimitry Andric bool selectUnreachable(const Instruction *I); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric public: 2010b57cec5SDimitry Andric // Backend specific FastISel code. 2020b57cec5SDimitry Andric WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo, 2030b57cec5SDimitry Andric const TargetLibraryInfo *LibInfo) 2040b57cec5SDimitry Andric : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) { 2050b57cec5SDimitry Andric Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>(); 2060b57cec5SDimitry Andric Context = &FuncInfo.Fn->getContext(); 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric bool fastSelectInstruction(const Instruction *I) override; 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric #include "WebAssemblyGenFastISel.inc" 2120b57cec5SDimitry Andric }; 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric } // end anonymous namespace 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) { 2170b57cec5SDimitry Andric const User *U = nullptr; 2180b57cec5SDimitry Andric unsigned Opcode = Instruction::UserOp1; 2190b57cec5SDimitry Andric if (const auto *I = dyn_cast<Instruction>(Obj)) { 2200b57cec5SDimitry Andric // Don't walk into other basic blocks unless the object is an alloca from 2210b57cec5SDimitry Andric // another block, otherwise it may not have a virtual register assigned. 2220b57cec5SDimitry Andric if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) || 2230b57cec5SDimitry Andric FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { 2240b57cec5SDimitry Andric Opcode = I->getOpcode(); 2250b57cec5SDimitry Andric U = I; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) { 2280b57cec5SDimitry Andric Opcode = C->getOpcode(); 2290b57cec5SDimitry Andric U = C; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric if (auto *Ty = dyn_cast<PointerType>(Obj->getType())) 2330b57cec5SDimitry Andric if (Ty->getAddressSpace() > 255) 2340b57cec5SDimitry Andric // Fast instruction selection doesn't support the special 2350b57cec5SDimitry Andric // address spaces. 2360b57cec5SDimitry Andric return false; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric if (const auto *GV = dyn_cast<GlobalValue>(Obj)) { 2390b57cec5SDimitry Andric if (TLI.isPositionIndependent()) 2400b57cec5SDimitry Andric return false; 2410b57cec5SDimitry Andric if (Addr.getGlobalValue()) 2420b57cec5SDimitry Andric return false; 2430b57cec5SDimitry Andric if (GV->isThreadLocal()) 2440b57cec5SDimitry Andric return false; 2450b57cec5SDimitry Andric Addr.setGlobalValue(GV); 2460b57cec5SDimitry Andric return true; 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric switch (Opcode) { 2500b57cec5SDimitry Andric default: 2510b57cec5SDimitry Andric break; 2520b57cec5SDimitry Andric case Instruction::BitCast: { 2530b57cec5SDimitry Andric // Look through bitcasts. 2540b57cec5SDimitry Andric return computeAddress(U->getOperand(0), Addr); 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric case Instruction::IntToPtr: { 2570b57cec5SDimitry Andric // Look past no-op inttoptrs. 2580b57cec5SDimitry Andric if (TLI.getValueType(DL, U->getOperand(0)->getType()) == 2590b57cec5SDimitry Andric TLI.getPointerTy(DL)) 2600b57cec5SDimitry Andric return computeAddress(U->getOperand(0), Addr); 2610b57cec5SDimitry Andric break; 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric case Instruction::PtrToInt: { 2640b57cec5SDimitry Andric // Look past no-op ptrtoints. 2650b57cec5SDimitry Andric if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL)) 2660b57cec5SDimitry Andric return computeAddress(U->getOperand(0), Addr); 2670b57cec5SDimitry Andric break; 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric case Instruction::GetElementPtr: { 2700b57cec5SDimitry Andric Address SavedAddr = Addr; 2710b57cec5SDimitry Andric uint64_t TmpOffset = Addr.getOffset(); 2720b57cec5SDimitry Andric // Non-inbounds geps can wrap; wasm's offsets can't. 2730b57cec5SDimitry Andric if (!cast<GEPOperator>(U)->isInBounds()) 2740b57cec5SDimitry Andric goto unsupported_gep; 2750b57cec5SDimitry Andric // Iterate through the GEP folding the constants into offsets where 2760b57cec5SDimitry Andric // we can. 2770b57cec5SDimitry Andric for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U); 2780b57cec5SDimitry Andric GTI != E; ++GTI) { 2790b57cec5SDimitry Andric const Value *Op = GTI.getOperand(); 2800b57cec5SDimitry Andric if (StructType *STy = GTI.getStructTypeOrNull()) { 2810b57cec5SDimitry Andric const StructLayout *SL = DL.getStructLayout(STy); 2820b57cec5SDimitry Andric unsigned Idx = cast<ConstantInt>(Op)->getZExtValue(); 2830b57cec5SDimitry Andric TmpOffset += SL->getElementOffset(Idx); 2840b57cec5SDimitry Andric } else { 2851db9f3b2SDimitry Andric uint64_t S = GTI.getSequentialElementStride(DL); 2860b57cec5SDimitry Andric for (;;) { 2870b57cec5SDimitry Andric if (const auto *CI = dyn_cast<ConstantInt>(Op)) { 2880b57cec5SDimitry Andric // Constant-offset addressing. 2890b57cec5SDimitry Andric TmpOffset += CI->getSExtValue() * S; 2900b57cec5SDimitry Andric break; 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) { 2930b57cec5SDimitry Andric // An unscaled add of a register. Set it as the new base. 29404eeddc0SDimitry Andric Register Reg = getRegForValue(Op); 2950b57cec5SDimitry Andric if (Reg == 0) 2960b57cec5SDimitry Andric return false; 2970b57cec5SDimitry Andric Addr.setReg(Reg); 2980b57cec5SDimitry Andric break; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric if (canFoldAddIntoGEP(U, Op)) { 3010b57cec5SDimitry Andric // A compatible add with a constant operand. Fold the constant. 3020b57cec5SDimitry Andric auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1)); 3030b57cec5SDimitry Andric TmpOffset += CI->getSExtValue() * S; 3040b57cec5SDimitry Andric // Iterate on the other operand. 3050b57cec5SDimitry Andric Op = cast<AddOperator>(Op)->getOperand(0); 3060b57cec5SDimitry Andric continue; 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric // Unsupported 3090b57cec5SDimitry Andric goto unsupported_gep; 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric // Don't fold in negative offsets. 3140b57cec5SDimitry Andric if (int64_t(TmpOffset) >= 0) { 3150b57cec5SDimitry Andric // Try to grab the base operand now. 3160b57cec5SDimitry Andric Addr.setOffset(TmpOffset); 3170b57cec5SDimitry Andric if (computeAddress(U->getOperand(0), Addr)) 3180b57cec5SDimitry Andric return true; 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric // We failed, restore everything and try the other options. 3210b57cec5SDimitry Andric Addr = SavedAddr; 3220b57cec5SDimitry Andric unsupported_gep: 3230b57cec5SDimitry Andric break; 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric case Instruction::Alloca: { 3260b57cec5SDimitry Andric const auto *AI = cast<AllocaInst>(Obj); 3270b57cec5SDimitry Andric DenseMap<const AllocaInst *, int>::iterator SI = 3280b57cec5SDimitry Andric FuncInfo.StaticAllocaMap.find(AI); 3290b57cec5SDimitry Andric if (SI != FuncInfo.StaticAllocaMap.end()) { 3300b57cec5SDimitry Andric if (Addr.isSet()) { 3310b57cec5SDimitry Andric return false; 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric Addr.setKind(Address::FrameIndexBase); 3340b57cec5SDimitry Andric Addr.setFI(SI->second); 3350b57cec5SDimitry Andric return true; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric break; 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric case Instruction::Add: { 3400b57cec5SDimitry Andric // Adds of constants are common and easy enough. 3410b57cec5SDimitry Andric const Value *LHS = U->getOperand(0); 3420b57cec5SDimitry Andric const Value *RHS = U->getOperand(1); 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric if (isa<ConstantInt>(LHS)) 3450b57cec5SDimitry Andric std::swap(LHS, RHS); 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric if (const auto *CI = dyn_cast<ConstantInt>(RHS)) { 3480b57cec5SDimitry Andric uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue(); 3490b57cec5SDimitry Andric if (int64_t(TmpOffset) >= 0) { 3500b57cec5SDimitry Andric Addr.setOffset(TmpOffset); 3510b57cec5SDimitry Andric return computeAddress(LHS, Addr); 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric Address Backup = Addr; 3560b57cec5SDimitry Andric if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr)) 3570b57cec5SDimitry Andric return true; 3580b57cec5SDimitry Andric Addr = Backup; 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric break; 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric case Instruction::Sub: { 3630b57cec5SDimitry Andric // Subs of constants are common and easy enough. 3640b57cec5SDimitry Andric const Value *LHS = U->getOperand(0); 3650b57cec5SDimitry Andric const Value *RHS = U->getOperand(1); 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric if (const auto *CI = dyn_cast<ConstantInt>(RHS)) { 3680b57cec5SDimitry Andric int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue(); 3690b57cec5SDimitry Andric if (TmpOffset >= 0) { 3700b57cec5SDimitry Andric Addr.setOffset(TmpOffset); 3710b57cec5SDimitry Andric return computeAddress(LHS, Addr); 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric break; 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric if (Addr.isSet()) { 3780b57cec5SDimitry Andric return false; 3790b57cec5SDimitry Andric } 38004eeddc0SDimitry Andric Register Reg = getRegForValue(Obj); 3810b57cec5SDimitry Andric if (Reg == 0) 3820b57cec5SDimitry Andric return false; 3830b57cec5SDimitry Andric Addr.setReg(Reg); 3840b57cec5SDimitry Andric return Addr.getReg() != 0; 3850b57cec5SDimitry Andric } 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) { 3880b57cec5SDimitry Andric if (Addr.isRegBase()) { 3890b57cec5SDimitry Andric unsigned Reg = Addr.getReg(); 3900b57cec5SDimitry Andric if (Reg == 0) { 3910b57cec5SDimitry Andric Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass 3920b57cec5SDimitry Andric : &WebAssembly::I32RegClass); 3930b57cec5SDimitry Andric unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 3940b57cec5SDimitry Andric : WebAssembly::CONST_I32; 395bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Reg) 3960b57cec5SDimitry Andric .addImm(0); 3970b57cec5SDimitry Andric Addr.setReg(Reg); 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr, 4030b57cec5SDimitry Andric const MachineInstrBuilder &MIB, 4040b57cec5SDimitry Andric MachineMemOperand *MMO) { 4050b57cec5SDimitry Andric // Set the alignment operand (this is rewritten in SetP2AlignOperands). 4060b57cec5SDimitry Andric // TODO: Disable SetP2AlignOperands for FastISel and just do it here. 4070b57cec5SDimitry Andric MIB.addImm(0); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric if (const GlobalValue *GV = Addr.getGlobalValue()) 4100b57cec5SDimitry Andric MIB.addGlobalAddress(GV, Addr.getOffset()); 4110b57cec5SDimitry Andric else 4120b57cec5SDimitry Andric MIB.addImm(Addr.getOffset()); 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric if (Addr.isRegBase()) 4150b57cec5SDimitry Andric MIB.addReg(Addr.getReg()); 4160b57cec5SDimitry Andric else 4170b57cec5SDimitry Andric MIB.addFrameIndex(Addr.getFI()); 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric MIB.addMemOperand(MMO); 4200b57cec5SDimitry Andric } 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) { 4230b57cec5SDimitry Andric return zeroExtendToI32(Reg, V, MVT::i1); 4240b57cec5SDimitry Andric } 4250b57cec5SDimitry Andric 42669ade1e0SDimitry Andric unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, 42769ade1e0SDimitry Andric const BasicBlock *BB, 42869ade1e0SDimitry Andric bool &Not) { 4290b57cec5SDimitry Andric if (const auto *ICmp = dyn_cast<ICmpInst>(V)) 4300b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1))) 43169ade1e0SDimitry Andric if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) && 43269ade1e0SDimitry Andric ICmp->getParent() == BB) { 4330b57cec5SDimitry Andric Not = ICmp->isTrueWhenEqual(); 4340b57cec5SDimitry Andric return getRegForValue(ICmp->getOperand(0)); 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric Not = false; 43804eeddc0SDimitry Andric Register Reg = getRegForValue(V); 4390b57cec5SDimitry Andric if (Reg == 0) 4400b57cec5SDimitry Andric return 0; 4410b57cec5SDimitry Andric return maskI1Value(Reg, V); 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V, 4450b57cec5SDimitry Andric MVT::SimpleValueType From) { 4460b57cec5SDimitry Andric if (Reg == 0) 4470b57cec5SDimitry Andric return 0; 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric switch (From) { 4500b57cec5SDimitry Andric case MVT::i1: 4510b57cec5SDimitry Andric // If the value is naturally an i1, we don't need to mask it. We only know 4520b57cec5SDimitry Andric // if a value is naturally an i1 if it is definitely lowered by FastISel, 4530b57cec5SDimitry Andric // not a DAG ISel fallback. 4540b57cec5SDimitry Andric if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()) 4550b57cec5SDimitry Andric return copyValue(Reg); 4560b57cec5SDimitry Andric break; 4570b57cec5SDimitry Andric case MVT::i8: 4580b57cec5SDimitry Andric case MVT::i16: 4590b57cec5SDimitry Andric break; 4600b57cec5SDimitry Andric case MVT::i32: 4610b57cec5SDimitry Andric return copyValue(Reg); 4620b57cec5SDimitry Andric default: 4630b57cec5SDimitry Andric return 0; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 46604eeddc0SDimitry Andric Register Imm = createResultReg(&WebAssembly::I32RegClass); 467bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 4680b57cec5SDimitry Andric TII.get(WebAssembly::CONST_I32), Imm) 4690b57cec5SDimitry Andric .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits())); 4700b57cec5SDimitry Andric 47104eeddc0SDimitry Andric Register Result = createResultReg(&WebAssembly::I32RegClass); 472bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 4730b57cec5SDimitry Andric TII.get(WebAssembly::AND_I32), Result) 4740b57cec5SDimitry Andric .addReg(Reg) 4750b57cec5SDimitry Andric .addReg(Imm); 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric return Result; 4780b57cec5SDimitry Andric } 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V, 4810b57cec5SDimitry Andric MVT::SimpleValueType From) { 4820b57cec5SDimitry Andric if (Reg == 0) 4830b57cec5SDimitry Andric return 0; 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric switch (From) { 4860b57cec5SDimitry Andric case MVT::i1: 4870b57cec5SDimitry Andric case MVT::i8: 4880b57cec5SDimitry Andric case MVT::i16: 4890b57cec5SDimitry Andric break; 4900b57cec5SDimitry Andric case MVT::i32: 4910b57cec5SDimitry Andric return copyValue(Reg); 4920b57cec5SDimitry Andric default: 4930b57cec5SDimitry Andric return 0; 4940b57cec5SDimitry Andric } 4950b57cec5SDimitry Andric 49604eeddc0SDimitry Andric Register Imm = createResultReg(&WebAssembly::I32RegClass); 497bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 4980b57cec5SDimitry Andric TII.get(WebAssembly::CONST_I32), Imm) 4990b57cec5SDimitry Andric .addImm(32 - MVT(From).getSizeInBits()); 5000b57cec5SDimitry Andric 50104eeddc0SDimitry Andric Register Left = createResultReg(&WebAssembly::I32RegClass); 502bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 5030b57cec5SDimitry Andric TII.get(WebAssembly::SHL_I32), Left) 5040b57cec5SDimitry Andric .addReg(Reg) 5050b57cec5SDimitry Andric .addReg(Imm); 5060b57cec5SDimitry Andric 50704eeddc0SDimitry Andric Register Right = createResultReg(&WebAssembly::I32RegClass); 508bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 5090b57cec5SDimitry Andric TII.get(WebAssembly::SHR_S_I32), Right) 5100b57cec5SDimitry Andric .addReg(Left) 5110b57cec5SDimitry Andric .addReg(Imm); 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric return Right; 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V, 5170b57cec5SDimitry Andric MVT::SimpleValueType From, 5180b57cec5SDimitry Andric MVT::SimpleValueType To) { 5190b57cec5SDimitry Andric if (To == MVT::i64) { 5200b57cec5SDimitry Andric if (From == MVT::i64) 5210b57cec5SDimitry Andric return copyValue(Reg); 5220b57cec5SDimitry Andric 5230b57cec5SDimitry Andric Reg = zeroExtendToI32(Reg, V, From); 5240b57cec5SDimitry Andric 52504eeddc0SDimitry Andric Register Result = createResultReg(&WebAssembly::I64RegClass); 526bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 5270b57cec5SDimitry Andric TII.get(WebAssembly::I64_EXTEND_U_I32), Result) 5280b57cec5SDimitry Andric .addReg(Reg); 5290b57cec5SDimitry Andric return Result; 5300b57cec5SDimitry Andric } 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric if (To == MVT::i32) 5330b57cec5SDimitry Andric return zeroExtendToI32(Reg, V, From); 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric return 0; 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V, 5390b57cec5SDimitry Andric MVT::SimpleValueType From, 5400b57cec5SDimitry Andric MVT::SimpleValueType To) { 5410b57cec5SDimitry Andric if (To == MVT::i64) { 5420b57cec5SDimitry Andric if (From == MVT::i64) 5430b57cec5SDimitry Andric return copyValue(Reg); 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric Reg = signExtendToI32(Reg, V, From); 5460b57cec5SDimitry Andric 54704eeddc0SDimitry Andric Register Result = createResultReg(&WebAssembly::I64RegClass); 548bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 5490b57cec5SDimitry Andric TII.get(WebAssembly::I64_EXTEND_S_I32), Result) 5500b57cec5SDimitry Andric .addReg(Reg); 5510b57cec5SDimitry Andric return Result; 5520b57cec5SDimitry Andric } 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric if (To == MVT::i32) 5550b57cec5SDimitry Andric return signExtendToI32(Reg, V, From); 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric return 0; 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) { 5610b57cec5SDimitry Andric MVT::SimpleValueType From = getSimpleType(V->getType()); 5620b57cec5SDimitry Andric MVT::SimpleValueType To = getLegalType(From); 56304eeddc0SDimitry Andric Register VReg = getRegForValue(V); 5640b57cec5SDimitry Andric if (VReg == 0) 5650b57cec5SDimitry Andric return 0; 566*0fca6ea1SDimitry Andric if (From == To) 567*0fca6ea1SDimitry Andric return VReg; 5680b57cec5SDimitry Andric return zeroExtend(VReg, V, From, To); 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) { 5720b57cec5SDimitry Andric MVT::SimpleValueType From = getSimpleType(V->getType()); 5730b57cec5SDimitry Andric MVT::SimpleValueType To = getLegalType(From); 57404eeddc0SDimitry Andric Register VReg = getRegForValue(V); 5750b57cec5SDimitry Andric if (VReg == 0) 5760b57cec5SDimitry Andric return 0; 577*0fca6ea1SDimitry Andric if (From == To) 578*0fca6ea1SDimitry Andric return VReg; 5790b57cec5SDimitry Andric return signExtend(VReg, V, From, To); 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V, 5830b57cec5SDimitry Andric bool IsSigned) { 5840b57cec5SDimitry Andric return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V); 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric 5870b57cec5SDimitry Andric unsigned WebAssemblyFastISel::notValue(unsigned Reg) { 5880b57cec5SDimitry Andric assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass); 5890b57cec5SDimitry Andric 59004eeddc0SDimitry Andric Register NotReg = createResultReg(&WebAssembly::I32RegClass); 591bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 5920b57cec5SDimitry Andric TII.get(WebAssembly::EQZ_I32), NotReg) 5930b57cec5SDimitry Andric .addReg(Reg); 5940b57cec5SDimitry Andric return NotReg; 5950b57cec5SDimitry Andric } 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric unsigned WebAssemblyFastISel::copyValue(unsigned Reg) { 59804eeddc0SDimitry Andric Register ResultReg = createResultReg(MRI.getRegClass(Reg)); 599bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY), 6000b57cec5SDimitry Andric ResultReg) 6010b57cec5SDimitry Andric .addReg(Reg); 6020b57cec5SDimitry Andric return ResultReg; 6030b57cec5SDimitry Andric } 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) { 6060b57cec5SDimitry Andric DenseMap<const AllocaInst *, int>::iterator SI = 6070b57cec5SDimitry Andric FuncInfo.StaticAllocaMap.find(AI); 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric if (SI != FuncInfo.StaticAllocaMap.end()) { 61004eeddc0SDimitry Andric Register ResultReg = 6110b57cec5SDimitry Andric createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass 6120b57cec5SDimitry Andric : &WebAssembly::I32RegClass); 6130b57cec5SDimitry Andric unsigned Opc = 6140b57cec5SDimitry Andric Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32; 615bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) 6160b57cec5SDimitry Andric .addFrameIndex(SI->second); 6170b57cec5SDimitry Andric return ResultReg; 6180b57cec5SDimitry Andric } 6190b57cec5SDimitry Andric 6200b57cec5SDimitry Andric return 0; 6210b57cec5SDimitry Andric } 6220b57cec5SDimitry Andric 6230b57cec5SDimitry Andric unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) { 6240b57cec5SDimitry Andric if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) { 6250b57cec5SDimitry Andric if (TLI.isPositionIndependent()) 6260b57cec5SDimitry Andric return 0; 6270b57cec5SDimitry Andric if (GV->isThreadLocal()) 6280b57cec5SDimitry Andric return 0; 62904eeddc0SDimitry Andric Register ResultReg = 6300b57cec5SDimitry Andric createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass 6310b57cec5SDimitry Andric : &WebAssembly::I32RegClass); 6320b57cec5SDimitry Andric unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 6330b57cec5SDimitry Andric : WebAssembly::CONST_I32; 634bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) 6350b57cec5SDimitry Andric .addGlobalAddress(GV); 6360b57cec5SDimitry Andric return ResultReg; 6370b57cec5SDimitry Andric } 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric // Let target-independent code handle it. 6400b57cec5SDimitry Andric return 0; 6410b57cec5SDimitry Andric } 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric bool WebAssemblyFastISel::fastLowerArguments() { 6440b57cec5SDimitry Andric if (!FuncInfo.CanLowerReturn) 6450b57cec5SDimitry Andric return false; 6460b57cec5SDimitry Andric 6470b57cec5SDimitry Andric const Function *F = FuncInfo.Fn; 6480b57cec5SDimitry Andric if (F->isVarArg()) 6490b57cec5SDimitry Andric return false; 6500b57cec5SDimitry Andric 6515ffd83dbSDimitry Andric if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift) 6525ffd83dbSDimitry Andric return false; 6535ffd83dbSDimitry Andric 6540b57cec5SDimitry Andric unsigned I = 0; 6550b57cec5SDimitry Andric for (auto const &Arg : F->args()) { 6560b57cec5SDimitry Andric const AttributeList &Attrs = F->getAttributes(); 657349cc55cSDimitry Andric if (Attrs.hasParamAttr(I, Attribute::ByVal) || 658349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::SwiftSelf) || 659349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::SwiftError) || 660349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::InAlloca) || 661349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::Nest)) 6620b57cec5SDimitry Andric return false; 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric Type *ArgTy = Arg.getType(); 6650b57cec5SDimitry Andric if (ArgTy->isStructTy() || ArgTy->isArrayTy()) 6660b57cec5SDimitry Andric return false; 6670b57cec5SDimitry Andric if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy()) 6680b57cec5SDimitry Andric return false; 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric unsigned Opc; 6710b57cec5SDimitry Andric const TargetRegisterClass *RC; 6720b57cec5SDimitry Andric switch (getSimpleType(ArgTy)) { 6730b57cec5SDimitry Andric case MVT::i1: 6740b57cec5SDimitry Andric case MVT::i8: 6750b57cec5SDimitry Andric case MVT::i16: 6760b57cec5SDimitry Andric case MVT::i32: 6770b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_i32; 6780b57cec5SDimitry Andric RC = &WebAssembly::I32RegClass; 6790b57cec5SDimitry Andric break; 6800b57cec5SDimitry Andric case MVT::i64: 6810b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_i64; 6820b57cec5SDimitry Andric RC = &WebAssembly::I64RegClass; 6830b57cec5SDimitry Andric break; 6840b57cec5SDimitry Andric case MVT::f32: 6850b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_f32; 6860b57cec5SDimitry Andric RC = &WebAssembly::F32RegClass; 6870b57cec5SDimitry Andric break; 6880b57cec5SDimitry Andric case MVT::f64: 6890b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_f64; 6900b57cec5SDimitry Andric RC = &WebAssembly::F64RegClass; 6910b57cec5SDimitry Andric break; 6920b57cec5SDimitry Andric case MVT::v16i8: 6930b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_v16i8; 6940b57cec5SDimitry Andric RC = &WebAssembly::V128RegClass; 6950b57cec5SDimitry Andric break; 6960b57cec5SDimitry Andric case MVT::v8i16: 6970b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_v8i16; 6980b57cec5SDimitry Andric RC = &WebAssembly::V128RegClass; 6990b57cec5SDimitry Andric break; 7000b57cec5SDimitry Andric case MVT::v4i32: 7010b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_v4i32; 7020b57cec5SDimitry Andric RC = &WebAssembly::V128RegClass; 7030b57cec5SDimitry Andric break; 7040b57cec5SDimitry Andric case MVT::v2i64: 7050b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_v2i64; 7060b57cec5SDimitry Andric RC = &WebAssembly::V128RegClass; 7070b57cec5SDimitry Andric break; 7080b57cec5SDimitry Andric case MVT::v4f32: 7090b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_v4f32; 7100b57cec5SDimitry Andric RC = &WebAssembly::V128RegClass; 7110b57cec5SDimitry Andric break; 7120b57cec5SDimitry Andric case MVT::v2f64: 7130b57cec5SDimitry Andric Opc = WebAssembly::ARGUMENT_v2f64; 7140b57cec5SDimitry Andric RC = &WebAssembly::V128RegClass; 7150b57cec5SDimitry Andric break; 716e8d8bef9SDimitry Andric case MVT::funcref: 717e8d8bef9SDimitry Andric Opc = WebAssembly::ARGUMENT_funcref; 718e8d8bef9SDimitry Andric RC = &WebAssembly::FUNCREFRegClass; 719e8d8bef9SDimitry Andric break; 720e8d8bef9SDimitry Andric case MVT::externref: 721e8d8bef9SDimitry Andric Opc = WebAssembly::ARGUMENT_externref; 722e8d8bef9SDimitry Andric RC = &WebAssembly::EXTERNREFRegClass; 7230b57cec5SDimitry Andric break; 724*0fca6ea1SDimitry Andric case MVT::exnref: 725*0fca6ea1SDimitry Andric Opc = WebAssembly::ARGUMENT_exnref; 726*0fca6ea1SDimitry Andric RC = &WebAssembly::EXNREFRegClass; 727*0fca6ea1SDimitry Andric break; 7280b57cec5SDimitry Andric default: 7290b57cec5SDimitry Andric return false; 7300b57cec5SDimitry Andric } 73104eeddc0SDimitry Andric Register ResultReg = createResultReg(RC); 732bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) 7330b57cec5SDimitry Andric .addImm(I); 7340b57cec5SDimitry Andric updateValueMap(&Arg, ResultReg); 7350b57cec5SDimitry Andric 7360b57cec5SDimitry Andric ++I; 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric MRI.addLiveIn(WebAssembly::ARGUMENTS); 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>(); 7420b57cec5SDimitry Andric for (auto const &Arg : F->args()) { 7430b57cec5SDimitry Andric MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType())); 7440b57cec5SDimitry Andric if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) { 7450b57cec5SDimitry Andric MFI->clearParamsAndResults(); 7460b57cec5SDimitry Andric return false; 7470b57cec5SDimitry Andric } 7480b57cec5SDimitry Andric MFI->addParam(ArgTy); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric if (!F->getReturnType()->isVoidTy()) { 7520b57cec5SDimitry Andric MVT::SimpleValueType RetTy = 7530b57cec5SDimitry Andric getLegalType(getSimpleType(F->getReturnType())); 7540b57cec5SDimitry Andric if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) { 7550b57cec5SDimitry Andric MFI->clearParamsAndResults(); 7560b57cec5SDimitry Andric return false; 7570b57cec5SDimitry Andric } 7580b57cec5SDimitry Andric MFI->addResult(RetTy); 7590b57cec5SDimitry Andric } 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric return true; 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric bool WebAssemblyFastISel::selectCall(const Instruction *I) { 7650b57cec5SDimitry Andric const auto *Call = cast<CallInst>(I); 7660b57cec5SDimitry Andric 7670b57cec5SDimitry Andric // TODO: Support tail calls in FastISel 7680b57cec5SDimitry Andric if (Call->isMustTailCall() || Call->isInlineAsm() || 7690b57cec5SDimitry Andric Call->getFunctionType()->isVarArg()) 7700b57cec5SDimitry Andric return false; 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric Function *Func = Call->getCalledFunction(); 7730b57cec5SDimitry Andric if (Func && Func->isIntrinsic()) 7740b57cec5SDimitry Andric return false; 7750b57cec5SDimitry Andric 7765ffd83dbSDimitry Andric if (Call->getCallingConv() == CallingConv::Swift) 7775ffd83dbSDimitry Andric return false; 7785ffd83dbSDimitry Andric 7790b57cec5SDimitry Andric bool IsDirect = Func != nullptr; 7805ffd83dbSDimitry Andric if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand())) 7810b57cec5SDimitry Andric return false; 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric FunctionType *FuncTy = Call->getFunctionType(); 7845ffd83dbSDimitry Andric unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT; 7850b57cec5SDimitry Andric bool IsVoid = FuncTy->getReturnType()->isVoidTy(); 7860b57cec5SDimitry Andric unsigned ResultReg; 7875ffd83dbSDimitry Andric if (!IsVoid) { 7880b57cec5SDimitry Andric if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy()) 7890b57cec5SDimitry Andric return false; 7900b57cec5SDimitry Andric 7910b57cec5SDimitry Andric MVT::SimpleValueType RetTy = getSimpleType(Call->getType()); 7920b57cec5SDimitry Andric switch (RetTy) { 7930b57cec5SDimitry Andric case MVT::i1: 7940b57cec5SDimitry Andric case MVT::i8: 7950b57cec5SDimitry Andric case MVT::i16: 7960b57cec5SDimitry Andric case MVT::i32: 7970b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::I32RegClass); 7980b57cec5SDimitry Andric break; 7990b57cec5SDimitry Andric case MVT::i64: 8000b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::I64RegClass); 8010b57cec5SDimitry Andric break; 8020b57cec5SDimitry Andric case MVT::f32: 8030b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::F32RegClass); 8040b57cec5SDimitry Andric break; 8050b57cec5SDimitry Andric case MVT::f64: 8060b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::F64RegClass); 8070b57cec5SDimitry Andric break; 8080b57cec5SDimitry Andric case MVT::v16i8: 8090b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::V128RegClass); 8100b57cec5SDimitry Andric break; 8110b57cec5SDimitry Andric case MVT::v8i16: 8120b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::V128RegClass); 8130b57cec5SDimitry Andric break; 8140b57cec5SDimitry Andric case MVT::v4i32: 8150b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::V128RegClass); 8160b57cec5SDimitry Andric break; 8170b57cec5SDimitry Andric case MVT::v2i64: 8180b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::V128RegClass); 8190b57cec5SDimitry Andric break; 8200b57cec5SDimitry Andric case MVT::v4f32: 8210b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::V128RegClass); 8220b57cec5SDimitry Andric break; 8230b57cec5SDimitry Andric case MVT::v2f64: 8240b57cec5SDimitry Andric ResultReg = createResultReg(&WebAssembly::V128RegClass); 8250b57cec5SDimitry Andric break; 826e8d8bef9SDimitry Andric case MVT::funcref: 827e8d8bef9SDimitry Andric ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass); 828e8d8bef9SDimitry Andric break; 829e8d8bef9SDimitry Andric case MVT::externref: 830e8d8bef9SDimitry Andric ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass); 8310b57cec5SDimitry Andric break; 832*0fca6ea1SDimitry Andric case MVT::exnref: 833*0fca6ea1SDimitry Andric ResultReg = createResultReg(&WebAssembly::EXNREFRegClass); 834*0fca6ea1SDimitry Andric break; 8350b57cec5SDimitry Andric default: 8360b57cec5SDimitry Andric return false; 8370b57cec5SDimitry Andric } 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric 8400b57cec5SDimitry Andric SmallVector<unsigned, 8> Args; 841349cc55cSDimitry Andric for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) { 8420b57cec5SDimitry Andric Value *V = Call->getArgOperand(I); 8430b57cec5SDimitry Andric MVT::SimpleValueType ArgTy = getSimpleType(V->getType()); 8440b57cec5SDimitry Andric if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) 8450b57cec5SDimitry Andric return false; 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric const AttributeList &Attrs = Call->getAttributes(); 848349cc55cSDimitry Andric if (Attrs.hasParamAttr(I, Attribute::ByVal) || 849349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::SwiftSelf) || 850349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::SwiftError) || 851349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::InAlloca) || 852349cc55cSDimitry Andric Attrs.hasParamAttr(I, Attribute::Nest)) 8530b57cec5SDimitry Andric return false; 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric unsigned Reg; 8560b57cec5SDimitry Andric 857297eecfbSDimitry Andric if (Call->paramHasAttr(I, Attribute::SExt)) 8580b57cec5SDimitry Andric Reg = getRegForSignedValue(V); 859297eecfbSDimitry Andric else if (Call->paramHasAttr(I, Attribute::ZExt)) 8600b57cec5SDimitry Andric Reg = getRegForUnsignedValue(V); 8610b57cec5SDimitry Andric else 8620b57cec5SDimitry Andric Reg = getRegForValue(V); 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric if (Reg == 0) 8650b57cec5SDimitry Andric return false; 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric Args.push_back(Reg); 8680b57cec5SDimitry Andric } 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric unsigned CalleeReg = 0; 8710b57cec5SDimitry Andric if (!IsDirect) { 8725ffd83dbSDimitry Andric CalleeReg = getRegForValue(Call->getCalledOperand()); 8730b57cec5SDimitry Andric if (!CalleeReg) 8740b57cec5SDimitry Andric return false; 8750b57cec5SDimitry Andric } 8760b57cec5SDimitry Andric 877bdd1243dSDimitry Andric auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc)); 8780b57cec5SDimitry Andric 8790b57cec5SDimitry Andric if (!IsVoid) 8800b57cec5SDimitry Andric MIB.addReg(ResultReg, RegState::Define); 8810b57cec5SDimitry Andric 8825ffd83dbSDimitry Andric if (IsDirect) { 8830b57cec5SDimitry Andric MIB.addGlobalAddress(Func); 8845ffd83dbSDimitry Andric } else { 885fe6060f1SDimitry Andric // Placeholder for the type index. 8865ffd83dbSDimitry Andric MIB.addImm(0); 887fe6060f1SDimitry Andric // The table into which this call_indirect indexes. 888fe6060f1SDimitry Andric MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol( 889*0fca6ea1SDimitry Andric MF->getContext(), Subtarget); 890fe6060f1SDimitry Andric if (Subtarget->hasReferenceTypes()) { 891fe6060f1SDimitry Andric MIB.addSym(Table); 892fe6060f1SDimitry Andric } else { 893fe6060f1SDimitry Andric // Otherwise for the MVP there is at most one table whose number is 0, but 894fe6060f1SDimitry Andric // we can't write a table symbol or issue relocations. Instead we just 895fe6060f1SDimitry Andric // ensure the table is live. 896fe6060f1SDimitry Andric Table->setNoStrip(); 8975ffd83dbSDimitry Andric MIB.addImm(0); 898fe6060f1SDimitry Andric } 8995ffd83dbSDimitry Andric } 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric for (unsigned ArgReg : Args) 9020b57cec5SDimitry Andric MIB.addReg(ArgReg); 9030b57cec5SDimitry Andric 9045ffd83dbSDimitry Andric if (!IsDirect) 9055ffd83dbSDimitry Andric MIB.addReg(CalleeReg); 9065ffd83dbSDimitry Andric 9070b57cec5SDimitry Andric if (!IsVoid) 9080b57cec5SDimitry Andric updateValueMap(Call, ResultReg); 9090b57cec5SDimitry Andric return true; 9100b57cec5SDimitry Andric } 9110b57cec5SDimitry Andric 9120b57cec5SDimitry Andric bool WebAssemblyFastISel::selectSelect(const Instruction *I) { 9130b57cec5SDimitry Andric const auto *Select = cast<SelectInst>(I); 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric bool Not; 91669ade1e0SDimitry Andric unsigned CondReg = 91769ade1e0SDimitry Andric getRegForI1Value(Select->getCondition(), I->getParent(), Not); 9180b57cec5SDimitry Andric if (CondReg == 0) 9190b57cec5SDimitry Andric return false; 9200b57cec5SDimitry Andric 92104eeddc0SDimitry Andric Register TrueReg = getRegForValue(Select->getTrueValue()); 9220b57cec5SDimitry Andric if (TrueReg == 0) 9230b57cec5SDimitry Andric return false; 9240b57cec5SDimitry Andric 92504eeddc0SDimitry Andric Register FalseReg = getRegForValue(Select->getFalseValue()); 9260b57cec5SDimitry Andric if (FalseReg == 0) 9270b57cec5SDimitry Andric return false; 9280b57cec5SDimitry Andric 9290b57cec5SDimitry Andric if (Not) 9300b57cec5SDimitry Andric std::swap(TrueReg, FalseReg); 9310b57cec5SDimitry Andric 9320b57cec5SDimitry Andric unsigned Opc; 9330b57cec5SDimitry Andric const TargetRegisterClass *RC; 9340b57cec5SDimitry Andric switch (getSimpleType(Select->getType())) { 9350b57cec5SDimitry Andric case MVT::i1: 9360b57cec5SDimitry Andric case MVT::i8: 9370b57cec5SDimitry Andric case MVT::i16: 9380b57cec5SDimitry Andric case MVT::i32: 9390b57cec5SDimitry Andric Opc = WebAssembly::SELECT_I32; 9400b57cec5SDimitry Andric RC = &WebAssembly::I32RegClass; 9410b57cec5SDimitry Andric break; 9420b57cec5SDimitry Andric case MVT::i64: 9430b57cec5SDimitry Andric Opc = WebAssembly::SELECT_I64; 9440b57cec5SDimitry Andric RC = &WebAssembly::I64RegClass; 9450b57cec5SDimitry Andric break; 9460b57cec5SDimitry Andric case MVT::f32: 9470b57cec5SDimitry Andric Opc = WebAssembly::SELECT_F32; 9480b57cec5SDimitry Andric RC = &WebAssembly::F32RegClass; 9490b57cec5SDimitry Andric break; 9500b57cec5SDimitry Andric case MVT::f64: 9510b57cec5SDimitry Andric Opc = WebAssembly::SELECT_F64; 9520b57cec5SDimitry Andric RC = &WebAssembly::F64RegClass; 9530b57cec5SDimitry Andric break; 954e8d8bef9SDimitry Andric case MVT::funcref: 955e8d8bef9SDimitry Andric Opc = WebAssembly::SELECT_FUNCREF; 956e8d8bef9SDimitry Andric RC = &WebAssembly::FUNCREFRegClass; 957e8d8bef9SDimitry Andric break; 958e8d8bef9SDimitry Andric case MVT::externref: 959e8d8bef9SDimitry Andric Opc = WebAssembly::SELECT_EXTERNREF; 960e8d8bef9SDimitry Andric RC = &WebAssembly::EXTERNREFRegClass; 9610b57cec5SDimitry Andric break; 962*0fca6ea1SDimitry Andric case MVT::exnref: 963*0fca6ea1SDimitry Andric Opc = WebAssembly::SELECT_EXNREF; 964*0fca6ea1SDimitry Andric RC = &WebAssembly::EXNREFRegClass; 965*0fca6ea1SDimitry Andric break; 9660b57cec5SDimitry Andric default: 9670b57cec5SDimitry Andric return false; 9680b57cec5SDimitry Andric } 9690b57cec5SDimitry Andric 97004eeddc0SDimitry Andric Register ResultReg = createResultReg(RC); 971bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) 9720b57cec5SDimitry Andric .addReg(TrueReg) 9730b57cec5SDimitry Andric .addReg(FalseReg) 9740b57cec5SDimitry Andric .addReg(CondReg); 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric updateValueMap(Select, ResultReg); 9770b57cec5SDimitry Andric return true; 9780b57cec5SDimitry Andric } 9790b57cec5SDimitry Andric 9800b57cec5SDimitry Andric bool WebAssemblyFastISel::selectTrunc(const Instruction *I) { 9810b57cec5SDimitry Andric const auto *Trunc = cast<TruncInst>(I); 9820b57cec5SDimitry Andric 98304eeddc0SDimitry Andric Register Reg = getRegForValue(Trunc->getOperand(0)); 9840b57cec5SDimitry Andric if (Reg == 0) 9850b57cec5SDimitry Andric return false; 9860b57cec5SDimitry Andric 9870b57cec5SDimitry Andric if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) { 98804eeddc0SDimitry Andric Register Result = createResultReg(&WebAssembly::I32RegClass); 989bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 9900b57cec5SDimitry Andric TII.get(WebAssembly::I32_WRAP_I64), Result) 9910b57cec5SDimitry Andric .addReg(Reg); 9920b57cec5SDimitry Andric Reg = Result; 9930b57cec5SDimitry Andric } 9940b57cec5SDimitry Andric 9950b57cec5SDimitry Andric updateValueMap(Trunc, Reg); 9960b57cec5SDimitry Andric return true; 9970b57cec5SDimitry Andric } 9980b57cec5SDimitry Andric 9990b57cec5SDimitry Andric bool WebAssemblyFastISel::selectZExt(const Instruction *I) { 10000b57cec5SDimitry Andric const auto *ZExt = cast<ZExtInst>(I); 10010b57cec5SDimitry Andric 10020b57cec5SDimitry Andric const Value *Op = ZExt->getOperand(0); 10030b57cec5SDimitry Andric MVT::SimpleValueType From = getSimpleType(Op->getType()); 10040b57cec5SDimitry Andric MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType())); 100504eeddc0SDimitry Andric Register In = getRegForValue(Op); 10060b57cec5SDimitry Andric if (In == 0) 10070b57cec5SDimitry Andric return false; 10080b57cec5SDimitry Andric unsigned Reg = zeroExtend(In, Op, From, To); 10090b57cec5SDimitry Andric if (Reg == 0) 10100b57cec5SDimitry Andric return false; 10110b57cec5SDimitry Andric 10120b57cec5SDimitry Andric updateValueMap(ZExt, Reg); 10130b57cec5SDimitry Andric return true; 10140b57cec5SDimitry Andric } 10150b57cec5SDimitry Andric 10160b57cec5SDimitry Andric bool WebAssemblyFastISel::selectSExt(const Instruction *I) { 10170b57cec5SDimitry Andric const auto *SExt = cast<SExtInst>(I); 10180b57cec5SDimitry Andric 10190b57cec5SDimitry Andric const Value *Op = SExt->getOperand(0); 10200b57cec5SDimitry Andric MVT::SimpleValueType From = getSimpleType(Op->getType()); 10210b57cec5SDimitry Andric MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType())); 102204eeddc0SDimitry Andric Register In = getRegForValue(Op); 10230b57cec5SDimitry Andric if (In == 0) 10240b57cec5SDimitry Andric return false; 10250b57cec5SDimitry Andric unsigned Reg = signExtend(In, Op, From, To); 10260b57cec5SDimitry Andric if (Reg == 0) 10270b57cec5SDimitry Andric return false; 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric updateValueMap(SExt, Reg); 10300b57cec5SDimitry Andric return true; 10310b57cec5SDimitry Andric } 10320b57cec5SDimitry Andric 10330b57cec5SDimitry Andric bool WebAssemblyFastISel::selectICmp(const Instruction *I) { 10340b57cec5SDimitry Andric const auto *ICmp = cast<ICmpInst>(I); 10350b57cec5SDimitry Andric 10360b57cec5SDimitry Andric bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64; 10370b57cec5SDimitry Andric unsigned Opc; 10380b57cec5SDimitry Andric bool IsSigned = false; 10390b57cec5SDimitry Andric switch (ICmp->getPredicate()) { 10400b57cec5SDimitry Andric case ICmpInst::ICMP_EQ: 10410b57cec5SDimitry Andric Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64; 10420b57cec5SDimitry Andric break; 10430b57cec5SDimitry Andric case ICmpInst::ICMP_NE: 10440b57cec5SDimitry Andric Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64; 10450b57cec5SDimitry Andric break; 10460b57cec5SDimitry Andric case ICmpInst::ICMP_UGT: 10470b57cec5SDimitry Andric Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64; 10480b57cec5SDimitry Andric break; 10490b57cec5SDimitry Andric case ICmpInst::ICMP_UGE: 10500b57cec5SDimitry Andric Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64; 10510b57cec5SDimitry Andric break; 10520b57cec5SDimitry Andric case ICmpInst::ICMP_ULT: 10530b57cec5SDimitry Andric Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64; 10540b57cec5SDimitry Andric break; 10550b57cec5SDimitry Andric case ICmpInst::ICMP_ULE: 10560b57cec5SDimitry Andric Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64; 10570b57cec5SDimitry Andric break; 10580b57cec5SDimitry Andric case ICmpInst::ICMP_SGT: 10590b57cec5SDimitry Andric Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64; 10600b57cec5SDimitry Andric IsSigned = true; 10610b57cec5SDimitry Andric break; 10620b57cec5SDimitry Andric case ICmpInst::ICMP_SGE: 10630b57cec5SDimitry Andric Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64; 10640b57cec5SDimitry Andric IsSigned = true; 10650b57cec5SDimitry Andric break; 10660b57cec5SDimitry Andric case ICmpInst::ICMP_SLT: 10670b57cec5SDimitry Andric Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64; 10680b57cec5SDimitry Andric IsSigned = true; 10690b57cec5SDimitry Andric break; 10700b57cec5SDimitry Andric case ICmpInst::ICMP_SLE: 10710b57cec5SDimitry Andric Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64; 10720b57cec5SDimitry Andric IsSigned = true; 10730b57cec5SDimitry Andric break; 10740b57cec5SDimitry Andric default: 10750b57cec5SDimitry Andric return false; 10760b57cec5SDimitry Andric } 10770b57cec5SDimitry Andric 10780b57cec5SDimitry Andric unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned); 10790b57cec5SDimitry Andric if (LHS == 0) 10800b57cec5SDimitry Andric return false; 10810b57cec5SDimitry Andric 10820b57cec5SDimitry Andric unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned); 10830b57cec5SDimitry Andric if (RHS == 0) 10840b57cec5SDimitry Andric return false; 10850b57cec5SDimitry Andric 108604eeddc0SDimitry Andric Register ResultReg = createResultReg(&WebAssembly::I32RegClass); 1087bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) 10880b57cec5SDimitry Andric .addReg(LHS) 10890b57cec5SDimitry Andric .addReg(RHS); 10900b57cec5SDimitry Andric updateValueMap(ICmp, ResultReg); 10910b57cec5SDimitry Andric return true; 10920b57cec5SDimitry Andric } 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric bool WebAssemblyFastISel::selectFCmp(const Instruction *I) { 10950b57cec5SDimitry Andric const auto *FCmp = cast<FCmpInst>(I); 10960b57cec5SDimitry Andric 109704eeddc0SDimitry Andric Register LHS = getRegForValue(FCmp->getOperand(0)); 10980b57cec5SDimitry Andric if (LHS == 0) 10990b57cec5SDimitry Andric return false; 11000b57cec5SDimitry Andric 110104eeddc0SDimitry Andric Register RHS = getRegForValue(FCmp->getOperand(1)); 11020b57cec5SDimitry Andric if (RHS == 0) 11030b57cec5SDimitry Andric return false; 11040b57cec5SDimitry Andric 11050b57cec5SDimitry Andric bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64; 11060b57cec5SDimitry Andric unsigned Opc; 11070b57cec5SDimitry Andric bool Not = false; 11080b57cec5SDimitry Andric switch (FCmp->getPredicate()) { 11090b57cec5SDimitry Andric case FCmpInst::FCMP_OEQ: 11100b57cec5SDimitry Andric Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64; 11110b57cec5SDimitry Andric break; 11120b57cec5SDimitry Andric case FCmpInst::FCMP_UNE: 11130b57cec5SDimitry Andric Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64; 11140b57cec5SDimitry Andric break; 11150b57cec5SDimitry Andric case FCmpInst::FCMP_OGT: 11160b57cec5SDimitry Andric Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 11170b57cec5SDimitry Andric break; 11180b57cec5SDimitry Andric case FCmpInst::FCMP_OGE: 11190b57cec5SDimitry Andric Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 11200b57cec5SDimitry Andric break; 11210b57cec5SDimitry Andric case FCmpInst::FCMP_OLT: 11220b57cec5SDimitry Andric Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 11230b57cec5SDimitry Andric break; 11240b57cec5SDimitry Andric case FCmpInst::FCMP_OLE: 11250b57cec5SDimitry Andric Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 11260b57cec5SDimitry Andric break; 11270b57cec5SDimitry Andric case FCmpInst::FCMP_UGT: 11280b57cec5SDimitry Andric Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 11290b57cec5SDimitry Andric Not = true; 11300b57cec5SDimitry Andric break; 11310b57cec5SDimitry Andric case FCmpInst::FCMP_UGE: 11320b57cec5SDimitry Andric Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 11330b57cec5SDimitry Andric Not = true; 11340b57cec5SDimitry Andric break; 11350b57cec5SDimitry Andric case FCmpInst::FCMP_ULT: 11360b57cec5SDimitry Andric Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 11370b57cec5SDimitry Andric Not = true; 11380b57cec5SDimitry Andric break; 11390b57cec5SDimitry Andric case FCmpInst::FCMP_ULE: 11400b57cec5SDimitry Andric Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 11410b57cec5SDimitry Andric Not = true; 11420b57cec5SDimitry Andric break; 11430b57cec5SDimitry Andric default: 11440b57cec5SDimitry Andric return false; 11450b57cec5SDimitry Andric } 11460b57cec5SDimitry Andric 114704eeddc0SDimitry Andric Register ResultReg = createResultReg(&WebAssembly::I32RegClass); 1148bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) 11490b57cec5SDimitry Andric .addReg(LHS) 11500b57cec5SDimitry Andric .addReg(RHS); 11510b57cec5SDimitry Andric 11520b57cec5SDimitry Andric if (Not) 11530b57cec5SDimitry Andric ResultReg = notValue(ResultReg); 11540b57cec5SDimitry Andric 11550b57cec5SDimitry Andric updateValueMap(FCmp, ResultReg); 11560b57cec5SDimitry Andric return true; 11570b57cec5SDimitry Andric } 11580b57cec5SDimitry Andric 11590b57cec5SDimitry Andric bool WebAssemblyFastISel::selectBitCast(const Instruction *I) { 11600b57cec5SDimitry Andric // Target-independent code can handle this, except it doesn't set the dead 11610b57cec5SDimitry Andric // flag on the ARGUMENTS clobber, so we have to do that manually in order 11620b57cec5SDimitry Andric // to satisfy code that expects this of isBitcast() instructions. 11630b57cec5SDimitry Andric EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType()); 11640b57cec5SDimitry Andric EVT RetVT = TLI.getValueType(DL, I->getType()); 11650b57cec5SDimitry Andric if (!VT.isSimple() || !RetVT.isSimple()) 11660b57cec5SDimitry Andric return false; 11670b57cec5SDimitry Andric 116804eeddc0SDimitry Andric Register In = getRegForValue(I->getOperand(0)); 11690b57cec5SDimitry Andric if (In == 0) 11700b57cec5SDimitry Andric return false; 11710b57cec5SDimitry Andric 11720b57cec5SDimitry Andric if (VT == RetVT) { 11730b57cec5SDimitry Andric // No-op bitcast. 11740b57cec5SDimitry Andric updateValueMap(I, In); 11750b57cec5SDimitry Andric return true; 11760b57cec5SDimitry Andric } 11770b57cec5SDimitry Andric 11788bcb0991SDimitry Andric Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), 1179fe6060f1SDimitry Andric In); 11800b57cec5SDimitry Andric if (!Reg) 11810b57cec5SDimitry Andric return false; 11820b57cec5SDimitry Andric MachineBasicBlock::iterator Iter = FuncInfo.InsertPt; 11830b57cec5SDimitry Andric --Iter; 11840b57cec5SDimitry Andric assert(Iter->isBitcast()); 11858bcb0991SDimitry Andric Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI); 11860b57cec5SDimitry Andric updateValueMap(I, Reg); 11870b57cec5SDimitry Andric return true; 11880b57cec5SDimitry Andric } 11890b57cec5SDimitry Andric 11900b57cec5SDimitry Andric bool WebAssemblyFastISel::selectLoad(const Instruction *I) { 11910b57cec5SDimitry Andric const auto *Load = cast<LoadInst>(I); 11920b57cec5SDimitry Andric if (Load->isAtomic()) 11930b57cec5SDimitry Andric return false; 1194fe6060f1SDimitry Andric if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace())) 1195fe6060f1SDimitry Andric return false; 11960b57cec5SDimitry Andric if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy()) 11970b57cec5SDimitry Andric return false; 11980b57cec5SDimitry Andric 11990b57cec5SDimitry Andric Address Addr; 12000b57cec5SDimitry Andric if (!computeAddress(Load->getPointerOperand(), Addr)) 12010b57cec5SDimitry Andric return false; 12020b57cec5SDimitry Andric 12030b57cec5SDimitry Andric // TODO: Fold a following sign-/zero-extend into the load instruction. 12040b57cec5SDimitry Andric 12050b57cec5SDimitry Andric unsigned Opc; 12060b57cec5SDimitry Andric const TargetRegisterClass *RC; 12075ffd83dbSDimitry Andric bool A64 = Subtarget->hasAddr64(); 12080b57cec5SDimitry Andric switch (getSimpleType(Load->getType())) { 12090b57cec5SDimitry Andric case MVT::i1: 12100b57cec5SDimitry Andric case MVT::i8: 12115ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32; 12120b57cec5SDimitry Andric RC = &WebAssembly::I32RegClass; 12130b57cec5SDimitry Andric break; 12140b57cec5SDimitry Andric case MVT::i16: 12155ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32; 12160b57cec5SDimitry Andric RC = &WebAssembly::I32RegClass; 12170b57cec5SDimitry Andric break; 12180b57cec5SDimitry Andric case MVT::i32: 12195ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32; 12200b57cec5SDimitry Andric RC = &WebAssembly::I32RegClass; 12210b57cec5SDimitry Andric break; 12220b57cec5SDimitry Andric case MVT::i64: 12235ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32; 12240b57cec5SDimitry Andric RC = &WebAssembly::I64RegClass; 12250b57cec5SDimitry Andric break; 12260b57cec5SDimitry Andric case MVT::f32: 12275ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32; 12280b57cec5SDimitry Andric RC = &WebAssembly::F32RegClass; 12290b57cec5SDimitry Andric break; 12300b57cec5SDimitry Andric case MVT::f64: 12315ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32; 12320b57cec5SDimitry Andric RC = &WebAssembly::F64RegClass; 12330b57cec5SDimitry Andric break; 12340b57cec5SDimitry Andric default: 12350b57cec5SDimitry Andric return false; 12360b57cec5SDimitry Andric } 12370b57cec5SDimitry Andric 12380b57cec5SDimitry Andric materializeLoadStoreOperands(Addr); 12390b57cec5SDimitry Andric 124004eeddc0SDimitry Andric Register ResultReg = createResultReg(RC); 1241bdd1243dSDimitry Andric auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), 12420b57cec5SDimitry Andric ResultReg); 12430b57cec5SDimitry Andric 12440b57cec5SDimitry Andric addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load)); 12450b57cec5SDimitry Andric 12460b57cec5SDimitry Andric updateValueMap(Load, ResultReg); 12470b57cec5SDimitry Andric return true; 12480b57cec5SDimitry Andric } 12490b57cec5SDimitry Andric 12500b57cec5SDimitry Andric bool WebAssemblyFastISel::selectStore(const Instruction *I) { 12510b57cec5SDimitry Andric const auto *Store = cast<StoreInst>(I); 12520b57cec5SDimitry Andric if (Store->isAtomic()) 12530b57cec5SDimitry Andric return false; 1254fe6060f1SDimitry Andric if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace())) 1255fe6060f1SDimitry Andric return false; 12560b57cec5SDimitry Andric if (!Subtarget->hasSIMD128() && 12570b57cec5SDimitry Andric Store->getValueOperand()->getType()->isVectorTy()) 12580b57cec5SDimitry Andric return false; 12590b57cec5SDimitry Andric 12600b57cec5SDimitry Andric Address Addr; 12610b57cec5SDimitry Andric if (!computeAddress(Store->getPointerOperand(), Addr)) 12620b57cec5SDimitry Andric return false; 12630b57cec5SDimitry Andric 12640b57cec5SDimitry Andric unsigned Opc; 12650b57cec5SDimitry Andric bool VTIsi1 = false; 12665ffd83dbSDimitry Andric bool A64 = Subtarget->hasAddr64(); 12670b57cec5SDimitry Andric switch (getSimpleType(Store->getValueOperand()->getType())) { 12680b57cec5SDimitry Andric case MVT::i1: 12690b57cec5SDimitry Andric VTIsi1 = true; 1270bdd1243dSDimitry Andric [[fallthrough]]; 12710b57cec5SDimitry Andric case MVT::i8: 12725ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32; 12730b57cec5SDimitry Andric break; 12740b57cec5SDimitry Andric case MVT::i16: 12755ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32; 12760b57cec5SDimitry Andric break; 12770b57cec5SDimitry Andric case MVT::i32: 12785ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32; 12790b57cec5SDimitry Andric break; 12800b57cec5SDimitry Andric case MVT::i64: 12815ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32; 12820b57cec5SDimitry Andric break; 12830b57cec5SDimitry Andric case MVT::f32: 12845ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32; 12850b57cec5SDimitry Andric break; 12860b57cec5SDimitry Andric case MVT::f64: 12875ffd83dbSDimitry Andric Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32; 12880b57cec5SDimitry Andric break; 12890b57cec5SDimitry Andric default: 12900b57cec5SDimitry Andric return false; 12910b57cec5SDimitry Andric } 12920b57cec5SDimitry Andric 12930b57cec5SDimitry Andric materializeLoadStoreOperands(Addr); 12940b57cec5SDimitry Andric 129504eeddc0SDimitry Andric Register ValueReg = getRegForValue(Store->getValueOperand()); 12960b57cec5SDimitry Andric if (ValueReg == 0) 12970b57cec5SDimitry Andric return false; 12980b57cec5SDimitry Andric if (VTIsi1) 12990b57cec5SDimitry Andric ValueReg = maskI1Value(ValueReg, Store->getValueOperand()); 13000b57cec5SDimitry Andric 1301bdd1243dSDimitry Andric auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc)); 13020b57cec5SDimitry Andric 13030b57cec5SDimitry Andric addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store)); 13040b57cec5SDimitry Andric 13050b57cec5SDimitry Andric MIB.addReg(ValueReg); 13060b57cec5SDimitry Andric return true; 13070b57cec5SDimitry Andric } 13080b57cec5SDimitry Andric 13090b57cec5SDimitry Andric bool WebAssemblyFastISel::selectBr(const Instruction *I) { 13100b57cec5SDimitry Andric const auto *Br = cast<BranchInst>(I); 13110b57cec5SDimitry Andric if (Br->isUnconditional()) { 13120b57cec5SDimitry Andric MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)]; 13130b57cec5SDimitry Andric fastEmitBranch(MSucc, Br->getDebugLoc()); 13140b57cec5SDimitry Andric return true; 13150b57cec5SDimitry Andric } 13160b57cec5SDimitry Andric 13170b57cec5SDimitry Andric MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)]; 13180b57cec5SDimitry Andric MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)]; 13190b57cec5SDimitry Andric 13200b57cec5SDimitry Andric bool Not; 132169ade1e0SDimitry Andric unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not); 13220b57cec5SDimitry Andric if (CondReg == 0) 13230b57cec5SDimitry Andric return false; 13240b57cec5SDimitry Andric 13250b57cec5SDimitry Andric unsigned Opc = WebAssembly::BR_IF; 13260b57cec5SDimitry Andric if (Not) 13270b57cec5SDimitry Andric Opc = WebAssembly::BR_UNLESS; 13280b57cec5SDimitry Andric 1329bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc)) 13300b57cec5SDimitry Andric .addMBB(TBB) 13310b57cec5SDimitry Andric .addReg(CondReg); 13320b57cec5SDimitry Andric 13330b57cec5SDimitry Andric finishCondBranch(Br->getParent(), TBB, FBB); 13340b57cec5SDimitry Andric return true; 13350b57cec5SDimitry Andric } 13360b57cec5SDimitry Andric 13370b57cec5SDimitry Andric bool WebAssemblyFastISel::selectRet(const Instruction *I) { 13380b57cec5SDimitry Andric if (!FuncInfo.CanLowerReturn) 13390b57cec5SDimitry Andric return false; 13400b57cec5SDimitry Andric 13410b57cec5SDimitry Andric const auto *Ret = cast<ReturnInst>(I); 13420b57cec5SDimitry Andric 13430b57cec5SDimitry Andric if (Ret->getNumOperands() == 0) { 1344bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 13458bcb0991SDimitry Andric TII.get(WebAssembly::RETURN)); 13460b57cec5SDimitry Andric return true; 13470b57cec5SDimitry Andric } 13480b57cec5SDimitry Andric 13498bcb0991SDimitry Andric // TODO: support multiple return in FastISel 13508bcb0991SDimitry Andric if (Ret->getNumOperands() > 1) 13518bcb0991SDimitry Andric return false; 13528bcb0991SDimitry Andric 13530b57cec5SDimitry Andric Value *RV = Ret->getOperand(0); 13540b57cec5SDimitry Andric if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy()) 13550b57cec5SDimitry Andric return false; 13560b57cec5SDimitry Andric 13570b57cec5SDimitry Andric switch (getSimpleType(RV->getType())) { 13580b57cec5SDimitry Andric case MVT::i1: 13590b57cec5SDimitry Andric case MVT::i8: 13600b57cec5SDimitry Andric case MVT::i16: 13610b57cec5SDimitry Andric case MVT::i32: 13620b57cec5SDimitry Andric case MVT::i64: 13630b57cec5SDimitry Andric case MVT::f32: 13640b57cec5SDimitry Andric case MVT::f64: 13650b57cec5SDimitry Andric case MVT::v16i8: 13660b57cec5SDimitry Andric case MVT::v8i16: 13670b57cec5SDimitry Andric case MVT::v4i32: 13680b57cec5SDimitry Andric case MVT::v2i64: 13690b57cec5SDimitry Andric case MVT::v4f32: 13700b57cec5SDimitry Andric case MVT::v2f64: 1371e8d8bef9SDimitry Andric case MVT::funcref: 1372e8d8bef9SDimitry Andric case MVT::externref: 1373*0fca6ea1SDimitry Andric case MVT::exnref: 13740b57cec5SDimitry Andric break; 13750b57cec5SDimitry Andric default: 13760b57cec5SDimitry Andric return false; 13770b57cec5SDimitry Andric } 13780b57cec5SDimitry Andric 13790b57cec5SDimitry Andric unsigned Reg; 1380349cc55cSDimitry Andric if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt)) 13810b57cec5SDimitry Andric Reg = getRegForSignedValue(RV); 1382349cc55cSDimitry Andric else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt)) 13830b57cec5SDimitry Andric Reg = getRegForUnsignedValue(RV); 13840b57cec5SDimitry Andric else 13850b57cec5SDimitry Andric Reg = getRegForValue(RV); 13860b57cec5SDimitry Andric 13870b57cec5SDimitry Andric if (Reg == 0) 13880b57cec5SDimitry Andric return false; 13890b57cec5SDimitry Andric 1390bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 13918bcb0991SDimitry Andric TII.get(WebAssembly::RETURN)) 13928bcb0991SDimitry Andric .addReg(Reg); 13930b57cec5SDimitry Andric return true; 13940b57cec5SDimitry Andric } 13950b57cec5SDimitry Andric 13960b57cec5SDimitry Andric bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) { 1397bdd1243dSDimitry Andric BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, 13980b57cec5SDimitry Andric TII.get(WebAssembly::UNREACHABLE)); 13990b57cec5SDimitry Andric return true; 14000b57cec5SDimitry Andric } 14010b57cec5SDimitry Andric 14020b57cec5SDimitry Andric bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) { 14030b57cec5SDimitry Andric switch (I->getOpcode()) { 14040b57cec5SDimitry Andric case Instruction::Call: 14050b57cec5SDimitry Andric if (selectCall(I)) 14060b57cec5SDimitry Andric return true; 14070b57cec5SDimitry Andric break; 14080b57cec5SDimitry Andric case Instruction::Select: 14090b57cec5SDimitry Andric return selectSelect(I); 14100b57cec5SDimitry Andric case Instruction::Trunc: 14110b57cec5SDimitry Andric return selectTrunc(I); 14120b57cec5SDimitry Andric case Instruction::ZExt: 14130b57cec5SDimitry Andric return selectZExt(I); 14140b57cec5SDimitry Andric case Instruction::SExt: 14150b57cec5SDimitry Andric return selectSExt(I); 14160b57cec5SDimitry Andric case Instruction::ICmp: 14170b57cec5SDimitry Andric return selectICmp(I); 14180b57cec5SDimitry Andric case Instruction::FCmp: 14190b57cec5SDimitry Andric return selectFCmp(I); 14200b57cec5SDimitry Andric case Instruction::BitCast: 14210b57cec5SDimitry Andric return selectBitCast(I); 14220b57cec5SDimitry Andric case Instruction::Load: 14230b57cec5SDimitry Andric return selectLoad(I); 14240b57cec5SDimitry Andric case Instruction::Store: 14250b57cec5SDimitry Andric return selectStore(I); 14260b57cec5SDimitry Andric case Instruction::Br: 14270b57cec5SDimitry Andric return selectBr(I); 14280b57cec5SDimitry Andric case Instruction::Ret: 14290b57cec5SDimitry Andric return selectRet(I); 14300b57cec5SDimitry Andric case Instruction::Unreachable: 14310b57cec5SDimitry Andric return selectUnreachable(I); 14320b57cec5SDimitry Andric default: 14330b57cec5SDimitry Andric break; 14340b57cec5SDimitry Andric } 14350b57cec5SDimitry Andric 14360b57cec5SDimitry Andric // Fall back to target-independent instruction selection. 14370b57cec5SDimitry Andric return selectOperator(I, I->getOpcode()); 14380b57cec5SDimitry Andric } 14390b57cec5SDimitry Andric 14400b57cec5SDimitry Andric FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo, 14410b57cec5SDimitry Andric const TargetLibraryInfo *LibInfo) { 14420b57cec5SDimitry Andric return new WebAssemblyFastISel(FuncInfo, LibInfo); 14430b57cec5SDimitry Andric } 1444