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.
Address()730b57cec5SDimitry Andric Address() { Base.Reg = 0; }
setKind(BaseKind K)740b57cec5SDimitry Andric void setKind(BaseKind K) {
750b57cec5SDimitry Andric assert(!isSet() && "Can't change kind with non-zero base");
760b57cec5SDimitry Andric Kind = K;
770b57cec5SDimitry Andric }
getKind() const780b57cec5SDimitry Andric BaseKind getKind() const { return Kind; }
isRegBase() const790b57cec5SDimitry Andric bool isRegBase() const { return Kind == RegBase; }
isFIBase() const800b57cec5SDimitry Andric bool isFIBase() const { return Kind == FrameIndexBase; }
setReg(unsigned Reg)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 }
getReg() const870b57cec5SDimitry Andric unsigned getReg() const {
880b57cec5SDimitry Andric assert(isRegBase() && "Invalid base register access!");
890b57cec5SDimitry Andric return Base.Reg;
900b57cec5SDimitry Andric }
setFI(unsigned FI)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 }
getFI() const970b57cec5SDimitry Andric unsigned getFI() const {
980b57cec5SDimitry Andric assert(isFIBase() && "Invalid base frame index access!");
990b57cec5SDimitry Andric return Base.FI;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric
setOffset(int64_t NewOffset)1020b57cec5SDimitry Andric void setOffset(int64_t NewOffset) {
1030b57cec5SDimitry Andric assert(NewOffset >= 0 && "Offsets must be non-negative");
1040b57cec5SDimitry Andric Offset = NewOffset;
1050b57cec5SDimitry Andric }
getOffset() const1060b57cec5SDimitry Andric int64_t getOffset() const { return Offset; }
setGlobalValue(const GlobalValue * G)1070b57cec5SDimitry Andric void setGlobalValue(const GlobalValue *G) { GV = G; }
getGlobalValue() const1080b57cec5SDimitry Andric const GlobalValue *getGlobalValue() const { return GV; }
isSet() const109eaeb601bSDimitry 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
getSimpleType(Type * Ty)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 }
getLegalType(MVT::SimpleValueType VT)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.
WebAssemblyFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)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
computeAddress(const Value * Obj,Address & Addr)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
materializeLoadStoreOperands(Address & Addr)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
addLoadStoreOperands(const Address & Addr,const MachineInstrBuilder & MIB,MachineMemOperand * MMO)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
maskI1Value(unsigned Reg,const Value * V)4220b57cec5SDimitry Andric unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
4230b57cec5SDimitry Andric return zeroExtendToI32(Reg, V, MVT::i1);
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric
getRegForI1Value(const Value * V,const BasicBlock * BB,bool & Not)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
zeroExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)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
signExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)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
zeroExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)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
signExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)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
getRegForUnsignedValue(const Value * V)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
getRegForSignedValue(const Value * V)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
getRegForPromotedValue(const Value * V,bool IsSigned)5820b57cec5SDimitry Andric unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
5830b57cec5SDimitry Andric bool IsSigned) {
5840b57cec5SDimitry Andric return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
5850b57cec5SDimitry Andric }
5860b57cec5SDimitry Andric
notValue(unsigned Reg)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
copyValue(unsigned Reg)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
fastMaterializeAlloca(const AllocaInst * AI)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
fastMaterializeConstant(const Constant * C)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
fastLowerArguments()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
selectCall(const Instruction * I)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
selectSelect(const Instruction * I)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
selectTrunc(const Instruction * I)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
selectZExt(const Instruction * I)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
selectSExt(const Instruction * I)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
selectICmp(const Instruction * I)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
selectFCmp(const Instruction * I)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
selectBitCast(const Instruction * I)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
selectLoad(const Instruction * I)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
selectStore(const Instruction * I)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
selectBr(const Instruction * I)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
selectRet(const Instruction * I)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
selectUnreachable(const Instruction * I)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
fastSelectInstruction(const Instruction * I)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
createFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)14400b57cec5SDimitry Andric FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
14410b57cec5SDimitry Andric const TargetLibraryInfo *LibInfo) {
14420b57cec5SDimitry Andric return new WebAssemblyFastISel(FuncInfo, LibInfo);
14430b57cec5SDimitry Andric }
1444