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