17b63484bSDan Gohman //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
27b63484bSDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67b63484bSDan Gohman //
77b63484bSDan Gohman //===----------------------------------------------------------------------===//
87b63484bSDan Gohman ///
97b63484bSDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file defines the WebAssembly-specific support for the FastISel
117b63484bSDan Gohman /// class. Some of the target-specific code is generated by tablegen in the file
127b63484bSDan Gohman /// WebAssemblyGenFastISel.inc, which is #included here.
137b63484bSDan Gohman ///
1433e694a8SDan Gohman /// TODO: kill flags
1533e694a8SDan Gohman ///
167b63484bSDan Gohman //===----------------------------------------------------------------------===//
177b63484bSDan Gohman
187b63484bSDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19*864767abSPaulo Matos #include "Utils/WebAssemblyTypeUtilities.h"
200b2bc69bSHeejin Ahn #include "Utils/WebAssemblyUtilities.h"
216bda14b3SChandler Carruth #include "WebAssembly.h"
2233e694a8SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
237b63484bSDan Gohman #include "WebAssemblySubtarget.h"
247b63484bSDan Gohman #include "WebAssemblyTargetMachine.h"
257b63484bSDan Gohman #include "llvm/Analysis/BranchProbabilityInfo.h"
267b63484bSDan Gohman #include "llvm/CodeGen/FastISel.h"
277b63484bSDan Gohman #include "llvm/CodeGen/FunctionLoweringInfo.h"
287b63484bSDan Gohman #include "llvm/CodeGen/MachineConstantPool.h"
297b63484bSDan Gohman #include "llvm/CodeGen/MachineFrameInfo.h"
307b63484bSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h"
319ad83fd6SAndy Wingo #include "llvm/CodeGen/MachineModuleInfo.h"
327b63484bSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
337b63484bSDan Gohman #include "llvm/IR/DataLayout.h"
347b63484bSDan Gohman #include "llvm/IR/DerivedTypes.h"
357b63484bSDan Gohman #include "llvm/IR/Function.h"
367b63484bSDan Gohman #include "llvm/IR/GetElementPtrTypeIterator.h"
377b63484bSDan Gohman #include "llvm/IR/GlobalAlias.h"
387b63484bSDan Gohman #include "llvm/IR/GlobalVariable.h"
397b63484bSDan Gohman #include "llvm/IR/Instructions.h"
407b63484bSDan Gohman #include "llvm/IR/IntrinsicInst.h"
417b63484bSDan Gohman #include "llvm/IR/Operator.h"
4247a52a05SSanjay Patel #include "llvm/IR/PatternMatch.h"
4347a52a05SSanjay Patel
447b63484bSDan Gohman using namespace llvm;
4547a52a05SSanjay Patel using namespace PatternMatch;
467b63484bSDan Gohman
477b63484bSDan Gohman #define DEBUG_TYPE "wasm-fastisel"
487b63484bSDan Gohman
497b63484bSDan Gohman namespace {
507b63484bSDan Gohman
517b63484bSDan Gohman class WebAssemblyFastISel final : public FastISel {
522e64438aSDan Gohman // All possible address modes.
532e64438aSDan Gohman class Address {
542e64438aSDan Gohman public:
5518c56a07SHeejin Ahn using BaseKind = enum { RegBase, FrameIndexBase };
562e64438aSDan Gohman
572e64438aSDan Gohman private:
5818c56a07SHeejin Ahn BaseKind Kind = RegBase;
592e64438aSDan Gohman union {
602e64438aSDan Gohman unsigned Reg;
612e64438aSDan Gohman int FI;
622e64438aSDan Gohman } Base;
632e64438aSDan Gohman
64cc612c29SThomas Lively // Whether the base has been determined yet
65cc612c29SThomas Lively bool IsBaseSet = false;
66cc612c29SThomas Lively
6718c56a07SHeejin Ahn int64_t Offset = 0;
682e64438aSDan Gohman
6918c56a07SHeejin Ahn const GlobalValue *GV = nullptr;
702e64438aSDan Gohman
712e64438aSDan Gohman public:
722e64438aSDan Gohman // Innocuous defaults for our address.
Address()7318c56a07SHeejin Ahn Address() { Base.Reg = 0; }
setKind(BaseKind K)74a31ec61cSJacob Gravelle void setKind(BaseKind K) {
75a31ec61cSJacob Gravelle assert(!isSet() && "Can't change kind with non-zero base");
76a31ec61cSJacob Gravelle Kind = K;
77a31ec61cSJacob Gravelle }
getKind() const782e64438aSDan Gohman BaseKind getKind() const { return Kind; }
isRegBase() const792e64438aSDan Gohman bool isRegBase() const { return Kind == RegBase; }
isFIBase() const802e64438aSDan Gohman bool isFIBase() const { return Kind == FrameIndexBase; }
setReg(unsigned Reg)812e64438aSDan Gohman void setReg(unsigned Reg) {
822e64438aSDan Gohman assert(isRegBase() && "Invalid base register access!");
83cc612c29SThomas Lively assert(!IsBaseSet && "Base cannot be reset");
842e64438aSDan Gohman Base.Reg = Reg;
85cc612c29SThomas Lively IsBaseSet = true;
862e64438aSDan Gohman }
getReg() const872e64438aSDan Gohman unsigned getReg() const {
882e64438aSDan Gohman assert(isRegBase() && "Invalid base register access!");
892e64438aSDan Gohman return Base.Reg;
902e64438aSDan Gohman }
setFI(unsigned FI)912e64438aSDan Gohman void setFI(unsigned FI) {
922e64438aSDan Gohman assert(isFIBase() && "Invalid base frame index access!");
93cc612c29SThomas Lively assert(!IsBaseSet && "Base cannot be reset");
942e64438aSDan Gohman Base.FI = FI;
95cc612c29SThomas Lively IsBaseSet = true;
962e64438aSDan Gohman }
getFI() const972e64438aSDan Gohman unsigned getFI() const {
982e64438aSDan Gohman assert(isFIBase() && "Invalid base frame index access!");
992e64438aSDan Gohman return Base.FI;
1002e64438aSDan Gohman }
1012e64438aSDan Gohman
setOffset(int64_t NewOffset)10218c56a07SHeejin Ahn void setOffset(int64_t NewOffset) {
10318c56a07SHeejin Ahn assert(NewOffset >= 0 && "Offsets must be non-negative");
10418c56a07SHeejin Ahn Offset = NewOffset;
105728926acSDan Gohman }
getOffset() const1062e64438aSDan Gohman int64_t getOffset() const { return Offset; }
setGlobalValue(const GlobalValue * G)1072e64438aSDan Gohman void setGlobalValue(const GlobalValue *G) { GV = G; }
getGlobalValue() const1082e64438aSDan Gohman const GlobalValue *getGlobalValue() const { return GV; }
isSet() const109cc612c29SThomas Lively bool isSet() const { return IsBaseSet; }
1102e64438aSDan Gohman };
1112e64438aSDan Gohman
1127b63484bSDan Gohman /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
1137b63484bSDan Gohman /// right decision when generating code for different targets.
1147b63484bSDan Gohman const WebAssemblySubtarget *Subtarget;
1157b63484bSDan Gohman LLVMContext *Context;
1167b63484bSDan Gohman
1177b63484bSDan Gohman private:
1182e64438aSDan Gohman // Utility helper routines
getSimpleType(Type * Ty)1193a5ce733SDan Gohman MVT::SimpleValueType getSimpleType(Type *Ty) {
12049a3ad21SRui Ueyama EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
121f208f631SHeejin Ahn return VT.isSimple() ? VT.getSimpleVT().SimpleTy
122f208f631SHeejin Ahn : MVT::INVALID_SIMPLE_VALUE_TYPE;
1233a5ce733SDan Gohman }
getLegalType(MVT::SimpleValueType VT)1243a5ce733SDan Gohman MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
1253a5ce733SDan Gohman switch (VT) {
1263a5ce733SDan Gohman case MVT::i1:
1273a5ce733SDan Gohman case MVT::i8:
1283a5ce733SDan Gohman case MVT::i16:
1293a5ce733SDan Gohman return MVT::i32;
13033e694a8SDan Gohman case MVT::i32:
1313a5ce733SDan Gohman case MVT::i64:
13233e694a8SDan Gohman case MVT::f32:
13333e694a8SDan Gohman case MVT::f64:
13446667a10SPaulo Matos return VT;
13569e2797eSPaulo Matos case MVT::funcref:
13669e2797eSPaulo Matos case MVT::externref:
13746667a10SPaulo Matos if (Subtarget->hasReferenceTypes())
13833e694a8SDan Gohman return VT;
13946667a10SPaulo Matos break;
1406999c4fdSDan Gohman case MVT::f16:
1416999c4fdSDan Gohman return MVT::f32;
14239bf39f3SDerek Schuff case MVT::v16i8:
14339bf39f3SDerek Schuff case MVT::v8i16:
14439bf39f3SDerek Schuff case MVT::v4i32:
14539bf39f3SDerek Schuff case MVT::v4f32:
146b6dac89cSThomas Lively case MVT::v2i64:
147b6dac89cSThomas Lively case MVT::v2f64:
1488638c897SThomas Lively if (Subtarget->hasSIMD128())
149b6dac89cSThomas Lively return VT;
150b6dac89cSThomas Lively break;
1513a5ce733SDan Gohman default:
1523a5ce733SDan Gohman break;
1533a5ce733SDan Gohman }
1543a5ce733SDan Gohman return MVT::INVALID_SIMPLE_VALUE_TYPE;
1553a5ce733SDan Gohman }
1562e64438aSDan Gohman bool computeAddress(const Value *Obj, Address &Addr);
1579da81421SSam Clegg void materializeLoadStoreOperands(Address &Addr);
1582e64438aSDan Gohman void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
1592e64438aSDan Gohman MachineMemOperand *MMO);
1603a5ce733SDan Gohman unsigned maskI1Value(unsigned Reg, const Value *V);
16116086d47SNikita Popov unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not);
1623a5ce733SDan Gohman unsigned zeroExtendToI32(unsigned Reg, const Value *V,
1633a5ce733SDan Gohman MVT::SimpleValueType From);
1643a5ce733SDan Gohman unsigned signExtendToI32(unsigned Reg, const Value *V,
1653a5ce733SDan Gohman MVT::SimpleValueType From);
166f208f631SHeejin Ahn unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
1673a5ce733SDan Gohman MVT::SimpleValueType To);
168f208f631SHeejin Ahn unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
1693a5ce733SDan Gohman MVT::SimpleValueType To);
1703a5ce733SDan Gohman unsigned getRegForUnsignedValue(const Value *V);
1713a5ce733SDan Gohman unsigned getRegForSignedValue(const Value *V);
1723a5ce733SDan Gohman unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
1733a5ce733SDan Gohman unsigned notValue(unsigned Reg);
17433e694a8SDan Gohman unsigned copyValue(unsigned Reg);
1752e64438aSDan Gohman
1762e64438aSDan Gohman // Backend specific FastISel code.
1772e64438aSDan Gohman unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
1782e64438aSDan Gohman unsigned fastMaterializeConstant(const Constant *C) override;
17933e694a8SDan Gohman bool fastLowerArguments() override;
1802e64438aSDan Gohman
1812e64438aSDan Gohman // Selection routines.
18233e694a8SDan Gohman bool selectCall(const Instruction *I);
18333e694a8SDan Gohman bool selectSelect(const Instruction *I);
18433e694a8SDan Gohman bool selectTrunc(const Instruction *I);
1853a5ce733SDan Gohman bool selectZExt(const Instruction *I);
1863a5ce733SDan Gohman bool selectSExt(const Instruction *I);
1873a5ce733SDan Gohman bool selectICmp(const Instruction *I);
1883a5ce733SDan Gohman bool selectFCmp(const Instruction *I);
1892e64438aSDan Gohman bool selectBitCast(const Instruction *I);
1902e64438aSDan Gohman bool selectLoad(const Instruction *I);
1912e64438aSDan Gohman bool selectStore(const Instruction *I);
1922e64438aSDan Gohman bool selectBr(const Instruction *I);
1932e64438aSDan Gohman bool selectRet(const Instruction *I);
1942e64438aSDan Gohman bool selectUnreachable(const Instruction *I);
1952e64438aSDan Gohman
1967b63484bSDan Gohman public:
1977b63484bSDan Gohman // Backend specific FastISel code.
WebAssemblyFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)1987b63484bSDan Gohman WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
1997b63484bSDan Gohman const TargetLibraryInfo *LibInfo)
2007b63484bSDan Gohman : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
2017b63484bSDan Gohman Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
2027b63484bSDan Gohman Context = &FuncInfo.Fn->getContext();
2037b63484bSDan Gohman }
2047b63484bSDan Gohman
2057b63484bSDan Gohman bool fastSelectInstruction(const Instruction *I) override;
2067b63484bSDan Gohman
2077b63484bSDan Gohman #include "WebAssemblyGenFastISel.inc"
2087b63484bSDan Gohman };
2097b63484bSDan Gohman
2107b63484bSDan Gohman } // end anonymous namespace
2117b63484bSDan Gohman
computeAddress(const Value * Obj,Address & Addr)2122e64438aSDan Gohman bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
2132e64438aSDan Gohman const User *U = nullptr;
2142e64438aSDan Gohman unsigned Opcode = Instruction::UserOp1;
21518c56a07SHeejin Ahn if (const auto *I = dyn_cast<Instruction>(Obj)) {
2162e64438aSDan Gohman // Don't walk into other basic blocks unless the object is an alloca from
2172e64438aSDan Gohman // another block, otherwise it may not have a virtual register assigned.
2182e64438aSDan Gohman if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
2192e64438aSDan Gohman FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
2202e64438aSDan Gohman Opcode = I->getOpcode();
2212e64438aSDan Gohman U = I;
2222e64438aSDan Gohman }
22318c56a07SHeejin Ahn } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
2242e64438aSDan Gohman Opcode = C->getOpcode();
2252e64438aSDan Gohman U = C;
2262e64438aSDan Gohman }
2272e64438aSDan Gohman
2282e64438aSDan Gohman if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
2292e64438aSDan Gohman if (Ty->getAddressSpace() > 255)
2302e64438aSDan Gohman // Fast instruction selection doesn't support the special
2312e64438aSDan Gohman // address spaces.
2322e64438aSDan Gohman return false;
2332e64438aSDan Gohman
23418c56a07SHeejin Ahn if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
2359da81421SSam Clegg if (TLI.isPositionIndependent())
2369da81421SSam Clegg return false;
2372e64438aSDan Gohman if (Addr.getGlobalValue())
2382e64438aSDan Gohman return false;
23942bba4b8SGuanzhong Chen if (GV->isThreadLocal())
24042bba4b8SGuanzhong Chen return false;
2412e64438aSDan Gohman Addr.setGlobalValue(GV);
2422e64438aSDan Gohman return true;
2432e64438aSDan Gohman }
2442e64438aSDan Gohman
2452e64438aSDan Gohman switch (Opcode) {
2467b63484bSDan Gohman default:
2477b63484bSDan Gohman break;
2482e64438aSDan Gohman case Instruction::BitCast: {
2492e64438aSDan Gohman // Look through bitcasts.
2502e64438aSDan Gohman return computeAddress(U->getOperand(0), Addr);
2512e64438aSDan Gohman }
2522e64438aSDan Gohman case Instruction::IntToPtr: {
2532e64438aSDan Gohman // Look past no-op inttoptrs.
2542e64438aSDan Gohman if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
2552e64438aSDan Gohman TLI.getPointerTy(DL))
2562e64438aSDan Gohman return computeAddress(U->getOperand(0), Addr);
2572e64438aSDan Gohman break;
2582e64438aSDan Gohman }
2592e64438aSDan Gohman case Instruction::PtrToInt: {
2602e64438aSDan Gohman // Look past no-op ptrtoints.
2612e64438aSDan Gohman if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
2622e64438aSDan Gohman return computeAddress(U->getOperand(0), Addr);
2632e64438aSDan Gohman break;
2642e64438aSDan Gohman }
2652e64438aSDan Gohman case Instruction::GetElementPtr: {
2662e64438aSDan Gohman Address SavedAddr = Addr;
2672e64438aSDan Gohman uint64_t TmpOffset = Addr.getOffset();
268728926acSDan Gohman // Non-inbounds geps can wrap; wasm's offsets can't.
269728926acSDan Gohman if (!cast<GEPOperator>(U)->isInBounds())
270728926acSDan Gohman goto unsupported_gep;
2712e64438aSDan Gohman // Iterate through the GEP folding the constants into offsets where
2722e64438aSDan Gohman // we can.
2732e64438aSDan Gohman for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
2742e64438aSDan Gohman GTI != E; ++GTI) {
2752e64438aSDan Gohman const Value *Op = GTI.getOperand();
276ab85225bSPeter Collingbourne if (StructType *STy = GTI.getStructTypeOrNull()) {
2772e64438aSDan Gohman const StructLayout *SL = DL.getStructLayout(STy);
2782e64438aSDan Gohman unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
2792e64438aSDan Gohman TmpOffset += SL->getElementOffset(Idx);
2802e64438aSDan Gohman } else {
2812e64438aSDan Gohman uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
2822e64438aSDan Gohman for (;;) {
28318c56a07SHeejin Ahn if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
2842e64438aSDan Gohman // Constant-offset addressing.
2852e64438aSDan Gohman TmpOffset += CI->getSExtValue() * S;
2862e64438aSDan Gohman break;
2872e64438aSDan Gohman }
28833e694a8SDan Gohman if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
28933e694a8SDan Gohman // An unscaled add of a register. Set it as the new base.
290d6b07348SJim Lin Register Reg = getRegForValue(Op);
2913ff73cfbSDan Gohman if (Reg == 0)
2923ff73cfbSDan Gohman return false;
2933ff73cfbSDan Gohman Addr.setReg(Reg);
29433e694a8SDan Gohman break;
29533e694a8SDan Gohman }
2962e64438aSDan Gohman if (canFoldAddIntoGEP(U, Op)) {
2972e64438aSDan Gohman // A compatible add with a constant operand. Fold the constant.
29818c56a07SHeejin Ahn auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
2992e64438aSDan Gohman TmpOffset += CI->getSExtValue() * S;
3002e64438aSDan Gohman // Iterate on the other operand.
3012e64438aSDan Gohman Op = cast<AddOperator>(Op)->getOperand(0);
3022e64438aSDan Gohman continue;
3032e64438aSDan Gohman }
3042e64438aSDan Gohman // Unsupported
3052e64438aSDan Gohman goto unsupported_gep;
3062e64438aSDan Gohman }
3072e64438aSDan Gohman }
3082e64438aSDan Gohman }
309728926acSDan Gohman // Don't fold in negative offsets.
310728926acSDan Gohman if (int64_t(TmpOffset) >= 0) {
3112e64438aSDan Gohman // Try to grab the base operand now.
3122e64438aSDan Gohman Addr.setOffset(TmpOffset);
3132e64438aSDan Gohman if (computeAddress(U->getOperand(0), Addr))
3142e64438aSDan Gohman return true;
315728926acSDan Gohman }
3162e64438aSDan Gohman // We failed, restore everything and try the other options.
3172e64438aSDan Gohman Addr = SavedAddr;
3182e64438aSDan Gohman unsupported_gep:
3192e64438aSDan Gohman break;
3202e64438aSDan Gohman }
3212e64438aSDan Gohman case Instruction::Alloca: {
32218c56a07SHeejin Ahn const auto *AI = cast<AllocaInst>(Obj);
3232e64438aSDan Gohman DenseMap<const AllocaInst *, int>::iterator SI =
3242e64438aSDan Gohman FuncInfo.StaticAllocaMap.find(AI);
3252e64438aSDan Gohman if (SI != FuncInfo.StaticAllocaMap.end()) {
326a31ec61cSJacob Gravelle if (Addr.isSet()) {
327a31ec61cSJacob Gravelle return false;
328a31ec61cSJacob Gravelle }
3292e64438aSDan Gohman Addr.setKind(Address::FrameIndexBase);
3302e64438aSDan Gohman Addr.setFI(SI->second);
3312e64438aSDan Gohman return true;
3322e64438aSDan Gohman }
3332e64438aSDan Gohman break;
3342e64438aSDan Gohman }
3352e64438aSDan Gohman case Instruction::Add: {
3362e64438aSDan Gohman // Adds of constants are common and easy enough.
3372e64438aSDan Gohman const Value *LHS = U->getOperand(0);
3382e64438aSDan Gohman const Value *RHS = U->getOperand(1);
3392e64438aSDan Gohman
3402e64438aSDan Gohman if (isa<ConstantInt>(LHS))
3412e64438aSDan Gohman std::swap(LHS, RHS);
3422e64438aSDan Gohman
34318c56a07SHeejin Ahn if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
344728926acSDan Gohman uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
345728926acSDan Gohman if (int64_t(TmpOffset) >= 0) {
346728926acSDan Gohman Addr.setOffset(TmpOffset);
3472e64438aSDan Gohman return computeAddress(LHS, Addr);
3482e64438aSDan Gohman }
349728926acSDan Gohman }
3502e64438aSDan Gohman
3512e64438aSDan Gohman Address Backup = Addr;
3522e64438aSDan Gohman if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
3532e64438aSDan Gohman return true;
3542e64438aSDan Gohman Addr = Backup;
3552e64438aSDan Gohman
3562e64438aSDan Gohman break;
3572e64438aSDan Gohman }
3582e64438aSDan Gohman case Instruction::Sub: {
3592e64438aSDan Gohman // Subs of constants are common and easy enough.
3602e64438aSDan Gohman const Value *LHS = U->getOperand(0);
3612e64438aSDan Gohman const Value *RHS = U->getOperand(1);
3622e64438aSDan Gohman
36318c56a07SHeejin Ahn if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
364728926acSDan Gohman int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
365728926acSDan Gohman if (TmpOffset >= 0) {
366728926acSDan Gohman Addr.setOffset(TmpOffset);
3672e64438aSDan Gohman return computeAddress(LHS, Addr);
3682e64438aSDan Gohman }
369728926acSDan Gohman }
3702e64438aSDan Gohman break;
3712e64438aSDan Gohman }
3722e64438aSDan Gohman }
373a31ec61cSJacob Gravelle if (Addr.isSet()) {
374a31ec61cSJacob Gravelle return false;
375a31ec61cSJacob Gravelle }
376d6b07348SJim Lin Register Reg = getRegForValue(Obj);
3773ff73cfbSDan Gohman if (Reg == 0)
3783ff73cfbSDan Gohman return false;
3793ff73cfbSDan Gohman Addr.setReg(Reg);
3802e64438aSDan Gohman return Addr.getReg() != 0;
3812e64438aSDan Gohman }
3822e64438aSDan Gohman
materializeLoadStoreOperands(Address & Addr)3839da81421SSam Clegg void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
3842e64438aSDan Gohman if (Addr.isRegBase()) {
3852e64438aSDan Gohman unsigned Reg = Addr.getReg();
3862e64438aSDan Gohman if (Reg == 0) {
387f208f631SHeejin Ahn Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
388f208f631SHeejin Ahn : &WebAssembly::I32RegClass);
389f208f631SHeejin Ahn unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
390f208f631SHeejin Ahn : WebAssembly::CONST_I32;
3912e64438aSDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
3922e64438aSDan Gohman .addImm(0);
3932e64438aSDan Gohman Addr.setReg(Reg);
3942e64438aSDan Gohman }
3952e64438aSDan Gohman }
3962e64438aSDan Gohman }
3972e64438aSDan Gohman
addLoadStoreOperands(const Address & Addr,const MachineInstrBuilder & MIB,MachineMemOperand * MMO)3982e64438aSDan Gohman void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
3992e64438aSDan Gohman const MachineInstrBuilder &MIB,
4002e64438aSDan Gohman MachineMemOperand *MMO) {
40148abaa9cSDan Gohman // Set the alignment operand (this is rewritten in SetP2AlignOperands).
40248abaa9cSDan Gohman // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
40348abaa9cSDan Gohman MIB.addImm(0);
40448abaa9cSDan Gohman
4052e64438aSDan Gohman if (const GlobalValue *GV = Addr.getGlobalValue())
4062e64438aSDan Gohman MIB.addGlobalAddress(GV, Addr.getOffset());
4072e64438aSDan Gohman else
4082e64438aSDan Gohman MIB.addImm(Addr.getOffset());
4092e64438aSDan Gohman
4102e64438aSDan Gohman if (Addr.isRegBase())
4112e64438aSDan Gohman MIB.addReg(Addr.getReg());
4122e64438aSDan Gohman else
4132e64438aSDan Gohman MIB.addFrameIndex(Addr.getFI());
4142e64438aSDan Gohman
4152e64438aSDan Gohman MIB.addMemOperand(MMO);
4162e64438aSDan Gohman }
4172e64438aSDan Gohman
maskI1Value(unsigned Reg,const Value * V)4183a5ce733SDan Gohman unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
4193a5ce733SDan Gohman return zeroExtendToI32(Reg, V, MVT::i1);
4202e64438aSDan Gohman }
4212e64438aSDan Gohman
getRegForI1Value(const Value * V,const BasicBlock * BB,bool & Not)42216086d47SNikita Popov unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V,
42316086d47SNikita Popov const BasicBlock *BB,
42416086d47SNikita Popov bool &Not) {
42518c56a07SHeejin Ahn if (const auto *ICmp = dyn_cast<ICmpInst>(V))
42633e694a8SDan Gohman if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
42716086d47SNikita Popov if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) &&
42816086d47SNikita Popov ICmp->getParent() == BB) {
42933e694a8SDan Gohman Not = ICmp->isTrueWhenEqual();
43033e694a8SDan Gohman return getRegForValue(ICmp->getOperand(0));
43133e694a8SDan Gohman }
43233e694a8SDan Gohman
43333e694a8SDan Gohman Not = false;
434d6b07348SJim Lin Register Reg = getRegForValue(V);
4353ff73cfbSDan Gohman if (Reg == 0)
4363ff73cfbSDan Gohman return 0;
4373ff73cfbSDan Gohman return maskI1Value(Reg, V);
4383a5ce733SDan Gohman }
4393a5ce733SDan Gohman
zeroExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)4403a5ce733SDan Gohman unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
4413a5ce733SDan Gohman MVT::SimpleValueType From) {
442732636d9SDerek Schuff if (Reg == 0)
443732636d9SDerek Schuff return 0;
444732636d9SDerek Schuff
4453a5ce733SDan Gohman switch (From) {
4463a5ce733SDan Gohman case MVT::i1:
4472a47e03eSThomas Lively // If the value is naturally an i1, we don't need to mask it. We only know
4482a47e03eSThomas Lively // if a value is naturally an i1 if it is definitely lowered by FastISel,
4492a47e03eSThomas Lively // not a DAG ISel fallback.
4502a47e03eSThomas Lively if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
45133e694a8SDan Gohman return copyValue(Reg);
4524dc0b1acSReid Kleckner break;
45333e694a8SDan Gohman case MVT::i8:
45433e694a8SDan Gohman case MVT::i16:
4553a5ce733SDan Gohman break;
4563a5ce733SDan Gohman case MVT::i32:
45733e694a8SDan Gohman return copyValue(Reg);
4583a5ce733SDan Gohman default:
4593a5ce733SDan Gohman return 0;
4603a5ce733SDan Gohman }
4613a5ce733SDan Gohman
462d6b07348SJim Lin Register Imm = createResultReg(&WebAssembly::I32RegClass);
4633a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
4643a5ce733SDan Gohman TII.get(WebAssembly::CONST_I32), Imm)
4653a5ce733SDan Gohman .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
4663a5ce733SDan Gohman
467d6b07348SJim Lin Register Result = createResultReg(&WebAssembly::I32RegClass);
4683a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
4693a5ce733SDan Gohman TII.get(WebAssembly::AND_I32), Result)
4703a5ce733SDan Gohman .addReg(Reg)
4713a5ce733SDan Gohman .addReg(Imm);
4723a5ce733SDan Gohman
4733a5ce733SDan Gohman return Result;
4743a5ce733SDan Gohman }
4753a5ce733SDan Gohman
signExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)4763a5ce733SDan Gohman unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
4773a5ce733SDan Gohman MVT::SimpleValueType From) {
478732636d9SDerek Schuff if (Reg == 0)
479732636d9SDerek Schuff return 0;
480732636d9SDerek Schuff
4813a5ce733SDan Gohman switch (From) {
4823a5ce733SDan Gohman case MVT::i1:
4833a5ce733SDan Gohman case MVT::i8:
4843a5ce733SDan Gohman case MVT::i16:
4853a5ce733SDan Gohman break;
4863a5ce733SDan Gohman case MVT::i32:
48733e694a8SDan Gohman return copyValue(Reg);
4883a5ce733SDan Gohman default:
48933e694a8SDan Gohman return 0;
4903a5ce733SDan Gohman }
4913a5ce733SDan Gohman
492d6b07348SJim Lin Register Imm = createResultReg(&WebAssembly::I32RegClass);
4933a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
4943a5ce733SDan Gohman TII.get(WebAssembly::CONST_I32), Imm)
4953a5ce733SDan Gohman .addImm(32 - MVT(From).getSizeInBits());
4963a5ce733SDan Gohman
497d6b07348SJim Lin Register Left = createResultReg(&WebAssembly::I32RegClass);
4983a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
4993a5ce733SDan Gohman TII.get(WebAssembly::SHL_I32), Left)
5003a5ce733SDan Gohman .addReg(Reg)
5013a5ce733SDan Gohman .addReg(Imm);
5023a5ce733SDan Gohman
503d6b07348SJim Lin Register Right = createResultReg(&WebAssembly::I32RegClass);
5043a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
5053a5ce733SDan Gohman TII.get(WebAssembly::SHR_S_I32), Right)
5063a5ce733SDan Gohman .addReg(Left)
5073a5ce733SDan Gohman .addReg(Imm);
5083a5ce733SDan Gohman
5093a5ce733SDan Gohman return Right;
5103a5ce733SDan Gohman }
5113a5ce733SDan Gohman
zeroExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)5123a5ce733SDan Gohman unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
5133a5ce733SDan Gohman MVT::SimpleValueType From,
5143a5ce733SDan Gohman MVT::SimpleValueType To) {
5153a5ce733SDan Gohman if (To == MVT::i64) {
5163a5ce733SDan Gohman if (From == MVT::i64)
51733e694a8SDan Gohman return copyValue(Reg);
5183a5ce733SDan Gohman
5193a5ce733SDan Gohman Reg = zeroExtendToI32(Reg, V, From);
5203a5ce733SDan Gohman
521d6b07348SJim Lin Register Result = createResultReg(&WebAssembly::I64RegClass);
5223a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
5233a5ce733SDan Gohman TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
5243a5ce733SDan Gohman .addReg(Reg);
5253a5ce733SDan Gohman return Result;
5263a5ce733SDan Gohman }
5273a5ce733SDan Gohman
528323dc634SNikita Popov if (To == MVT::i32)
5293a5ce733SDan Gohman return zeroExtendToI32(Reg, V, From);
530323dc634SNikita Popov
531323dc634SNikita Popov return 0;
5323a5ce733SDan Gohman }
5333a5ce733SDan Gohman
signExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)5343a5ce733SDan Gohman unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
5353a5ce733SDan Gohman MVT::SimpleValueType From,
5363a5ce733SDan Gohman MVT::SimpleValueType To) {
5373a5ce733SDan Gohman if (To == MVT::i64) {
5383a5ce733SDan Gohman if (From == MVT::i64)
53933e694a8SDan Gohman return copyValue(Reg);
5403a5ce733SDan Gohman
5413a5ce733SDan Gohman Reg = signExtendToI32(Reg, V, From);
5423a5ce733SDan Gohman
543d6b07348SJim Lin Register Result = createResultReg(&WebAssembly::I64RegClass);
5443a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
5453a5ce733SDan Gohman TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
5463a5ce733SDan Gohman .addReg(Reg);
5473a5ce733SDan Gohman return Result;
5483a5ce733SDan Gohman }
5493a5ce733SDan Gohman
550323dc634SNikita Popov if (To == MVT::i32)
5513a5ce733SDan Gohman return signExtendToI32(Reg, V, From);
552323dc634SNikita Popov
553323dc634SNikita Popov return 0;
5543a5ce733SDan Gohman }
5553a5ce733SDan Gohman
getRegForUnsignedValue(const Value * V)5563a5ce733SDan Gohman unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
5573a5ce733SDan Gohman MVT::SimpleValueType From = getSimpleType(V->getType());
5583a5ce733SDan Gohman MVT::SimpleValueType To = getLegalType(From);
559d6b07348SJim Lin Register VReg = getRegForValue(V);
5603ff73cfbSDan Gohman if (VReg == 0)
5613ff73cfbSDan Gohman return 0;
5623ff73cfbSDan Gohman return zeroExtend(VReg, V, From, To);
5633a5ce733SDan Gohman }
5643a5ce733SDan Gohman
getRegForSignedValue(const Value * V)5653a5ce733SDan Gohman unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
5663a5ce733SDan Gohman MVT::SimpleValueType From = getSimpleType(V->getType());
5673a5ce733SDan Gohman MVT::SimpleValueType To = getLegalType(From);
568d6b07348SJim Lin Register VReg = getRegForValue(V);
5693ff73cfbSDan Gohman if (VReg == 0)
5703ff73cfbSDan Gohman return 0;
5713ff73cfbSDan Gohman return signExtend(VReg, V, From, To);
5723a5ce733SDan Gohman }
5733a5ce733SDan Gohman
getRegForPromotedValue(const Value * V,bool IsSigned)5743a5ce733SDan Gohman unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
5753a5ce733SDan Gohman bool IsSigned) {
576f208f631SHeejin Ahn return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
5773a5ce733SDan Gohman }
5783a5ce733SDan Gohman
notValue(unsigned Reg)5793a5ce733SDan Gohman unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
58033e694a8SDan Gohman assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
58133e694a8SDan Gohman
582d6b07348SJim Lin Register NotReg = createResultReg(&WebAssembly::I32RegClass);
5833a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
5843a5ce733SDan Gohman TII.get(WebAssembly::EQZ_I32), NotReg)
5853a5ce733SDan Gohman .addReg(Reg);
5863a5ce733SDan Gohman return NotReg;
5872e64438aSDan Gohman }
5882e64438aSDan Gohman
copyValue(unsigned Reg)58933e694a8SDan Gohman unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
590d6b07348SJim Lin Register ResultReg = createResultReg(MRI.getRegClass(Reg));
591f208f631SHeejin Ahn BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY),
592f208f631SHeejin Ahn ResultReg)
59333e694a8SDan Gohman .addReg(Reg);
59433e694a8SDan Gohman return ResultReg;
59533e694a8SDan Gohman }
59633e694a8SDan Gohman
fastMaterializeAlloca(const AllocaInst * AI)5972e64438aSDan Gohman unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
5982e64438aSDan Gohman DenseMap<const AllocaInst *, int>::iterator SI =
5992e64438aSDan Gohman FuncInfo.StaticAllocaMap.find(AI);
6002e64438aSDan Gohman
6012e64438aSDan Gohman if (SI != FuncInfo.StaticAllocaMap.end()) {
602d6b07348SJim Lin Register ResultReg =
603f208f631SHeejin Ahn createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
604f208f631SHeejin Ahn : &WebAssembly::I32RegClass);
605f208f631SHeejin Ahn unsigned Opc =
606f208f631SHeejin Ahn Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
6072e64438aSDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
6082e64438aSDan Gohman .addFrameIndex(SI->second);
6092e64438aSDan Gohman return ResultReg;
6102e64438aSDan Gohman }
6112e64438aSDan Gohman
6122e64438aSDan Gohman return 0;
6132e64438aSDan Gohman }
6142e64438aSDan Gohman
fastMaterializeConstant(const Constant * C)6152e64438aSDan Gohman unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
616492f7529SSam Clegg if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
617492f7529SSam Clegg if (TLI.isPositionIndependent())
618492f7529SSam Clegg return 0;
61942bba4b8SGuanzhong Chen if (GV->isThreadLocal())
62042bba4b8SGuanzhong Chen return 0;
621d6b07348SJim Lin Register ResultReg =
622f208f631SHeejin Ahn createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
623f208f631SHeejin Ahn : &WebAssembly::I32RegClass);
624f208f631SHeejin Ahn unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
625f208f631SHeejin Ahn : WebAssembly::CONST_I32;
62633e694a8SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
6272e64438aSDan Gohman .addGlobalAddress(GV);
62833e694a8SDan Gohman return ResultReg;
6292e64438aSDan Gohman }
6302e64438aSDan Gohman
6312e64438aSDan Gohman // Let target-independent code handle it.
6322e64438aSDan Gohman return 0;
6332e64438aSDan Gohman }
6342e64438aSDan Gohman
fastLowerArguments()63533e694a8SDan Gohman bool WebAssemblyFastISel::fastLowerArguments() {
63633e694a8SDan Gohman if (!FuncInfo.CanLowerReturn)
63733e694a8SDan Gohman return false;
63833e694a8SDan Gohman
63933e694a8SDan Gohman const Function *F = FuncInfo.Fn;
64033e694a8SDan Gohman if (F->isVarArg())
64133e694a8SDan Gohman return false;
64233e694a8SDan Gohman
64308670d43SYuta Saito if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
64408670d43SYuta Saito return false;
64508670d43SYuta Saito
64618c56a07SHeejin Ahn unsigned I = 0;
64733e694a8SDan Gohman for (auto const &Arg : F->args()) {
648b518054bSReid Kleckner const AttributeList &Attrs = F->getAttributes();
649a0c42ca5SArthur Eubanks if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
650a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
651a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::SwiftError) ||
652a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::InAlloca) ||
653a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::Nest))
65433e694a8SDan Gohman return false;
65533e694a8SDan Gohman
65633e694a8SDan Gohman Type *ArgTy = Arg.getType();
65739bf39f3SDerek Schuff if (ArgTy->isStructTy() || ArgTy->isArrayTy())
65839bf39f3SDerek Schuff return false;
65939bf39f3SDerek Schuff if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
66033e694a8SDan Gohman return false;
66133e694a8SDan Gohman
66233e694a8SDan Gohman unsigned Opc;
66333e694a8SDan Gohman const TargetRegisterClass *RC;
66433e694a8SDan Gohman switch (getSimpleType(ArgTy)) {
66533e694a8SDan Gohman case MVT::i1:
66633e694a8SDan Gohman case MVT::i8:
66733e694a8SDan Gohman case MVT::i16:
66833e694a8SDan Gohman case MVT::i32:
6690ff82ac1SThomas Lively Opc = WebAssembly::ARGUMENT_i32;
67033e694a8SDan Gohman RC = &WebAssembly::I32RegClass;
67133e694a8SDan Gohman break;
67233e694a8SDan Gohman case MVT::i64:
6730ff82ac1SThomas Lively Opc = WebAssembly::ARGUMENT_i64;
67433e694a8SDan Gohman RC = &WebAssembly::I64RegClass;
67533e694a8SDan Gohman break;
67633e694a8SDan Gohman case MVT::f32:
6770ff82ac1SThomas Lively Opc = WebAssembly::ARGUMENT_f32;
67833e694a8SDan Gohman RC = &WebAssembly::F32RegClass;
67933e694a8SDan Gohman break;
68033e694a8SDan Gohman case MVT::f64:
6810ff82ac1SThomas Lively Opc = WebAssembly::ARGUMENT_f64;
68233e694a8SDan Gohman RC = &WebAssembly::F64RegClass;
68333e694a8SDan Gohman break;
68439bf39f3SDerek Schuff case MVT::v16i8:
68539bf39f3SDerek Schuff Opc = WebAssembly::ARGUMENT_v16i8;
68639bf39f3SDerek Schuff RC = &WebAssembly::V128RegClass;
68739bf39f3SDerek Schuff break;
68839bf39f3SDerek Schuff case MVT::v8i16:
68939bf39f3SDerek Schuff Opc = WebAssembly::ARGUMENT_v8i16;
69039bf39f3SDerek Schuff RC = &WebAssembly::V128RegClass;
69139bf39f3SDerek Schuff break;
69239bf39f3SDerek Schuff case MVT::v4i32:
69339bf39f3SDerek Schuff Opc = WebAssembly::ARGUMENT_v4i32;
69439bf39f3SDerek Schuff RC = &WebAssembly::V128RegClass;
69539bf39f3SDerek Schuff break;
69651ed131eSDerek Schuff case MVT::v2i64:
69751ed131eSDerek Schuff Opc = WebAssembly::ARGUMENT_v2i64;
69851ed131eSDerek Schuff RC = &WebAssembly::V128RegClass;
69951ed131eSDerek Schuff break;
70039bf39f3SDerek Schuff case MVT::v4f32:
70139bf39f3SDerek Schuff Opc = WebAssembly::ARGUMENT_v4f32;
70239bf39f3SDerek Schuff RC = &WebAssembly::V128RegClass;
70339bf39f3SDerek Schuff break;
70451ed131eSDerek Schuff case MVT::v2f64:
70551ed131eSDerek Schuff Opc = WebAssembly::ARGUMENT_v2f64;
70651ed131eSDerek Schuff RC = &WebAssembly::V128RegClass;
70751ed131eSDerek Schuff break;
70860653e24SHeejin Ahn case MVT::funcref:
70960653e24SHeejin Ahn Opc = WebAssembly::ARGUMENT_funcref;
71060653e24SHeejin Ahn RC = &WebAssembly::FUNCREFRegClass;
71160653e24SHeejin Ahn break;
71260653e24SHeejin Ahn case MVT::externref:
71360653e24SHeejin Ahn Opc = WebAssembly::ARGUMENT_externref;
71460653e24SHeejin Ahn RC = &WebAssembly::EXTERNREFRegClass;
71560653e24SHeejin Ahn break;
71633e694a8SDan Gohman default:
71733e694a8SDan Gohman return false;
71833e694a8SDan Gohman }
719d6b07348SJim Lin Register ResultReg = createResultReg(RC);
72033e694a8SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
72118c56a07SHeejin Ahn .addImm(I);
72233e694a8SDan Gohman updateValueMap(&Arg, ResultReg);
72333e694a8SDan Gohman
72418c56a07SHeejin Ahn ++I;
72533e694a8SDan Gohman }
72633e694a8SDan Gohman
72733e694a8SDan Gohman MRI.addLiveIn(WebAssembly::ARGUMENTS);
72833e694a8SDan Gohman
72933e694a8SDan Gohman auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
730b8184827SDan Gohman for (auto const &Arg : F->args()) {
731b8184827SDan Gohman MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
732b8184827SDan Gohman if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
733b8184827SDan Gohman MFI->clearParamsAndResults();
734b8184827SDan Gohman return false;
735b8184827SDan Gohman }
736b8184827SDan Gohman MFI->addParam(ArgTy);
737b8184827SDan Gohman }
73833e694a8SDan Gohman
7394576dc06SDan Gohman if (!F->getReturnType()->isVoidTy()) {
740f208f631SHeejin Ahn MVT::SimpleValueType RetTy =
741f208f631SHeejin Ahn getLegalType(getSimpleType(F->getReturnType()));
742b8184827SDan Gohman if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
743b8184827SDan Gohman MFI->clearParamsAndResults();
7444576dc06SDan Gohman return false;
745b8184827SDan Gohman }
746b8184827SDan Gohman MFI->addResult(RetTy);
7474576dc06SDan Gohman }
7486055fbaeSDan Gohman
74933e694a8SDan Gohman return true;
75033e694a8SDan Gohman }
75133e694a8SDan Gohman
selectCall(const Instruction * I)75233e694a8SDan Gohman bool WebAssemblyFastISel::selectCall(const Instruction *I) {
75318c56a07SHeejin Ahn const auto *Call = cast<CallInst>(I);
75433e694a8SDan Gohman
755a1d97a96SThomas Lively // TODO: Support tail calls in FastISel
75633e694a8SDan Gohman if (Call->isMustTailCall() || Call->isInlineAsm() ||
75733e694a8SDan Gohman Call->getFunctionType()->isVarArg())
75833e694a8SDan Gohman return false;
75933e694a8SDan Gohman
76033e694a8SDan Gohman Function *Func = Call->getCalledFunction();
76133e694a8SDan Gohman if (Func && Func->isIntrinsic())
76233e694a8SDan Gohman return false;
76333e694a8SDan Gohman
76408670d43SYuta Saito if (Call->getCallingConv() == CallingConv::Swift)
76508670d43SYuta Saito return false;
76608670d43SYuta Saito
767690b76e1SJacob Gravelle bool IsDirect = Func != nullptr;
768a58b62b4SCraig Topper if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
769690b76e1SJacob Gravelle return false;
770690b76e1SJacob Gravelle
77133e694a8SDan Gohman FunctionType *FuncTy = Call->getFunctionType();
772ca9ba764SThomas Lively unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
77333e694a8SDan Gohman bool IsVoid = FuncTy->getReturnType()->isVoidTy();
77433e694a8SDan Gohman unsigned ResultReg;
775ca9ba764SThomas Lively if (!IsVoid) {
77639bf39f3SDerek Schuff if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
77739bf39f3SDerek Schuff return false;
77839bf39f3SDerek Schuff
77933e694a8SDan Gohman MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
78033e694a8SDan Gohman switch (RetTy) {
78133e694a8SDan Gohman case MVT::i1:
78233e694a8SDan Gohman case MVT::i8:
78333e694a8SDan Gohman case MVT::i16:
78433e694a8SDan Gohman case MVT::i32:
78533e694a8SDan Gohman ResultReg = createResultReg(&WebAssembly::I32RegClass);
78633e694a8SDan Gohman break;
78733e694a8SDan Gohman case MVT::i64:
78833e694a8SDan Gohman ResultReg = createResultReg(&WebAssembly::I64RegClass);
78933e694a8SDan Gohman break;
79033e694a8SDan Gohman case MVT::f32:
79133e694a8SDan Gohman ResultReg = createResultReg(&WebAssembly::F32RegClass);
79233e694a8SDan Gohman break;
79333e694a8SDan Gohman case MVT::f64:
79433e694a8SDan Gohman ResultReg = createResultReg(&WebAssembly::F64RegClass);
79533e694a8SDan Gohman break;
79639bf39f3SDerek Schuff case MVT::v16i8:
79739bf39f3SDerek Schuff ResultReg = createResultReg(&WebAssembly::V128RegClass);
79839bf39f3SDerek Schuff break;
79939bf39f3SDerek Schuff case MVT::v8i16:
80039bf39f3SDerek Schuff ResultReg = createResultReg(&WebAssembly::V128RegClass);
80139bf39f3SDerek Schuff break;
80239bf39f3SDerek Schuff case MVT::v4i32:
80339bf39f3SDerek Schuff ResultReg = createResultReg(&WebAssembly::V128RegClass);
80439bf39f3SDerek Schuff break;
80551ed131eSDerek Schuff case MVT::v2i64:
80651ed131eSDerek Schuff ResultReg = createResultReg(&WebAssembly::V128RegClass);
80751ed131eSDerek Schuff break;
80839bf39f3SDerek Schuff case MVT::v4f32:
80939bf39f3SDerek Schuff ResultReg = createResultReg(&WebAssembly::V128RegClass);
81039bf39f3SDerek Schuff break;
81151ed131eSDerek Schuff case MVT::v2f64:
81251ed131eSDerek Schuff ResultReg = createResultReg(&WebAssembly::V128RegClass);
81351ed131eSDerek Schuff break;
81469e2797eSPaulo Matos case MVT::funcref:
81569e2797eSPaulo Matos ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
81669e2797eSPaulo Matos break;
81769e2797eSPaulo Matos case MVT::externref:
81869e2797eSPaulo Matos ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
81969e2797eSPaulo Matos break;
82033e694a8SDan Gohman default:
82133e694a8SDan Gohman return false;
82233e694a8SDan Gohman }
82333e694a8SDan Gohman }
82433e694a8SDan Gohman
82533e694a8SDan Gohman SmallVector<unsigned, 8> Args;
826c1e32b3fSKazu Hirata for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
82718c56a07SHeejin Ahn Value *V = Call->getArgOperand(I);
82833e694a8SDan Gohman MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
82933e694a8SDan Gohman if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
83033e694a8SDan Gohman return false;
83133e694a8SDan Gohman
832b518054bSReid Kleckner const AttributeList &Attrs = Call->getAttributes();
833a0c42ca5SArthur Eubanks if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
834a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
835a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::SwiftError) ||
836a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::InAlloca) ||
837a0c42ca5SArthur Eubanks Attrs.hasParamAttr(I, Attribute::Nest))
83833e694a8SDan Gohman return false;
83933e694a8SDan Gohman
84033e694a8SDan Gohman unsigned Reg;
84133e694a8SDan Gohman
842a0c42ca5SArthur Eubanks if (Attrs.hasParamAttr(I, Attribute::SExt))
84333e694a8SDan Gohman Reg = getRegForSignedValue(V);
844a0c42ca5SArthur Eubanks else if (Attrs.hasParamAttr(I, Attribute::ZExt))
84533e694a8SDan Gohman Reg = getRegForUnsignedValue(V);
84633e694a8SDan Gohman else
84733e694a8SDan Gohman Reg = getRegForValue(V);
84833e694a8SDan Gohman
84933e694a8SDan Gohman if (Reg == 0)
85033e694a8SDan Gohman return false;
85133e694a8SDan Gohman
85233e694a8SDan Gohman Args.push_back(Reg);
85333e694a8SDan Gohman }
85433e694a8SDan Gohman
855a2725279SSam Clegg unsigned CalleeReg = 0;
856a2725279SSam Clegg if (!IsDirect) {
857a58b62b4SCraig Topper CalleeReg = getRegForValue(Call->getCalledOperand());
858a2725279SSam Clegg if (!CalleeReg)
859a2725279SSam Clegg return false;
860a2725279SSam Clegg }
861a2725279SSam Clegg
86233e694a8SDan Gohman auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
86333e694a8SDan Gohman
86433e694a8SDan Gohman if (!IsVoid)
86533e694a8SDan Gohman MIB.addReg(ResultReg, RegState::Define);
86633e694a8SDan Gohman
867ca9ba764SThomas Lively if (IsDirect) {
86833e694a8SDan Gohman MIB.addGlobalAddress(Func);
869ca9ba764SThomas Lively } else {
8704307069dSAndy Wingo // Placeholder for the type index.
871ca9ba764SThomas Lively MIB.addImm(0);
8722632ba6aSAndy Wingo // The table into which this call_indirect indexes.
8732632ba6aSAndy Wingo MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol(
8742632ba6aSAndy Wingo MF->getMMI().getContext(), Subtarget);
8752632ba6aSAndy Wingo if (Subtarget->hasReferenceTypes()) {
8762632ba6aSAndy Wingo MIB.addSym(Table);
8772632ba6aSAndy Wingo } else {
8782632ba6aSAndy Wingo // Otherwise for the MVP there is at most one table whose number is 0, but
8792632ba6aSAndy Wingo // we can't write a table symbol or issue relocations. Instead we just
8802632ba6aSAndy Wingo // ensure the table is live.
8812632ba6aSAndy Wingo Table->setNoStrip();
88296ef4f30SSam Clegg MIB.addImm(0);
8832632ba6aSAndy Wingo }
884275c6af7SWouter van Oortmerssen // See if we must truncate the function pointer.
885275c6af7SWouter van Oortmerssen // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
886275c6af7SWouter van Oortmerssen // as 64-bit for uniformity with other pointer types.
887275c6af7SWouter van Oortmerssen // See also: WebAssemblyISelLowering.cpp: LowerCallResults
888275c6af7SWouter van Oortmerssen if (Subtarget->hasAddr64()) {
889275c6af7SWouter van Oortmerssen auto Wrap = BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), DbgLoc,
890275c6af7SWouter van Oortmerssen TII.get(WebAssembly::I32_WRAP_I64));
891d6b07348SJim Lin Register Reg32 = createResultReg(&WebAssembly::I32RegClass);
892275c6af7SWouter van Oortmerssen Wrap.addReg(Reg32, RegState::Define);
893275c6af7SWouter van Oortmerssen Wrap.addReg(CalleeReg);
894275c6af7SWouter van Oortmerssen CalleeReg = Reg32;
895275c6af7SWouter van Oortmerssen }
896ca9ba764SThomas Lively }
89733e694a8SDan Gohman
89833e694a8SDan Gohman for (unsigned ArgReg : Args)
89933e694a8SDan Gohman MIB.addReg(ArgReg);
90033e694a8SDan Gohman
901ca9ba764SThomas Lively if (!IsDirect)
902ca9ba764SThomas Lively MIB.addReg(CalleeReg);
903ca9ba764SThomas Lively
90433e694a8SDan Gohman if (!IsVoid)
90533e694a8SDan Gohman updateValueMap(Call, ResultReg);
90633e694a8SDan Gohman return true;
90733e694a8SDan Gohman }
90833e694a8SDan Gohman
selectSelect(const Instruction * I)90933e694a8SDan Gohman bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
91018c56a07SHeejin Ahn const auto *Select = cast<SelectInst>(I);
91133e694a8SDan Gohman
91233e694a8SDan Gohman bool Not;
91316086d47SNikita Popov unsigned CondReg =
91416086d47SNikita Popov getRegForI1Value(Select->getCondition(), I->getParent(), Not);
91533e694a8SDan Gohman if (CondReg == 0)
91633e694a8SDan Gohman return false;
91733e694a8SDan Gohman
918d6b07348SJim Lin Register TrueReg = getRegForValue(Select->getTrueValue());
91933e694a8SDan Gohman if (TrueReg == 0)
92033e694a8SDan Gohman return false;
92133e694a8SDan Gohman
922d6b07348SJim Lin Register FalseReg = getRegForValue(Select->getFalseValue());
92333e694a8SDan Gohman if (FalseReg == 0)
92433e694a8SDan Gohman return false;
92533e694a8SDan Gohman
92633e694a8SDan Gohman if (Not)
92733e694a8SDan Gohman std::swap(TrueReg, FalseReg);
92833e694a8SDan Gohman
92933e694a8SDan Gohman unsigned Opc;
93033e694a8SDan Gohman const TargetRegisterClass *RC;
93133e694a8SDan Gohman switch (getSimpleType(Select->getType())) {
93233e694a8SDan Gohman case MVT::i1:
93333e694a8SDan Gohman case MVT::i8:
93433e694a8SDan Gohman case MVT::i16:
93533e694a8SDan Gohman case MVT::i32:
93633e694a8SDan Gohman Opc = WebAssembly::SELECT_I32;
93733e694a8SDan Gohman RC = &WebAssembly::I32RegClass;
93833e694a8SDan Gohman break;
93933e694a8SDan Gohman case MVT::i64:
94033e694a8SDan Gohman Opc = WebAssembly::SELECT_I64;
94133e694a8SDan Gohman RC = &WebAssembly::I64RegClass;
94233e694a8SDan Gohman break;
94333e694a8SDan Gohman case MVT::f32:
94433e694a8SDan Gohman Opc = WebAssembly::SELECT_F32;
94533e694a8SDan Gohman RC = &WebAssembly::F32RegClass;
94633e694a8SDan Gohman break;
94733e694a8SDan Gohman case MVT::f64:
94833e694a8SDan Gohman Opc = WebAssembly::SELECT_F64;
94933e694a8SDan Gohman RC = &WebAssembly::F64RegClass;
95033e694a8SDan Gohman break;
95160653e24SHeejin Ahn case MVT::funcref:
95260653e24SHeejin Ahn Opc = WebAssembly::SELECT_FUNCREF;
95360653e24SHeejin Ahn RC = &WebAssembly::FUNCREFRegClass;
95460653e24SHeejin Ahn break;
95560653e24SHeejin Ahn case MVT::externref:
95660653e24SHeejin Ahn Opc = WebAssembly::SELECT_EXTERNREF;
95760653e24SHeejin Ahn RC = &WebAssembly::EXTERNREFRegClass;
95860653e24SHeejin Ahn break;
95933e694a8SDan Gohman default:
96033e694a8SDan Gohman return false;
96133e694a8SDan Gohman }
96233e694a8SDan Gohman
963d6b07348SJim Lin Register ResultReg = createResultReg(RC);
96433e694a8SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
96533e694a8SDan Gohman .addReg(TrueReg)
96633e694a8SDan Gohman .addReg(FalseReg)
96733e694a8SDan Gohman .addReg(CondReg);
96833e694a8SDan Gohman
96933e694a8SDan Gohman updateValueMap(Select, ResultReg);
97033e694a8SDan Gohman return true;
97133e694a8SDan Gohman }
97233e694a8SDan Gohman
selectTrunc(const Instruction * I)97333e694a8SDan Gohman bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
97418c56a07SHeejin Ahn const auto *Trunc = cast<TruncInst>(I);
97533e694a8SDan Gohman
976d6b07348SJim Lin Register Reg = getRegForValue(Trunc->getOperand(0));
97733e694a8SDan Gohman if (Reg == 0)
97833e694a8SDan Gohman return false;
97933e694a8SDan Gohman
98033e694a8SDan Gohman if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
981d6b07348SJim Lin Register Result = createResultReg(&WebAssembly::I32RegClass);
98233e694a8SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
98333e694a8SDan Gohman TII.get(WebAssembly::I32_WRAP_I64), Result)
98433e694a8SDan Gohman .addReg(Reg);
98533e694a8SDan Gohman Reg = Result;
98633e694a8SDan Gohman }
98733e694a8SDan Gohman
98833e694a8SDan Gohman updateValueMap(Trunc, Reg);
98933e694a8SDan Gohman return true;
99033e694a8SDan Gohman }
99133e694a8SDan Gohman
selectZExt(const Instruction * I)9923a5ce733SDan Gohman bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
99318c56a07SHeejin Ahn const auto *ZExt = cast<ZExtInst>(I);
9943a5ce733SDan Gohman
99533e694a8SDan Gohman const Value *Op = ZExt->getOperand(0);
99633e694a8SDan Gohman MVT::SimpleValueType From = getSimpleType(Op->getType());
99733e694a8SDan Gohman MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
998d6b07348SJim Lin Register In = getRegForValue(Op);
9993ff73cfbSDan Gohman if (In == 0)
10003ff73cfbSDan Gohman return false;
10013ff73cfbSDan Gohman unsigned Reg = zeroExtend(In, Op, From, To);
10023a5ce733SDan Gohman if (Reg == 0)
10033a5ce733SDan Gohman return false;
10043a5ce733SDan Gohman
10053a5ce733SDan Gohman updateValueMap(ZExt, Reg);
10063a5ce733SDan Gohman return true;
10073a5ce733SDan Gohman }
10083a5ce733SDan Gohman
selectSExt(const Instruction * I)10093a5ce733SDan Gohman bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
101018c56a07SHeejin Ahn const auto *SExt = cast<SExtInst>(I);
10113a5ce733SDan Gohman
101233e694a8SDan Gohman const Value *Op = SExt->getOperand(0);
101333e694a8SDan Gohman MVT::SimpleValueType From = getSimpleType(Op->getType());
101433e694a8SDan Gohman MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1015d6b07348SJim Lin Register In = getRegForValue(Op);
10163ff73cfbSDan Gohman if (In == 0)
10173ff73cfbSDan Gohman return false;
10183ff73cfbSDan Gohman unsigned Reg = signExtend(In, Op, From, To);
10193a5ce733SDan Gohman if (Reg == 0)
10203a5ce733SDan Gohman return false;
10213a5ce733SDan Gohman
10223a5ce733SDan Gohman updateValueMap(SExt, Reg);
10233a5ce733SDan Gohman return true;
10243a5ce733SDan Gohman }
10253a5ce733SDan Gohman
selectICmp(const Instruction * I)10263a5ce733SDan Gohman bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
102718c56a07SHeejin Ahn const auto *ICmp = cast<ICmpInst>(I);
10283a5ce733SDan Gohman
10293a5ce733SDan Gohman bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
10303a5ce733SDan Gohman unsigned Opc;
103118c56a07SHeejin Ahn bool IsSigned = false;
10323a5ce733SDan Gohman switch (ICmp->getPredicate()) {
10333a5ce733SDan Gohman case ICmpInst::ICMP_EQ:
10343a5ce733SDan Gohman Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
10353a5ce733SDan Gohman break;
10363a5ce733SDan Gohman case ICmpInst::ICMP_NE:
10373a5ce733SDan Gohman Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
10383a5ce733SDan Gohman break;
10393a5ce733SDan Gohman case ICmpInst::ICMP_UGT:
10403a5ce733SDan Gohman Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
10413a5ce733SDan Gohman break;
10423a5ce733SDan Gohman case ICmpInst::ICMP_UGE:
10433a5ce733SDan Gohman Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
10443a5ce733SDan Gohman break;
10453a5ce733SDan Gohman case ICmpInst::ICMP_ULT:
10463a5ce733SDan Gohman Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
10473a5ce733SDan Gohman break;
10483a5ce733SDan Gohman case ICmpInst::ICMP_ULE:
10493a5ce733SDan Gohman Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
10503a5ce733SDan Gohman break;
10513a5ce733SDan Gohman case ICmpInst::ICMP_SGT:
10523a5ce733SDan Gohman Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
105318c56a07SHeejin Ahn IsSigned = true;
10543a5ce733SDan Gohman break;
10553a5ce733SDan Gohman case ICmpInst::ICMP_SGE:
10563a5ce733SDan Gohman Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
105718c56a07SHeejin Ahn IsSigned = true;
10583a5ce733SDan Gohman break;
10593a5ce733SDan Gohman case ICmpInst::ICMP_SLT:
10603a5ce733SDan Gohman Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
106118c56a07SHeejin Ahn IsSigned = true;
10623a5ce733SDan Gohman break;
10633a5ce733SDan Gohman case ICmpInst::ICMP_SLE:
10643a5ce733SDan Gohman Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
106518c56a07SHeejin Ahn IsSigned = true;
10663a5ce733SDan Gohman break;
1067f208f631SHeejin Ahn default:
1068f208f631SHeejin Ahn return false;
10693a5ce733SDan Gohman }
10703a5ce733SDan Gohman
107118c56a07SHeejin Ahn unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
10723a5ce733SDan Gohman if (LHS == 0)
10733a5ce733SDan Gohman return false;
10743a5ce733SDan Gohman
107518c56a07SHeejin Ahn unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
10763a5ce733SDan Gohman if (RHS == 0)
10773a5ce733SDan Gohman return false;
10783a5ce733SDan Gohman
1079d6b07348SJim Lin Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
10803a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
10813a5ce733SDan Gohman .addReg(LHS)
10823a5ce733SDan Gohman .addReg(RHS);
10833a5ce733SDan Gohman updateValueMap(ICmp, ResultReg);
10843a5ce733SDan Gohman return true;
10853a5ce733SDan Gohman }
10863a5ce733SDan Gohman
selectFCmp(const Instruction * I)10873a5ce733SDan Gohman bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
108818c56a07SHeejin Ahn const auto *FCmp = cast<FCmpInst>(I);
10893a5ce733SDan Gohman
1090d6b07348SJim Lin Register LHS = getRegForValue(FCmp->getOperand(0));
10913a5ce733SDan Gohman if (LHS == 0)
10923a5ce733SDan Gohman return false;
10933a5ce733SDan Gohman
1094d6b07348SJim Lin Register RHS = getRegForValue(FCmp->getOperand(1));
10953a5ce733SDan Gohman if (RHS == 0)
10963a5ce733SDan Gohman return false;
10973a5ce733SDan Gohman
10983a5ce733SDan Gohman bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
10993a5ce733SDan Gohman unsigned Opc;
11003a5ce733SDan Gohman bool Not = false;
11013a5ce733SDan Gohman switch (FCmp->getPredicate()) {
11023a5ce733SDan Gohman case FCmpInst::FCMP_OEQ:
11033a5ce733SDan Gohman Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
11043a5ce733SDan Gohman break;
11053a5ce733SDan Gohman case FCmpInst::FCMP_UNE:
11063a5ce733SDan Gohman Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
11073a5ce733SDan Gohman break;
11083a5ce733SDan Gohman case FCmpInst::FCMP_OGT:
11093a5ce733SDan Gohman Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
11103a5ce733SDan Gohman break;
11113a5ce733SDan Gohman case FCmpInst::FCMP_OGE:
11123a5ce733SDan Gohman Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
11133a5ce733SDan Gohman break;
11143a5ce733SDan Gohman case FCmpInst::FCMP_OLT:
11153a5ce733SDan Gohman Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
11163a5ce733SDan Gohman break;
11173a5ce733SDan Gohman case FCmpInst::FCMP_OLE:
11183a5ce733SDan Gohman Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
11193a5ce733SDan Gohman break;
11203a5ce733SDan Gohman case FCmpInst::FCMP_UGT:
11213a5ce733SDan Gohman Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
11223a5ce733SDan Gohman Not = true;
11233a5ce733SDan Gohman break;
11243a5ce733SDan Gohman case FCmpInst::FCMP_UGE:
11253a5ce733SDan Gohman Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
11263a5ce733SDan Gohman Not = true;
11273a5ce733SDan Gohman break;
11283a5ce733SDan Gohman case FCmpInst::FCMP_ULT:
11293a5ce733SDan Gohman Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
11303a5ce733SDan Gohman Not = true;
11313a5ce733SDan Gohman break;
11323a5ce733SDan Gohman case FCmpInst::FCMP_ULE:
11333a5ce733SDan Gohman Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
11343a5ce733SDan Gohman Not = true;
11353a5ce733SDan Gohman break;
11363a5ce733SDan Gohman default:
11373a5ce733SDan Gohman return false;
11383a5ce733SDan Gohman }
11393a5ce733SDan Gohman
1140d6b07348SJim Lin Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
11413a5ce733SDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
11423a5ce733SDan Gohman .addReg(LHS)
11433a5ce733SDan Gohman .addReg(RHS);
11443a5ce733SDan Gohman
11453a5ce733SDan Gohman if (Not)
11463a5ce733SDan Gohman ResultReg = notValue(ResultReg);
11473a5ce733SDan Gohman
11483a5ce733SDan Gohman updateValueMap(FCmp, ResultReg);
11493a5ce733SDan Gohman return true;
11503a5ce733SDan Gohman }
11513a5ce733SDan Gohman
selectBitCast(const Instruction * I)11522e64438aSDan Gohman bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
11532e64438aSDan Gohman // Target-independent code can handle this, except it doesn't set the dead
11542e64438aSDan Gohman // flag on the ARGUMENTS clobber, so we have to do that manually in order
11552e64438aSDan Gohman // to satisfy code that expects this of isBitcast() instructions.
11562e64438aSDan Gohman EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
11572e64438aSDan Gohman EVT RetVT = TLI.getValueType(DL, I->getType());
11582e64438aSDan Gohman if (!VT.isSimple() || !RetVT.isSimple())
11592e64438aSDan Gohman return false;
116033e694a8SDan Gohman
1161d6b07348SJim Lin Register In = getRegForValue(I->getOperand(0));
11623ff73cfbSDan Gohman if (In == 0)
11633ff73cfbSDan Gohman return false;
11643ff73cfbSDan Gohman
116533e694a8SDan Gohman if (VT == RetVT) {
116633e694a8SDan Gohman // No-op bitcast.
11673ff73cfbSDan Gohman updateValueMap(I, In);
116833e694a8SDan Gohman return true;
116933e694a8SDan Gohman }
117033e694a8SDan Gohman
1171f4d3113aSMatt Arsenault Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
117266506582SNikita Popov In);
11732e64438aSDan Gohman if (!Reg)
11742e64438aSDan Gohman return false;
11752e64438aSDan Gohman MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
11762e64438aSDan Gohman --Iter;
11772e64438aSDan Gohman assert(Iter->isBitcast());
1178f4d3113aSMatt Arsenault Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
11792e64438aSDan Gohman updateValueMap(I, Reg);
11802e64438aSDan Gohman return true;
11812e64438aSDan Gohman }
11822e64438aSDan Gohman
selectLoad(const Instruction * I)11832e64438aSDan Gohman bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
118418c56a07SHeejin Ahn const auto *Load = cast<LoadInst>(I);
11852e64438aSDan Gohman if (Load->isAtomic())
11862e64438aSDan Gohman return false;
1187d7086af2SPaulo Matos if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1188d7086af2SPaulo Matos return false;
118939bf39f3SDerek Schuff if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
119039bf39f3SDerek Schuff return false;
11912e64438aSDan Gohman
11922e64438aSDan Gohman Address Addr;
11932e64438aSDan Gohman if (!computeAddress(Load->getPointerOperand(), Addr))
11942e64438aSDan Gohman return false;
11952e64438aSDan Gohman
11962e64438aSDan Gohman // TODO: Fold a following sign-/zero-extend into the load instruction.
11972e64438aSDan Gohman
11982e64438aSDan Gohman unsigned Opc;
11992e64438aSDan Gohman const TargetRegisterClass *RC;
1200d9e0bbd1SWouter van Oortmerssen bool A64 = Subtarget->hasAddr64();
12013a5ce733SDan Gohman switch (getSimpleType(Load->getType())) {
12023a5ce733SDan Gohman case MVT::i1:
12033a5ce733SDan Gohman case MVT::i8:
1204d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
12052e64438aSDan Gohman RC = &WebAssembly::I32RegClass;
12062e64438aSDan Gohman break;
12073a5ce733SDan Gohman case MVT::i16:
1208d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
12092e64438aSDan Gohman RC = &WebAssembly::I32RegClass;
12102e64438aSDan Gohman break;
12113a5ce733SDan Gohman case MVT::i32:
1212d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
12132e64438aSDan Gohman RC = &WebAssembly::I32RegClass;
12142e64438aSDan Gohman break;
12153a5ce733SDan Gohman case MVT::i64:
1216d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
12172e64438aSDan Gohman RC = &WebAssembly::I64RegClass;
12182e64438aSDan Gohman break;
12193a5ce733SDan Gohman case MVT::f32:
1220d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
12212e64438aSDan Gohman RC = &WebAssembly::F32RegClass;
12222e64438aSDan Gohman break;
12233a5ce733SDan Gohman case MVT::f64:
1224d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
12252e64438aSDan Gohman RC = &WebAssembly::F64RegClass;
12262e64438aSDan Gohman break;
12273a5ce733SDan Gohman default:
12283a5ce733SDan Gohman return false;
12292e64438aSDan Gohman }
12302e64438aSDan Gohman
12319da81421SSam Clegg materializeLoadStoreOperands(Addr);
12322e64438aSDan Gohman
1233d6b07348SJim Lin Register ResultReg = createResultReg(RC);
12342e64438aSDan Gohman auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
12352e64438aSDan Gohman ResultReg);
12362e64438aSDan Gohman
12372e64438aSDan Gohman addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
12382e64438aSDan Gohman
12392e64438aSDan Gohman updateValueMap(Load, ResultReg);
12402e64438aSDan Gohman return true;
12412e64438aSDan Gohman }
12422e64438aSDan Gohman
selectStore(const Instruction * I)12432e64438aSDan Gohman bool WebAssemblyFastISel::selectStore(const Instruction *I) {
124418c56a07SHeejin Ahn const auto *Store = cast<StoreInst>(I);
12452e64438aSDan Gohman if (Store->isAtomic())
12462e64438aSDan Gohman return false;
1247d7086af2SPaulo Matos if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1248d7086af2SPaulo Matos return false;
124939bf39f3SDerek Schuff if (!Subtarget->hasSIMD128() &&
125039bf39f3SDerek Schuff Store->getValueOperand()->getType()->isVectorTy())
125139bf39f3SDerek Schuff return false;
12522e64438aSDan Gohman
12532e64438aSDan Gohman Address Addr;
12542e64438aSDan Gohman if (!computeAddress(Store->getPointerOperand(), Addr))
12552e64438aSDan Gohman return false;
12562e64438aSDan Gohman
12572e64438aSDan Gohman unsigned Opc;
12582e64438aSDan Gohman bool VTIsi1 = false;
1259d9e0bbd1SWouter van Oortmerssen bool A64 = Subtarget->hasAddr64();
12603a5ce733SDan Gohman switch (getSimpleType(Store->getValueOperand()->getType())) {
12613a5ce733SDan Gohman case MVT::i1:
12622e64438aSDan Gohman VTIsi1 = true;
1263861bec2bSDan Gohman LLVM_FALLTHROUGH;
12643a5ce733SDan Gohman case MVT::i8:
1265d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
12662e64438aSDan Gohman break;
12673a5ce733SDan Gohman case MVT::i16:
1268d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
12692e64438aSDan Gohman break;
12703a5ce733SDan Gohman case MVT::i32:
1271d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
12722e64438aSDan Gohman break;
12733a5ce733SDan Gohman case MVT::i64:
1274d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
12752e64438aSDan Gohman break;
12763a5ce733SDan Gohman case MVT::f32:
1277d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
12782e64438aSDan Gohman break;
12793a5ce733SDan Gohman case MVT::f64:
1280d9e0bbd1SWouter van Oortmerssen Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
12812e64438aSDan Gohman break;
1282f208f631SHeejin Ahn default:
1283f208f631SHeejin Ahn return false;
12842e64438aSDan Gohman }
12852e64438aSDan Gohman
12869da81421SSam Clegg materializeLoadStoreOperands(Addr);
12872e64438aSDan Gohman
1288d6b07348SJim Lin Register ValueReg = getRegForValue(Store->getValueOperand());
1289732636d9SDerek Schuff if (ValueReg == 0)
1290732636d9SDerek Schuff return false;
12912e64438aSDan Gohman if (VTIsi1)
12923a5ce733SDan Gohman ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
12932e64438aSDan Gohman
12947f1bdb2eSDan Gohman auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
12952e64438aSDan Gohman
12962e64438aSDan Gohman addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
12972e64438aSDan Gohman
12982e64438aSDan Gohman MIB.addReg(ValueReg);
12992e64438aSDan Gohman return true;
13002e64438aSDan Gohman }
13012e64438aSDan Gohman
selectBr(const Instruction * I)13022e64438aSDan Gohman bool WebAssemblyFastISel::selectBr(const Instruction *I) {
130318c56a07SHeejin Ahn const auto *Br = cast<BranchInst>(I);
13042e64438aSDan Gohman if (Br->isUnconditional()) {
13052e64438aSDan Gohman MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
13062e64438aSDan Gohman fastEmitBranch(MSucc, Br->getDebugLoc());
13072e64438aSDan Gohman return true;
13082e64438aSDan Gohman }
13092e64438aSDan Gohman
13102e64438aSDan Gohman MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
13112e64438aSDan Gohman MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
13122e64438aSDan Gohman
131333e694a8SDan Gohman bool Not;
131416086d47SNikita Popov unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1315732636d9SDerek Schuff if (CondReg == 0)
1316732636d9SDerek Schuff return false;
13172e64438aSDan Gohman
131833e694a8SDan Gohman unsigned Opc = WebAssembly::BR_IF;
131933e694a8SDan Gohman if (Not)
132033e694a8SDan Gohman Opc = WebAssembly::BR_UNLESS;
132133e694a8SDan Gohman
13222e64438aSDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
13232e64438aSDan Gohman .addMBB(TBB)
13242e64438aSDan Gohman .addReg(CondReg);
13252e64438aSDan Gohman
13262e64438aSDan Gohman finishCondBranch(Br->getParent(), TBB, FBB);
13272e64438aSDan Gohman return true;
13282e64438aSDan Gohman }
13292e64438aSDan Gohman
selectRet(const Instruction * I)13302e64438aSDan Gohman bool WebAssemblyFastISel::selectRet(const Instruction *I) {
13312e64438aSDan Gohman if (!FuncInfo.CanLowerReturn)
13322e64438aSDan Gohman return false;
13332e64438aSDan Gohman
133418c56a07SHeejin Ahn const auto *Ret = cast<ReturnInst>(I);
13352e64438aSDan Gohman
13362e64438aSDan Gohman if (Ret->getNumOperands() == 0) {
13372e64438aSDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
133800f9e5aaSThomas Lively TII.get(WebAssembly::RETURN));
13392e64438aSDan Gohman return true;
13402e64438aSDan Gohman }
13412e64438aSDan Gohman
134200f9e5aaSThomas Lively // TODO: support multiple return in FastISel
134300f9e5aaSThomas Lively if (Ret->getNumOperands() > 1)
134400f9e5aaSThomas Lively return false;
134500f9e5aaSThomas Lively
13462e64438aSDan Gohman Value *RV = Ret->getOperand(0);
134739bf39f3SDerek Schuff if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
134839bf39f3SDerek Schuff return false;
134939bf39f3SDerek Schuff
13503a5ce733SDan Gohman switch (getSimpleType(RV->getType())) {
1351f208f631SHeejin Ahn case MVT::i1:
1352f208f631SHeejin Ahn case MVT::i8:
1353f208f631SHeejin Ahn case MVT::i16:
1354f208f631SHeejin Ahn case MVT::i32:
13553a5ce733SDan Gohman case MVT::i64:
135639bf39f3SDerek Schuff case MVT::f32:
135739bf39f3SDerek Schuff case MVT::f64:
135839bf39f3SDerek Schuff case MVT::v16i8:
135939bf39f3SDerek Schuff case MVT::v8i16:
136039bf39f3SDerek Schuff case MVT::v4i32:
136151ed131eSDerek Schuff case MVT::v2i64:
136239bf39f3SDerek Schuff case MVT::v4f32:
136351ed131eSDerek Schuff case MVT::v2f64:
136460653e24SHeejin Ahn case MVT::funcref:
136560653e24SHeejin Ahn case MVT::externref:
13660de58729SHeejin Ahn break;
1367f208f631SHeejin Ahn default:
1368f208f631SHeejin Ahn return false;
13692e64438aSDan Gohman }
13702e64438aSDan Gohman
137133e694a8SDan Gohman unsigned Reg;
1372d7593ebaSArthur Eubanks if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
137333e694a8SDan Gohman Reg = getRegForSignedValue(RV);
1374d7593ebaSArthur Eubanks else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
137533e694a8SDan Gohman Reg = getRegForUnsignedValue(RV);
137633e694a8SDan Gohman else
137733e694a8SDan Gohman Reg = getRegForValue(RV);
137833e694a8SDan Gohman
1379732636d9SDerek Schuff if (Reg == 0)
1380732636d9SDerek Schuff return false;
1381732636d9SDerek Schuff
138200f9e5aaSThomas Lively BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
138300f9e5aaSThomas Lively TII.get(WebAssembly::RETURN))
138400f9e5aaSThomas Lively .addReg(Reg);
13852e64438aSDan Gohman return true;
13862e64438aSDan Gohman }
13872e64438aSDan Gohman
selectUnreachable(const Instruction * I)13882e64438aSDan Gohman bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
13892e64438aSDan Gohman BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
13902e64438aSDan Gohman TII.get(WebAssembly::UNREACHABLE));
13912e64438aSDan Gohman return true;
13922e64438aSDan Gohman }
13932e64438aSDan Gohman
fastSelectInstruction(const Instruction * I)13942e64438aSDan Gohman bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
13952e64438aSDan Gohman switch (I->getOpcode()) {
139633e694a8SDan Gohman case Instruction::Call:
139733e694a8SDan Gohman if (selectCall(I))
139833e694a8SDan Gohman return true;
139933e694a8SDan Gohman break;
1400f208f631SHeejin Ahn case Instruction::Select:
1401f208f631SHeejin Ahn return selectSelect(I);
1402f208f631SHeejin Ahn case Instruction::Trunc:
1403f208f631SHeejin Ahn return selectTrunc(I);
1404f208f631SHeejin Ahn case Instruction::ZExt:
1405f208f631SHeejin Ahn return selectZExt(I);
1406f208f631SHeejin Ahn case Instruction::SExt:
1407f208f631SHeejin Ahn return selectSExt(I);
1408f208f631SHeejin Ahn case Instruction::ICmp:
1409f208f631SHeejin Ahn return selectICmp(I);
1410f208f631SHeejin Ahn case Instruction::FCmp:
1411f208f631SHeejin Ahn return selectFCmp(I);
1412f208f631SHeejin Ahn case Instruction::BitCast:
1413f208f631SHeejin Ahn return selectBitCast(I);
1414f208f631SHeejin Ahn case Instruction::Load:
1415f208f631SHeejin Ahn return selectLoad(I);
1416f208f631SHeejin Ahn case Instruction::Store:
1417f208f631SHeejin Ahn return selectStore(I);
1418f208f631SHeejin Ahn case Instruction::Br:
1419f208f631SHeejin Ahn return selectBr(I);
1420f208f631SHeejin Ahn case Instruction::Ret:
1421f208f631SHeejin Ahn return selectRet(I);
1422f208f631SHeejin Ahn case Instruction::Unreachable:
1423f208f631SHeejin Ahn return selectUnreachable(I);
1424f208f631SHeejin Ahn default:
1425f208f631SHeejin Ahn break;
14267b63484bSDan Gohman }
14277b63484bSDan Gohman
14287b63484bSDan Gohman // Fall back to target-independent instruction selection.
14297b63484bSDan Gohman return selectOperator(I, I->getOpcode());
14307b63484bSDan Gohman }
14317b63484bSDan Gohman
createFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)14327b63484bSDan Gohman FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
14337b63484bSDan Gohman const TargetLibraryInfo *LibInfo) {
14347b63484bSDan Gohman return new WebAssemblyFastISel(FuncInfo, LibInfo);
14357b63484bSDan Gohman }
1436