Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
35266 views
//===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file defines the WebAssembly-specific support for the FastISel10/// class. Some of the target-specific code is generated by tablegen in the file11/// WebAssemblyGenFastISel.inc, which is #included here.12///13/// TODO: kill flags14///15//===----------------------------------------------------------------------===//1617#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"18#include "Utils/WebAssemblyTypeUtilities.h"19#include "WebAssembly.h"20#include "WebAssemblyMachineFunctionInfo.h"21#include "WebAssemblySubtarget.h"22#include "WebAssemblyTargetMachine.h"23#include "WebAssemblyUtilities.h"24#include "llvm/Analysis/BranchProbabilityInfo.h"25#include "llvm/CodeGen/FastISel.h"26#include "llvm/CodeGen/FunctionLoweringInfo.h"27#include "llvm/CodeGen/MachineConstantPool.h"28#include "llvm/CodeGen/MachineFrameInfo.h"29#include "llvm/CodeGen/MachineInstrBuilder.h"30#include "llvm/CodeGen/MachineModuleInfo.h"31#include "llvm/CodeGen/MachineRegisterInfo.h"32#include "llvm/IR/DataLayout.h"33#include "llvm/IR/DerivedTypes.h"34#include "llvm/IR/Function.h"35#include "llvm/IR/GetElementPtrTypeIterator.h"36#include "llvm/IR/GlobalAlias.h"37#include "llvm/IR/GlobalVariable.h"38#include "llvm/IR/Instructions.h"39#include "llvm/IR/IntrinsicInst.h"40#include "llvm/IR/Operator.h"41#include "llvm/IR/PatternMatch.h"4243using namespace llvm;44using namespace PatternMatch;4546#define DEBUG_TYPE "wasm-fastisel"4748namespace {4950class WebAssemblyFastISel final : public FastISel {51// All possible address modes.52class Address {53public:54using BaseKind = enum { RegBase, FrameIndexBase };5556private:57BaseKind Kind = RegBase;58union {59unsigned Reg;60int FI;61} Base;6263// Whether the base has been determined yet64bool IsBaseSet = false;6566int64_t Offset = 0;6768const GlobalValue *GV = nullptr;6970public:71// Innocuous defaults for our address.72Address() { Base.Reg = 0; }73void setKind(BaseKind K) {74assert(!isSet() && "Can't change kind with non-zero base");75Kind = K;76}77BaseKind getKind() const { return Kind; }78bool isRegBase() const { return Kind == RegBase; }79bool isFIBase() const { return Kind == FrameIndexBase; }80void setReg(unsigned Reg) {81assert(isRegBase() && "Invalid base register access!");82assert(!IsBaseSet && "Base cannot be reset");83Base.Reg = Reg;84IsBaseSet = true;85}86unsigned getReg() const {87assert(isRegBase() && "Invalid base register access!");88return Base.Reg;89}90void setFI(unsigned FI) {91assert(isFIBase() && "Invalid base frame index access!");92assert(!IsBaseSet && "Base cannot be reset");93Base.FI = FI;94IsBaseSet = true;95}96unsigned getFI() const {97assert(isFIBase() && "Invalid base frame index access!");98return Base.FI;99}100101void setOffset(int64_t NewOffset) {102assert(NewOffset >= 0 && "Offsets must be non-negative");103Offset = NewOffset;104}105int64_t getOffset() const { return Offset; }106void setGlobalValue(const GlobalValue *G) { GV = G; }107const GlobalValue *getGlobalValue() const { return GV; }108bool isSet() const { return IsBaseSet; }109};110111/// Keep a pointer to the WebAssemblySubtarget around so that we can make the112/// right decision when generating code for different targets.113const WebAssemblySubtarget *Subtarget;114LLVMContext *Context;115116private:117// Utility helper routines118MVT::SimpleValueType getSimpleType(Type *Ty) {119EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);120return VT.isSimple() ? VT.getSimpleVT().SimpleTy121: MVT::INVALID_SIMPLE_VALUE_TYPE;122}123MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {124switch (VT) {125case MVT::i1:126case MVT::i8:127case MVT::i16:128return MVT::i32;129case MVT::i32:130case MVT::i64:131case MVT::f32:132case MVT::f64:133return VT;134case MVT::funcref:135case MVT::externref:136if (Subtarget->hasReferenceTypes())137return VT;138break;139case MVT::exnref:140if (Subtarget->hasReferenceTypes() && Subtarget->hasExceptionHandling())141return VT;142break;143case MVT::f16:144return MVT::f32;145case MVT::v16i8:146case MVT::v8i16:147case MVT::v4i32:148case MVT::v4f32:149case MVT::v2i64:150case MVT::v2f64:151if (Subtarget->hasSIMD128())152return VT;153break;154default:155break;156}157return MVT::INVALID_SIMPLE_VALUE_TYPE;158}159bool computeAddress(const Value *Obj, Address &Addr);160void materializeLoadStoreOperands(Address &Addr);161void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,162MachineMemOperand *MMO);163unsigned maskI1Value(unsigned Reg, const Value *V);164unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not);165unsigned zeroExtendToI32(unsigned Reg, const Value *V,166MVT::SimpleValueType From);167unsigned signExtendToI32(unsigned Reg, const Value *V,168MVT::SimpleValueType From);169unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,170MVT::SimpleValueType To);171unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,172MVT::SimpleValueType To);173unsigned getRegForUnsignedValue(const Value *V);174unsigned getRegForSignedValue(const Value *V);175unsigned getRegForPromotedValue(const Value *V, bool IsSigned);176unsigned notValue(unsigned Reg);177unsigned copyValue(unsigned Reg);178179// Backend specific FastISel code.180unsigned fastMaterializeAlloca(const AllocaInst *AI) override;181unsigned fastMaterializeConstant(const Constant *C) override;182bool fastLowerArguments() override;183184// Selection routines.185bool selectCall(const Instruction *I);186bool selectSelect(const Instruction *I);187bool selectTrunc(const Instruction *I);188bool selectZExt(const Instruction *I);189bool selectSExt(const Instruction *I);190bool selectICmp(const Instruction *I);191bool selectFCmp(const Instruction *I);192bool selectBitCast(const Instruction *I);193bool selectLoad(const Instruction *I);194bool selectStore(const Instruction *I);195bool selectBr(const Instruction *I);196bool selectRet(const Instruction *I);197bool selectUnreachable(const Instruction *I);198199public:200// Backend specific FastISel code.201WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,202const TargetLibraryInfo *LibInfo)203: FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {204Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();205Context = &FuncInfo.Fn->getContext();206}207208bool fastSelectInstruction(const Instruction *I) override;209210#include "WebAssemblyGenFastISel.inc"211};212213} // end anonymous namespace214215bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {216const User *U = nullptr;217unsigned Opcode = Instruction::UserOp1;218if (const auto *I = dyn_cast<Instruction>(Obj)) {219// Don't walk into other basic blocks unless the object is an alloca from220// another block, otherwise it may not have a virtual register assigned.221if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||222FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {223Opcode = I->getOpcode();224U = I;225}226} else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {227Opcode = C->getOpcode();228U = C;229}230231if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))232if (Ty->getAddressSpace() > 255)233// Fast instruction selection doesn't support the special234// address spaces.235return false;236237if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {238if (TLI.isPositionIndependent())239return false;240if (Addr.getGlobalValue())241return false;242if (GV->isThreadLocal())243return false;244Addr.setGlobalValue(GV);245return true;246}247248switch (Opcode) {249default:250break;251case Instruction::BitCast: {252// Look through bitcasts.253return computeAddress(U->getOperand(0), Addr);254}255case Instruction::IntToPtr: {256// Look past no-op inttoptrs.257if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==258TLI.getPointerTy(DL))259return computeAddress(U->getOperand(0), Addr);260break;261}262case Instruction::PtrToInt: {263// Look past no-op ptrtoints.264if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))265return computeAddress(U->getOperand(0), Addr);266break;267}268case Instruction::GetElementPtr: {269Address SavedAddr = Addr;270uint64_t TmpOffset = Addr.getOffset();271// Non-inbounds geps can wrap; wasm's offsets can't.272if (!cast<GEPOperator>(U)->isInBounds())273goto unsupported_gep;274// Iterate through the GEP folding the constants into offsets where275// we can.276for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);277GTI != E; ++GTI) {278const Value *Op = GTI.getOperand();279if (StructType *STy = GTI.getStructTypeOrNull()) {280const StructLayout *SL = DL.getStructLayout(STy);281unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();282TmpOffset += SL->getElementOffset(Idx);283} else {284uint64_t S = GTI.getSequentialElementStride(DL);285for (;;) {286if (const auto *CI = dyn_cast<ConstantInt>(Op)) {287// Constant-offset addressing.288TmpOffset += CI->getSExtValue() * S;289break;290}291if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {292// An unscaled add of a register. Set it as the new base.293Register Reg = getRegForValue(Op);294if (Reg == 0)295return false;296Addr.setReg(Reg);297break;298}299if (canFoldAddIntoGEP(U, Op)) {300// A compatible add with a constant operand. Fold the constant.301auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));302TmpOffset += CI->getSExtValue() * S;303// Iterate on the other operand.304Op = cast<AddOperator>(Op)->getOperand(0);305continue;306}307// Unsupported308goto unsupported_gep;309}310}311}312// Don't fold in negative offsets.313if (int64_t(TmpOffset) >= 0) {314// Try to grab the base operand now.315Addr.setOffset(TmpOffset);316if (computeAddress(U->getOperand(0), Addr))317return true;318}319// We failed, restore everything and try the other options.320Addr = SavedAddr;321unsupported_gep:322break;323}324case Instruction::Alloca: {325const auto *AI = cast<AllocaInst>(Obj);326DenseMap<const AllocaInst *, int>::iterator SI =327FuncInfo.StaticAllocaMap.find(AI);328if (SI != FuncInfo.StaticAllocaMap.end()) {329if (Addr.isSet()) {330return false;331}332Addr.setKind(Address::FrameIndexBase);333Addr.setFI(SI->second);334return true;335}336break;337}338case Instruction::Add: {339// Adds of constants are common and easy enough.340const Value *LHS = U->getOperand(0);341const Value *RHS = U->getOperand(1);342343if (isa<ConstantInt>(LHS))344std::swap(LHS, RHS);345346if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {347uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();348if (int64_t(TmpOffset) >= 0) {349Addr.setOffset(TmpOffset);350return computeAddress(LHS, Addr);351}352}353354Address Backup = Addr;355if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))356return true;357Addr = Backup;358359break;360}361case Instruction::Sub: {362// Subs of constants are common and easy enough.363const Value *LHS = U->getOperand(0);364const Value *RHS = U->getOperand(1);365366if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {367int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();368if (TmpOffset >= 0) {369Addr.setOffset(TmpOffset);370return computeAddress(LHS, Addr);371}372}373break;374}375}376if (Addr.isSet()) {377return false;378}379Register Reg = getRegForValue(Obj);380if (Reg == 0)381return false;382Addr.setReg(Reg);383return Addr.getReg() != 0;384}385386void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {387if (Addr.isRegBase()) {388unsigned Reg = Addr.getReg();389if (Reg == 0) {390Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass391: &WebAssembly::I32RegClass);392unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64393: WebAssembly::CONST_I32;394BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Reg)395.addImm(0);396Addr.setReg(Reg);397}398}399}400401void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,402const MachineInstrBuilder &MIB,403MachineMemOperand *MMO) {404// Set the alignment operand (this is rewritten in SetP2AlignOperands).405// TODO: Disable SetP2AlignOperands for FastISel and just do it here.406MIB.addImm(0);407408if (const GlobalValue *GV = Addr.getGlobalValue())409MIB.addGlobalAddress(GV, Addr.getOffset());410else411MIB.addImm(Addr.getOffset());412413if (Addr.isRegBase())414MIB.addReg(Addr.getReg());415else416MIB.addFrameIndex(Addr.getFI());417418MIB.addMemOperand(MMO);419}420421unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {422return zeroExtendToI32(Reg, V, MVT::i1);423}424425unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V,426const BasicBlock *BB,427bool &Not) {428if (const auto *ICmp = dyn_cast<ICmpInst>(V))429if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))430if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) &&431ICmp->getParent() == BB) {432Not = ICmp->isTrueWhenEqual();433return getRegForValue(ICmp->getOperand(0));434}435436Not = false;437Register Reg = getRegForValue(V);438if (Reg == 0)439return 0;440return maskI1Value(Reg, V);441}442443unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,444MVT::SimpleValueType From) {445if (Reg == 0)446return 0;447448switch (From) {449case MVT::i1:450// If the value is naturally an i1, we don't need to mask it. We only know451// if a value is naturally an i1 if it is definitely lowered by FastISel,452// not a DAG ISel fallback.453if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())454return copyValue(Reg);455break;456case MVT::i8:457case MVT::i16:458break;459case MVT::i32:460return copyValue(Reg);461default:462return 0;463}464465Register Imm = createResultReg(&WebAssembly::I32RegClass);466BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,467TII.get(WebAssembly::CONST_I32), Imm)468.addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));469470Register Result = createResultReg(&WebAssembly::I32RegClass);471BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,472TII.get(WebAssembly::AND_I32), Result)473.addReg(Reg)474.addReg(Imm);475476return Result;477}478479unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,480MVT::SimpleValueType From) {481if (Reg == 0)482return 0;483484switch (From) {485case MVT::i1:486case MVT::i8:487case MVT::i16:488break;489case MVT::i32:490return copyValue(Reg);491default:492return 0;493}494495Register Imm = createResultReg(&WebAssembly::I32RegClass);496BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,497TII.get(WebAssembly::CONST_I32), Imm)498.addImm(32 - MVT(From).getSizeInBits());499500Register Left = createResultReg(&WebAssembly::I32RegClass);501BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,502TII.get(WebAssembly::SHL_I32), Left)503.addReg(Reg)504.addReg(Imm);505506Register Right = createResultReg(&WebAssembly::I32RegClass);507BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,508TII.get(WebAssembly::SHR_S_I32), Right)509.addReg(Left)510.addReg(Imm);511512return Right;513}514515unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,516MVT::SimpleValueType From,517MVT::SimpleValueType To) {518if (To == MVT::i64) {519if (From == MVT::i64)520return copyValue(Reg);521522Reg = zeroExtendToI32(Reg, V, From);523524Register Result = createResultReg(&WebAssembly::I64RegClass);525BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,526TII.get(WebAssembly::I64_EXTEND_U_I32), Result)527.addReg(Reg);528return Result;529}530531if (To == MVT::i32)532return zeroExtendToI32(Reg, V, From);533534return 0;535}536537unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,538MVT::SimpleValueType From,539MVT::SimpleValueType To) {540if (To == MVT::i64) {541if (From == MVT::i64)542return copyValue(Reg);543544Reg = signExtendToI32(Reg, V, From);545546Register Result = createResultReg(&WebAssembly::I64RegClass);547BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,548TII.get(WebAssembly::I64_EXTEND_S_I32), Result)549.addReg(Reg);550return Result;551}552553if (To == MVT::i32)554return signExtendToI32(Reg, V, From);555556return 0;557}558559unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {560MVT::SimpleValueType From = getSimpleType(V->getType());561MVT::SimpleValueType To = getLegalType(From);562Register VReg = getRegForValue(V);563if (VReg == 0)564return 0;565if (From == To)566return VReg;567return zeroExtend(VReg, V, From, To);568}569570unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {571MVT::SimpleValueType From = getSimpleType(V->getType());572MVT::SimpleValueType To = getLegalType(From);573Register VReg = getRegForValue(V);574if (VReg == 0)575return 0;576if (From == To)577return VReg;578return signExtend(VReg, V, From, To);579}580581unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,582bool IsSigned) {583return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);584}585586unsigned WebAssemblyFastISel::notValue(unsigned Reg) {587assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);588589Register NotReg = createResultReg(&WebAssembly::I32RegClass);590BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,591TII.get(WebAssembly::EQZ_I32), NotReg)592.addReg(Reg);593return NotReg;594}595596unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {597Register ResultReg = createResultReg(MRI.getRegClass(Reg));598BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY),599ResultReg)600.addReg(Reg);601return ResultReg;602}603604unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {605DenseMap<const AllocaInst *, int>::iterator SI =606FuncInfo.StaticAllocaMap.find(AI);607608if (SI != FuncInfo.StaticAllocaMap.end()) {609Register ResultReg =610createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass611: &WebAssembly::I32RegClass);612unsigned Opc =613Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;614BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)615.addFrameIndex(SI->second);616return ResultReg;617}618619return 0;620}621622unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {623if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {624if (TLI.isPositionIndependent())625return 0;626if (GV->isThreadLocal())627return 0;628Register ResultReg =629createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass630: &WebAssembly::I32RegClass);631unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64632: WebAssembly::CONST_I32;633BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)634.addGlobalAddress(GV);635return ResultReg;636}637638// Let target-independent code handle it.639return 0;640}641642bool WebAssemblyFastISel::fastLowerArguments() {643if (!FuncInfo.CanLowerReturn)644return false;645646const Function *F = FuncInfo.Fn;647if (F->isVarArg())648return false;649650if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)651return false;652653unsigned I = 0;654for (auto const &Arg : F->args()) {655const AttributeList &Attrs = F->getAttributes();656if (Attrs.hasParamAttr(I, Attribute::ByVal) ||657Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||658Attrs.hasParamAttr(I, Attribute::SwiftError) ||659Attrs.hasParamAttr(I, Attribute::InAlloca) ||660Attrs.hasParamAttr(I, Attribute::Nest))661return false;662663Type *ArgTy = Arg.getType();664if (ArgTy->isStructTy() || ArgTy->isArrayTy())665return false;666if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())667return false;668669unsigned Opc;670const TargetRegisterClass *RC;671switch (getSimpleType(ArgTy)) {672case MVT::i1:673case MVT::i8:674case MVT::i16:675case MVT::i32:676Opc = WebAssembly::ARGUMENT_i32;677RC = &WebAssembly::I32RegClass;678break;679case MVT::i64:680Opc = WebAssembly::ARGUMENT_i64;681RC = &WebAssembly::I64RegClass;682break;683case MVT::f32:684Opc = WebAssembly::ARGUMENT_f32;685RC = &WebAssembly::F32RegClass;686break;687case MVT::f64:688Opc = WebAssembly::ARGUMENT_f64;689RC = &WebAssembly::F64RegClass;690break;691case MVT::v16i8:692Opc = WebAssembly::ARGUMENT_v16i8;693RC = &WebAssembly::V128RegClass;694break;695case MVT::v8i16:696Opc = WebAssembly::ARGUMENT_v8i16;697RC = &WebAssembly::V128RegClass;698break;699case MVT::v4i32:700Opc = WebAssembly::ARGUMENT_v4i32;701RC = &WebAssembly::V128RegClass;702break;703case MVT::v2i64:704Opc = WebAssembly::ARGUMENT_v2i64;705RC = &WebAssembly::V128RegClass;706break;707case MVT::v4f32:708Opc = WebAssembly::ARGUMENT_v4f32;709RC = &WebAssembly::V128RegClass;710break;711case MVT::v2f64:712Opc = WebAssembly::ARGUMENT_v2f64;713RC = &WebAssembly::V128RegClass;714break;715case MVT::funcref:716Opc = WebAssembly::ARGUMENT_funcref;717RC = &WebAssembly::FUNCREFRegClass;718break;719case MVT::externref:720Opc = WebAssembly::ARGUMENT_externref;721RC = &WebAssembly::EXTERNREFRegClass;722break;723case MVT::exnref:724Opc = WebAssembly::ARGUMENT_exnref;725RC = &WebAssembly::EXNREFRegClass;726break;727default:728return false;729}730Register ResultReg = createResultReg(RC);731BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)732.addImm(I);733updateValueMap(&Arg, ResultReg);734735++I;736}737738MRI.addLiveIn(WebAssembly::ARGUMENTS);739740auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();741for (auto const &Arg : F->args()) {742MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));743if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {744MFI->clearParamsAndResults();745return false;746}747MFI->addParam(ArgTy);748}749750if (!F->getReturnType()->isVoidTy()) {751MVT::SimpleValueType RetTy =752getLegalType(getSimpleType(F->getReturnType()));753if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {754MFI->clearParamsAndResults();755return false;756}757MFI->addResult(RetTy);758}759760return true;761}762763bool WebAssemblyFastISel::selectCall(const Instruction *I) {764const auto *Call = cast<CallInst>(I);765766// TODO: Support tail calls in FastISel767if (Call->isMustTailCall() || Call->isInlineAsm() ||768Call->getFunctionType()->isVarArg())769return false;770771Function *Func = Call->getCalledFunction();772if (Func && Func->isIntrinsic())773return false;774775if (Call->getCallingConv() == CallingConv::Swift)776return false;777778bool IsDirect = Func != nullptr;779if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))780return false;781782FunctionType *FuncTy = Call->getFunctionType();783unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;784bool IsVoid = FuncTy->getReturnType()->isVoidTy();785unsigned ResultReg;786if (!IsVoid) {787if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())788return false;789790MVT::SimpleValueType RetTy = getSimpleType(Call->getType());791switch (RetTy) {792case MVT::i1:793case MVT::i8:794case MVT::i16:795case MVT::i32:796ResultReg = createResultReg(&WebAssembly::I32RegClass);797break;798case MVT::i64:799ResultReg = createResultReg(&WebAssembly::I64RegClass);800break;801case MVT::f32:802ResultReg = createResultReg(&WebAssembly::F32RegClass);803break;804case MVT::f64:805ResultReg = createResultReg(&WebAssembly::F64RegClass);806break;807case MVT::v16i8:808ResultReg = createResultReg(&WebAssembly::V128RegClass);809break;810case MVT::v8i16:811ResultReg = createResultReg(&WebAssembly::V128RegClass);812break;813case MVT::v4i32:814ResultReg = createResultReg(&WebAssembly::V128RegClass);815break;816case MVT::v2i64:817ResultReg = createResultReg(&WebAssembly::V128RegClass);818break;819case MVT::v4f32:820ResultReg = createResultReg(&WebAssembly::V128RegClass);821break;822case MVT::v2f64:823ResultReg = createResultReg(&WebAssembly::V128RegClass);824break;825case MVT::funcref:826ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);827break;828case MVT::externref:829ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);830break;831case MVT::exnref:832ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);833break;834default:835return false;836}837}838839SmallVector<unsigned, 8> Args;840for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {841Value *V = Call->getArgOperand(I);842MVT::SimpleValueType ArgTy = getSimpleType(V->getType());843if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)844return false;845846const AttributeList &Attrs = Call->getAttributes();847if (Attrs.hasParamAttr(I, Attribute::ByVal) ||848Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||849Attrs.hasParamAttr(I, Attribute::SwiftError) ||850Attrs.hasParamAttr(I, Attribute::InAlloca) ||851Attrs.hasParamAttr(I, Attribute::Nest))852return false;853854unsigned Reg;855856if (Call->paramHasAttr(I, Attribute::SExt))857Reg = getRegForSignedValue(V);858else if (Call->paramHasAttr(I, Attribute::ZExt))859Reg = getRegForUnsignedValue(V);860else861Reg = getRegForValue(V);862863if (Reg == 0)864return false;865866Args.push_back(Reg);867}868869unsigned CalleeReg = 0;870if (!IsDirect) {871CalleeReg = getRegForValue(Call->getCalledOperand());872if (!CalleeReg)873return false;874}875876auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));877878if (!IsVoid)879MIB.addReg(ResultReg, RegState::Define);880881if (IsDirect) {882MIB.addGlobalAddress(Func);883} else {884// Placeholder for the type index.885MIB.addImm(0);886// The table into which this call_indirect indexes.887MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol(888MF->getContext(), Subtarget);889if (Subtarget->hasReferenceTypes()) {890MIB.addSym(Table);891} else {892// Otherwise for the MVP there is at most one table whose number is 0, but893// we can't write a table symbol or issue relocations. Instead we just894// ensure the table is live.895Table->setNoStrip();896MIB.addImm(0);897}898}899900for (unsigned ArgReg : Args)901MIB.addReg(ArgReg);902903if (!IsDirect)904MIB.addReg(CalleeReg);905906if (!IsVoid)907updateValueMap(Call, ResultReg);908return true;909}910911bool WebAssemblyFastISel::selectSelect(const Instruction *I) {912const auto *Select = cast<SelectInst>(I);913914bool Not;915unsigned CondReg =916getRegForI1Value(Select->getCondition(), I->getParent(), Not);917if (CondReg == 0)918return false;919920Register TrueReg = getRegForValue(Select->getTrueValue());921if (TrueReg == 0)922return false;923924Register FalseReg = getRegForValue(Select->getFalseValue());925if (FalseReg == 0)926return false;927928if (Not)929std::swap(TrueReg, FalseReg);930931unsigned Opc;932const TargetRegisterClass *RC;933switch (getSimpleType(Select->getType())) {934case MVT::i1:935case MVT::i8:936case MVT::i16:937case MVT::i32:938Opc = WebAssembly::SELECT_I32;939RC = &WebAssembly::I32RegClass;940break;941case MVT::i64:942Opc = WebAssembly::SELECT_I64;943RC = &WebAssembly::I64RegClass;944break;945case MVT::f32:946Opc = WebAssembly::SELECT_F32;947RC = &WebAssembly::F32RegClass;948break;949case MVT::f64:950Opc = WebAssembly::SELECT_F64;951RC = &WebAssembly::F64RegClass;952break;953case MVT::funcref:954Opc = WebAssembly::SELECT_FUNCREF;955RC = &WebAssembly::FUNCREFRegClass;956break;957case MVT::externref:958Opc = WebAssembly::SELECT_EXTERNREF;959RC = &WebAssembly::EXTERNREFRegClass;960break;961case MVT::exnref:962Opc = WebAssembly::SELECT_EXNREF;963RC = &WebAssembly::EXNREFRegClass;964break;965default:966return false;967}968969Register ResultReg = createResultReg(RC);970BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)971.addReg(TrueReg)972.addReg(FalseReg)973.addReg(CondReg);974975updateValueMap(Select, ResultReg);976return true;977}978979bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {980const auto *Trunc = cast<TruncInst>(I);981982Register Reg = getRegForValue(Trunc->getOperand(0));983if (Reg == 0)984return false;985986if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {987Register Result = createResultReg(&WebAssembly::I32RegClass);988BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,989TII.get(WebAssembly::I32_WRAP_I64), Result)990.addReg(Reg);991Reg = Result;992}993994updateValueMap(Trunc, Reg);995return true;996}997998bool WebAssemblyFastISel::selectZExt(const Instruction *I) {999const auto *ZExt = cast<ZExtInst>(I);10001001const Value *Op = ZExt->getOperand(0);1002MVT::SimpleValueType From = getSimpleType(Op->getType());1003MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));1004Register In = getRegForValue(Op);1005if (In == 0)1006return false;1007unsigned Reg = zeroExtend(In, Op, From, To);1008if (Reg == 0)1009return false;10101011updateValueMap(ZExt, Reg);1012return true;1013}10141015bool WebAssemblyFastISel::selectSExt(const Instruction *I) {1016const auto *SExt = cast<SExtInst>(I);10171018const Value *Op = SExt->getOperand(0);1019MVT::SimpleValueType From = getSimpleType(Op->getType());1020MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));1021Register In = getRegForValue(Op);1022if (In == 0)1023return false;1024unsigned Reg = signExtend(In, Op, From, To);1025if (Reg == 0)1026return false;10271028updateValueMap(SExt, Reg);1029return true;1030}10311032bool WebAssemblyFastISel::selectICmp(const Instruction *I) {1033const auto *ICmp = cast<ICmpInst>(I);10341035bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;1036unsigned Opc;1037bool IsSigned = false;1038switch (ICmp->getPredicate()) {1039case ICmpInst::ICMP_EQ:1040Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;1041break;1042case ICmpInst::ICMP_NE:1043Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;1044break;1045case ICmpInst::ICMP_UGT:1046Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;1047break;1048case ICmpInst::ICMP_UGE:1049Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;1050break;1051case ICmpInst::ICMP_ULT:1052Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;1053break;1054case ICmpInst::ICMP_ULE:1055Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;1056break;1057case ICmpInst::ICMP_SGT:1058Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;1059IsSigned = true;1060break;1061case ICmpInst::ICMP_SGE:1062Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;1063IsSigned = true;1064break;1065case ICmpInst::ICMP_SLT:1066Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;1067IsSigned = true;1068break;1069case ICmpInst::ICMP_SLE:1070Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;1071IsSigned = true;1072break;1073default:1074return false;1075}10761077unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);1078if (LHS == 0)1079return false;10801081unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);1082if (RHS == 0)1083return false;10841085Register ResultReg = createResultReg(&WebAssembly::I32RegClass);1086BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)1087.addReg(LHS)1088.addReg(RHS);1089updateValueMap(ICmp, ResultReg);1090return true;1091}10921093bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {1094const auto *FCmp = cast<FCmpInst>(I);10951096Register LHS = getRegForValue(FCmp->getOperand(0));1097if (LHS == 0)1098return false;10991100Register RHS = getRegForValue(FCmp->getOperand(1));1101if (RHS == 0)1102return false;11031104bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;1105unsigned Opc;1106bool Not = false;1107switch (FCmp->getPredicate()) {1108case FCmpInst::FCMP_OEQ:1109Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;1110break;1111case FCmpInst::FCMP_UNE:1112Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;1113break;1114case FCmpInst::FCMP_OGT:1115Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;1116break;1117case FCmpInst::FCMP_OGE:1118Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;1119break;1120case FCmpInst::FCMP_OLT:1121Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;1122break;1123case FCmpInst::FCMP_OLE:1124Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;1125break;1126case FCmpInst::FCMP_UGT:1127Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;1128Not = true;1129break;1130case FCmpInst::FCMP_UGE:1131Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;1132Not = true;1133break;1134case FCmpInst::FCMP_ULT:1135Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;1136Not = true;1137break;1138case FCmpInst::FCMP_ULE:1139Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;1140Not = true;1141break;1142default:1143return false;1144}11451146Register ResultReg = createResultReg(&WebAssembly::I32RegClass);1147BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)1148.addReg(LHS)1149.addReg(RHS);11501151if (Not)1152ResultReg = notValue(ResultReg);11531154updateValueMap(FCmp, ResultReg);1155return true;1156}11571158bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {1159// Target-independent code can handle this, except it doesn't set the dead1160// flag on the ARGUMENTS clobber, so we have to do that manually in order1161// to satisfy code that expects this of isBitcast() instructions.1162EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());1163EVT RetVT = TLI.getValueType(DL, I->getType());1164if (!VT.isSimple() || !RetVT.isSimple())1165return false;11661167Register In = getRegForValue(I->getOperand(0));1168if (In == 0)1169return false;11701171if (VT == RetVT) {1172// No-op bitcast.1173updateValueMap(I, In);1174return true;1175}11761177Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),1178In);1179if (!Reg)1180return false;1181MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;1182--Iter;1183assert(Iter->isBitcast());1184Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);1185updateValueMap(I, Reg);1186return true;1187}11881189bool WebAssemblyFastISel::selectLoad(const Instruction *I) {1190const auto *Load = cast<LoadInst>(I);1191if (Load->isAtomic())1192return false;1193if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))1194return false;1195if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())1196return false;11971198Address Addr;1199if (!computeAddress(Load->getPointerOperand(), Addr))1200return false;12011202// TODO: Fold a following sign-/zero-extend into the load instruction.12031204unsigned Opc;1205const TargetRegisterClass *RC;1206bool A64 = Subtarget->hasAddr64();1207switch (getSimpleType(Load->getType())) {1208case MVT::i1:1209case MVT::i8:1210Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;1211RC = &WebAssembly::I32RegClass;1212break;1213case MVT::i16:1214Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;1215RC = &WebAssembly::I32RegClass;1216break;1217case MVT::i32:1218Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;1219RC = &WebAssembly::I32RegClass;1220break;1221case MVT::i64:1222Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;1223RC = &WebAssembly::I64RegClass;1224break;1225case MVT::f32:1226Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;1227RC = &WebAssembly::F32RegClass;1228break;1229case MVT::f64:1230Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;1231RC = &WebAssembly::F64RegClass;1232break;1233default:1234return false;1235}12361237materializeLoadStoreOperands(Addr);12381239Register ResultReg = createResultReg(RC);1240auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc),1241ResultReg);12421243addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));12441245updateValueMap(Load, ResultReg);1246return true;1247}12481249bool WebAssemblyFastISel::selectStore(const Instruction *I) {1250const auto *Store = cast<StoreInst>(I);1251if (Store->isAtomic())1252return false;1253if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))1254return false;1255if (!Subtarget->hasSIMD128() &&1256Store->getValueOperand()->getType()->isVectorTy())1257return false;12581259Address Addr;1260if (!computeAddress(Store->getPointerOperand(), Addr))1261return false;12621263unsigned Opc;1264bool VTIsi1 = false;1265bool A64 = Subtarget->hasAddr64();1266switch (getSimpleType(Store->getValueOperand()->getType())) {1267case MVT::i1:1268VTIsi1 = true;1269[[fallthrough]];1270case MVT::i8:1271Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;1272break;1273case MVT::i16:1274Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;1275break;1276case MVT::i32:1277Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;1278break;1279case MVT::i64:1280Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;1281break;1282case MVT::f32:1283Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;1284break;1285case MVT::f64:1286Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;1287break;1288default:1289return false;1290}12911292materializeLoadStoreOperands(Addr);12931294Register ValueReg = getRegForValue(Store->getValueOperand());1295if (ValueReg == 0)1296return false;1297if (VTIsi1)1298ValueReg = maskI1Value(ValueReg, Store->getValueOperand());12991300auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));13011302addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));13031304MIB.addReg(ValueReg);1305return true;1306}13071308bool WebAssemblyFastISel::selectBr(const Instruction *I) {1309const auto *Br = cast<BranchInst>(I);1310if (Br->isUnconditional()) {1311MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];1312fastEmitBranch(MSucc, Br->getDebugLoc());1313return true;1314}13151316MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];1317MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];13181319bool Not;1320unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);1321if (CondReg == 0)1322return false;13231324unsigned Opc = WebAssembly::BR_IF;1325if (Not)1326Opc = WebAssembly::BR_UNLESS;13271328BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))1329.addMBB(TBB)1330.addReg(CondReg);13311332finishCondBranch(Br->getParent(), TBB, FBB);1333return true;1334}13351336bool WebAssemblyFastISel::selectRet(const Instruction *I) {1337if (!FuncInfo.CanLowerReturn)1338return false;13391340const auto *Ret = cast<ReturnInst>(I);13411342if (Ret->getNumOperands() == 0) {1343BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,1344TII.get(WebAssembly::RETURN));1345return true;1346}13471348// TODO: support multiple return in FastISel1349if (Ret->getNumOperands() > 1)1350return false;13511352Value *RV = Ret->getOperand(0);1353if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())1354return false;13551356switch (getSimpleType(RV->getType())) {1357case MVT::i1:1358case MVT::i8:1359case MVT::i16:1360case MVT::i32:1361case MVT::i64:1362case MVT::f32:1363case MVT::f64:1364case MVT::v16i8:1365case MVT::v8i16:1366case MVT::v4i32:1367case MVT::v2i64:1368case MVT::v4f32:1369case MVT::v2f64:1370case MVT::funcref:1371case MVT::externref:1372case MVT::exnref:1373break;1374default:1375return false;1376}13771378unsigned Reg;1379if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))1380Reg = getRegForSignedValue(RV);1381else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))1382Reg = getRegForUnsignedValue(RV);1383else1384Reg = getRegForValue(RV);13851386if (Reg == 0)1387return false;13881389BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,1390TII.get(WebAssembly::RETURN))1391.addReg(Reg);1392return true;1393}13941395bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {1396BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,1397TII.get(WebAssembly::UNREACHABLE));1398return true;1399}14001401bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {1402switch (I->getOpcode()) {1403case Instruction::Call:1404if (selectCall(I))1405return true;1406break;1407case Instruction::Select:1408return selectSelect(I);1409case Instruction::Trunc:1410return selectTrunc(I);1411case Instruction::ZExt:1412return selectZExt(I);1413case Instruction::SExt:1414return selectSExt(I);1415case Instruction::ICmp:1416return selectICmp(I);1417case Instruction::FCmp:1418return selectFCmp(I);1419case Instruction::BitCast:1420return selectBitCast(I);1421case Instruction::Load:1422return selectLoad(I);1423case Instruction::Store:1424return selectStore(I);1425case Instruction::Br:1426return selectBr(I);1427case Instruction::Ret:1428return selectRet(I);1429case Instruction::Unreachable:1430return selectUnreachable(I);1431default:1432break;1433}14341435// Fall back to target-independent instruction selection.1436return selectOperator(I, I->getOpcode());1437}14381439FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,1440const TargetLibraryInfo *LibInfo) {1441return new WebAssemblyFastISel(FuncInfo, LibInfo);1442}144314441445