xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
10b57cec5SDimitry Andric //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements the WebAssemblyTargetLowering class.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "WebAssemblyISelLowering.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
160b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
170b57cec5SDimitry Andric #include "WebAssemblySubtarget.h"
180b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/Analysis.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h"
270b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
280b57cec5SDimitry Andric #include "llvm/IR/DiagnosticPrinter.h"
290b57cec5SDimitry Andric #include "llvm/IR/Function.h"
300b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
310b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
320b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
330b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
340b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
350b57cec5SDimitry Andric using namespace llvm;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-lower"
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric WebAssemblyTargetLowering::WebAssemblyTargetLowering(
400b57cec5SDimitry Andric     const TargetMachine &TM, const WebAssemblySubtarget &STI)
410b57cec5SDimitry Andric     : TargetLowering(TM), Subtarget(&STI) {
420b57cec5SDimitry Andric   auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   // Booleans always contain 0 or 1.
450b57cec5SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
460b57cec5SDimitry Andric   // Except in SIMD vectors
470b57cec5SDimitry Andric   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
480b57cec5SDimitry Andric   // We don't know the microarchitecture here, so just reduce register pressure.
490b57cec5SDimitry Andric   setSchedulingPreference(Sched::RegPressure);
500b57cec5SDimitry Andric   // Tell ISel that we have a stack pointer.
510b57cec5SDimitry Andric   setStackPointerRegisterToSaveRestore(
520b57cec5SDimitry Andric       Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
530b57cec5SDimitry Andric   // Set up the register classes.
540b57cec5SDimitry Andric   addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
550b57cec5SDimitry Andric   addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
560b57cec5SDimitry Andric   addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
570b57cec5SDimitry Andric   addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
580b57cec5SDimitry Andric   if (Subtarget->hasSIMD128()) {
590b57cec5SDimitry Andric     addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
600b57cec5SDimitry Andric     addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
610b57cec5SDimitry Andric     addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
620b57cec5SDimitry Andric     addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric   if (Subtarget->hasUnimplementedSIMD128()) {
650b57cec5SDimitry Andric     addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
660b57cec5SDimitry Andric     addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric   // Compute derived properties from the register classes.
690b57cec5SDimitry Andric   computeRegisterProperties(Subtarget->getRegisterInfo());
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
720b57cec5SDimitry Andric   setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
730b57cec5SDimitry Andric   setOperationAction(ISD::JumpTable, MVTPtr, Custom);
740b57cec5SDimitry Andric   setOperationAction(ISD::BlockAddress, MVTPtr, Custom);
750b57cec5SDimitry Andric   setOperationAction(ISD::BRIND, MVT::Other, Custom);
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   // Take the default expansion for va_arg, va_copy, and va_end. There is no
780b57cec5SDimitry Andric   // default action for va_start, so we do that custom.
790b57cec5SDimitry Andric   setOperationAction(ISD::VASTART, MVT::Other, Custom);
800b57cec5SDimitry Andric   setOperationAction(ISD::VAARG, MVT::Other, Expand);
810b57cec5SDimitry Andric   setOperationAction(ISD::VACOPY, MVT::Other, Expand);
820b57cec5SDimitry Andric   setOperationAction(ISD::VAEND, MVT::Other, Expand);
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
850b57cec5SDimitry Andric     // Don't expand the floating-point types to constant pools.
860b57cec5SDimitry Andric     setOperationAction(ISD::ConstantFP, T, Legal);
870b57cec5SDimitry Andric     // Expand floating-point comparisons.
880b57cec5SDimitry Andric     for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
890b57cec5SDimitry Andric                     ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
900b57cec5SDimitry Andric       setCondCodeAction(CC, T, Expand);
910b57cec5SDimitry Andric     // Expand floating-point library function operators.
920b57cec5SDimitry Andric     for (auto Op :
930b57cec5SDimitry Andric          {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
940b57cec5SDimitry Andric       setOperationAction(Op, T, Expand);
950b57cec5SDimitry Andric     // Note supported floating-point library function operators that otherwise
960b57cec5SDimitry Andric     // default to expand.
970b57cec5SDimitry Andric     for (auto Op :
980b57cec5SDimitry Andric          {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
990b57cec5SDimitry Andric       setOperationAction(Op, T, Legal);
1000b57cec5SDimitry Andric     // Support minimum and maximum, which otherwise default to expand.
1010b57cec5SDimitry Andric     setOperationAction(ISD::FMINIMUM, T, Legal);
1020b57cec5SDimitry Andric     setOperationAction(ISD::FMAXIMUM, T, Legal);
1030b57cec5SDimitry Andric     // WebAssembly currently has no builtin f16 support.
1040b57cec5SDimitry Andric     setOperationAction(ISD::FP16_TO_FP, T, Expand);
1050b57cec5SDimitry Andric     setOperationAction(ISD::FP_TO_FP16, T, Expand);
1060b57cec5SDimitry Andric     setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand);
1070b57cec5SDimitry Andric     setTruncStoreAction(T, MVT::f16, Expand);
1080b57cec5SDimitry Andric   }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // Expand unavailable integer operations.
1110b57cec5SDimitry Andric   for (auto Op :
1120b57cec5SDimitry Andric        {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU,
1130b57cec5SDimitry Andric         ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS,
1140b57cec5SDimitry Andric         ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
1150b57cec5SDimitry Andric     for (auto T : {MVT::i32, MVT::i64})
1160b57cec5SDimitry Andric       setOperationAction(Op, T, Expand);
1170b57cec5SDimitry Andric     if (Subtarget->hasSIMD128())
1180b57cec5SDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
1190b57cec5SDimitry Andric         setOperationAction(Op, T, Expand);
1200b57cec5SDimitry Andric     if (Subtarget->hasUnimplementedSIMD128())
1210b57cec5SDimitry Andric       setOperationAction(Op, MVT::v2i64, Expand);
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   // SIMD-specific configuration
1250b57cec5SDimitry Andric   if (Subtarget->hasSIMD128()) {
1260b57cec5SDimitry Andric     // Support saturating add for i8x16 and i16x8
1270b57cec5SDimitry Andric     for (auto Op : {ISD::SADDSAT, ISD::UADDSAT})
1280b57cec5SDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16})
1290b57cec5SDimitry Andric         setOperationAction(Op, T, Legal);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric     // Custom lower BUILD_VECTORs to minimize number of replace_lanes
1320b57cec5SDimitry Andric     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
1330b57cec5SDimitry Andric       setOperationAction(ISD::BUILD_VECTOR, T, Custom);
1340b57cec5SDimitry Andric     if (Subtarget->hasUnimplementedSIMD128())
1350b57cec5SDimitry Andric       for (auto T : {MVT::v2i64, MVT::v2f64})
1360b57cec5SDimitry Andric         setOperationAction(ISD::BUILD_VECTOR, T, Custom);
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric     // We have custom shuffle lowering to expose the shuffle mask
1390b57cec5SDimitry Andric     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
1400b57cec5SDimitry Andric       setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
1410b57cec5SDimitry Andric     if (Subtarget->hasUnimplementedSIMD128())
1420b57cec5SDimitry Andric       for (auto T: {MVT::v2i64, MVT::v2f64})
1430b57cec5SDimitry Andric         setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric     // Custom lowering since wasm shifts must have a scalar shift amount
1460b57cec5SDimitry Andric     for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) {
1470b57cec5SDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
1480b57cec5SDimitry Andric         setOperationAction(Op, T, Custom);
1490b57cec5SDimitry Andric       if (Subtarget->hasUnimplementedSIMD128())
1500b57cec5SDimitry Andric         setOperationAction(Op, MVT::v2i64, Custom);
1510b57cec5SDimitry Andric     }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric     // Custom lower lane accesses to expand out variable indices
1540b57cec5SDimitry Andric     for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT}) {
1550b57cec5SDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
1560b57cec5SDimitry Andric         setOperationAction(Op, T, Custom);
1570b57cec5SDimitry Andric       if (Subtarget->hasUnimplementedSIMD128())
1580b57cec5SDimitry Andric         for (auto T : {MVT::v2i64, MVT::v2f64})
1590b57cec5SDimitry Andric           setOperationAction(Op, T, Custom);
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric     // There is no i64x2.mul instruction
1630b57cec5SDimitry Andric     setOperationAction(ISD::MUL, MVT::v2i64, Expand);
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric     // There are no vector select instructions
1660b57cec5SDimitry Andric     for (auto Op : {ISD::VSELECT, ISD::SELECT_CC, ISD::SELECT}) {
1670b57cec5SDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
1680b57cec5SDimitry Andric         setOperationAction(Op, T, Expand);
1690b57cec5SDimitry Andric       if (Subtarget->hasUnimplementedSIMD128())
1700b57cec5SDimitry Andric         for (auto T : {MVT::v2i64, MVT::v2f64})
1710b57cec5SDimitry Andric           setOperationAction(Op, T, Expand);
1720b57cec5SDimitry Andric     }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric     // Expand integer operations supported for scalars but not SIMD
1750b57cec5SDimitry Andric     for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP, ISD::SDIV, ISD::UDIV,
1760b57cec5SDimitry Andric                     ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR}) {
1770b57cec5SDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
1780b57cec5SDimitry Andric         setOperationAction(Op, T, Expand);
1790b57cec5SDimitry Andric       if (Subtarget->hasUnimplementedSIMD128())
1800b57cec5SDimitry Andric         setOperationAction(Op, MVT::v2i64, Expand);
1810b57cec5SDimitry Andric     }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     // Expand float operations supported for scalars but not SIMD
1840b57cec5SDimitry Andric     for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
1850b57cec5SDimitry Andric                     ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10,
1860b57cec5SDimitry Andric                     ISD::FEXP, ISD::FEXP2, ISD::FRINT}) {
1870b57cec5SDimitry Andric       setOperationAction(Op, MVT::v4f32, Expand);
1880b57cec5SDimitry Andric       if (Subtarget->hasUnimplementedSIMD128())
1890b57cec5SDimitry Andric         setOperationAction(Op, MVT::v2f64, Expand);
1900b57cec5SDimitry Andric     }
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric     // Expand additional SIMD ops that V8 hasn't implemented yet
1930b57cec5SDimitry Andric     if (!Subtarget->hasUnimplementedSIMD128()) {
1940b57cec5SDimitry Andric       setOperationAction(ISD::FSQRT, MVT::v4f32, Expand);
1950b57cec5SDimitry Andric       setOperationAction(ISD::FDIV, MVT::v4f32, Expand);
1960b57cec5SDimitry Andric     }
1970b57cec5SDimitry Andric   }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   // As a special case, these operators use the type to mean the type to
2000b57cec5SDimitry Andric   // sign-extend from.
2010b57cec5SDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
2020b57cec5SDimitry Andric   if (!Subtarget->hasSignExt()) {
2030b57cec5SDimitry Andric     // Sign extends are legal only when extending a vector extract
2040b57cec5SDimitry Andric     auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
2050b57cec5SDimitry Andric     for (auto T : {MVT::i8, MVT::i16, MVT::i32})
2060b57cec5SDimitry Andric       setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action);
2070b57cec5SDimitry Andric   }
208*8bcb0991SDimitry Andric   for (auto T : MVT::integer_fixedlen_vector_valuetypes())
2090b57cec5SDimitry Andric     setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   // Dynamic stack allocation: use the default expansion.
2120b57cec5SDimitry Andric   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
2130b57cec5SDimitry Andric   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
2140b57cec5SDimitry Andric   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
2170b57cec5SDimitry Andric   setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   // Expand these forms; we pattern-match the forms that we can handle in isel.
2200b57cec5SDimitry Andric   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
2210b57cec5SDimitry Andric     for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
2220b57cec5SDimitry Andric       setOperationAction(Op, T, Expand);
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   // We have custom switch handling.
2250b57cec5SDimitry Andric   setOperationAction(ISD::BR_JT, MVT::Other, Custom);
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   // WebAssembly doesn't have:
2280b57cec5SDimitry Andric   //  - Floating-point extending loads.
2290b57cec5SDimitry Andric   //  - Floating-point truncating stores.
2300b57cec5SDimitry Andric   //  - i1 extending loads.
231*8bcb0991SDimitry Andric   //  - truncating SIMD stores and most extending loads
2320b57cec5SDimitry Andric   setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
2330b57cec5SDimitry Andric   setTruncStoreAction(MVT::f64, MVT::f32, Expand);
2340b57cec5SDimitry Andric   for (auto T : MVT::integer_valuetypes())
2350b57cec5SDimitry Andric     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
2360b57cec5SDimitry Andric       setLoadExtAction(Ext, T, MVT::i1, Promote);
2370b57cec5SDimitry Andric   if (Subtarget->hasSIMD128()) {
2380b57cec5SDimitry Andric     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
2390b57cec5SDimitry Andric                    MVT::v2f64}) {
240*8bcb0991SDimitry Andric       for (auto MemT : MVT::fixedlen_vector_valuetypes()) {
2410b57cec5SDimitry Andric         if (MVT(T) != MemT) {
2420b57cec5SDimitry Andric           setTruncStoreAction(T, MemT, Expand);
2430b57cec5SDimitry Andric           for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
2440b57cec5SDimitry Andric             setLoadExtAction(Ext, T, MemT, Expand);
2450b57cec5SDimitry Andric         }
2460b57cec5SDimitry Andric       }
2470b57cec5SDimitry Andric     }
248*8bcb0991SDimitry Andric     // But some vector extending loads are legal
249*8bcb0991SDimitry Andric     if (Subtarget->hasUnimplementedSIMD128()) {
250*8bcb0991SDimitry Andric       for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
251*8bcb0991SDimitry Andric         setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal);
252*8bcb0991SDimitry Andric         setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal);
253*8bcb0991SDimitry Andric         setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal);
254*8bcb0991SDimitry Andric       }
255*8bcb0991SDimitry Andric     }
2560b57cec5SDimitry Andric   }
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   // Don't do anything clever with build_pairs
2590b57cec5SDimitry Andric   setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand);
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   // Trap lowers to wasm unreachable
2620b57cec5SDimitry Andric   setOperationAction(ISD::TRAP, MVT::Other, Legal);
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric   // Exception handling intrinsics
2650b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
2660b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   setMaxAtomicSizeInBitsSupported(64);
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is
2710b57cec5SDimitry Andric   // consistent with the f64 and f128 names.
2720b57cec5SDimitry Andric   setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
2730b57cec5SDimitry Andric   setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   // Define the emscripten name for return address helper.
2760b57cec5SDimitry Andric   // TODO: when implementing other WASM backends, make this generic or only do
2770b57cec5SDimitry Andric   // this on emscripten depending on what they end up doing.
2780b57cec5SDimitry Andric   setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address");
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric   // Always convert switches to br_tables unless there is only one case, which
2810b57cec5SDimitry Andric   // is equivalent to a simple branch. This reduces code size for wasm, and we
2820b57cec5SDimitry Andric   // defer possible jump table optimizations to the VM.
2830b57cec5SDimitry Andric   setMinimumJumpTableEntries(2);
2840b57cec5SDimitry Andric }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric TargetLowering::AtomicExpansionKind
2870b57cec5SDimitry Andric WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
2880b57cec5SDimitry Andric   // We have wasm instructions for these
2890b57cec5SDimitry Andric   switch (AI->getOperation()) {
2900b57cec5SDimitry Andric   case AtomicRMWInst::Add:
2910b57cec5SDimitry Andric   case AtomicRMWInst::Sub:
2920b57cec5SDimitry Andric   case AtomicRMWInst::And:
2930b57cec5SDimitry Andric   case AtomicRMWInst::Or:
2940b57cec5SDimitry Andric   case AtomicRMWInst::Xor:
2950b57cec5SDimitry Andric   case AtomicRMWInst::Xchg:
2960b57cec5SDimitry Andric     return AtomicExpansionKind::None;
2970b57cec5SDimitry Andric   default:
2980b57cec5SDimitry Andric     break;
2990b57cec5SDimitry Andric   }
3000b57cec5SDimitry Andric   return AtomicExpansionKind::CmpXChg;
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric FastISel *WebAssemblyTargetLowering::createFastISel(
3040b57cec5SDimitry Andric     FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
3050b57cec5SDimitry Andric   return WebAssembly::createFastISel(FuncInfo, LibInfo);
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
3090b57cec5SDimitry Andric                                                       EVT VT) const {
3100b57cec5SDimitry Andric   unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
3110b57cec5SDimitry Andric   if (BitWidth > 1 && BitWidth < 8)
3120b57cec5SDimitry Andric     BitWidth = 8;
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   if (BitWidth > 64) {
3150b57cec5SDimitry Andric     // The shift will be lowered to a libcall, and compiler-rt libcalls expect
3160b57cec5SDimitry Andric     // the count to be an i32.
3170b57cec5SDimitry Andric     BitWidth = 32;
3180b57cec5SDimitry Andric     assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&
3190b57cec5SDimitry Andric            "32-bit shift counts ought to be enough for anyone");
3200b57cec5SDimitry Andric   }
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric   MVT Result = MVT::getIntegerVT(BitWidth);
3230b57cec5SDimitry Andric   assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
3240b57cec5SDimitry Andric          "Unable to represent scalar shift amount type");
3250b57cec5SDimitry Andric   return Result;
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric // Lower an fp-to-int conversion operator from the LLVM opcode, which has an
3290b57cec5SDimitry Andric // undefined result on invalid/overflow, to the WebAssembly opcode, which
3300b57cec5SDimitry Andric // traps on invalid/overflow.
3310b57cec5SDimitry Andric static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
3320b57cec5SDimitry Andric                                        MachineBasicBlock *BB,
3330b57cec5SDimitry Andric                                        const TargetInstrInfo &TII,
3340b57cec5SDimitry Andric                                        bool IsUnsigned, bool Int64,
3350b57cec5SDimitry Andric                                        bool Float64, unsigned LoweredOpcode) {
3360b57cec5SDimitry Andric   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
3370b57cec5SDimitry Andric 
338*8bcb0991SDimitry Andric   Register OutReg = MI.getOperand(0).getReg();
339*8bcb0991SDimitry Andric   Register InReg = MI.getOperand(1).getReg();
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric   unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
3420b57cec5SDimitry Andric   unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
3430b57cec5SDimitry Andric   unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
3440b57cec5SDimitry Andric   unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
3450b57cec5SDimitry Andric   unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
3460b57cec5SDimitry Andric   unsigned Eqz = WebAssembly::EQZ_I32;
3470b57cec5SDimitry Andric   unsigned And = WebAssembly::AND_I32;
3480b57cec5SDimitry Andric   int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
3490b57cec5SDimitry Andric   int64_t Substitute = IsUnsigned ? 0 : Limit;
3500b57cec5SDimitry Andric   double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
3510b57cec5SDimitry Andric   auto &Context = BB->getParent()->getFunction().getContext();
3520b57cec5SDimitry Andric   Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric   const BasicBlock *LLVMBB = BB->getBasicBlock();
3550b57cec5SDimitry Andric   MachineFunction *F = BB->getParent();
3560b57cec5SDimitry Andric   MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
3570b57cec5SDimitry Andric   MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB);
3580b57cec5SDimitry Andric   MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   MachineFunction::iterator It = ++BB->getIterator();
3610b57cec5SDimitry Andric   F->insert(It, FalseMBB);
3620b57cec5SDimitry Andric   F->insert(It, TrueMBB);
3630b57cec5SDimitry Andric   F->insert(It, DoneMBB);
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   // Transfer the remainder of BB and its successor edges to DoneMBB.
3660b57cec5SDimitry Andric   DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
3670b57cec5SDimitry Andric   DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   BB->addSuccessor(TrueMBB);
3700b57cec5SDimitry Andric   BB->addSuccessor(FalseMBB);
3710b57cec5SDimitry Andric   TrueMBB->addSuccessor(DoneMBB);
3720b57cec5SDimitry Andric   FalseMBB->addSuccessor(DoneMBB);
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
3750b57cec5SDimitry Andric   Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
3760b57cec5SDimitry Andric   Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
3770b57cec5SDimitry Andric   CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
3780b57cec5SDimitry Andric   EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
3790b57cec5SDimitry Andric   FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
3800b57cec5SDimitry Andric   TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   MI.eraseFromParent();
3830b57cec5SDimitry Andric   // For signed numbers, we can do a single comparison to determine whether
3840b57cec5SDimitry Andric   // fabs(x) is within range.
3850b57cec5SDimitry Andric   if (IsUnsigned) {
3860b57cec5SDimitry Andric     Tmp0 = InReg;
3870b57cec5SDimitry Andric   } else {
3880b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
3890b57cec5SDimitry Andric   }
3900b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(FConst), Tmp1)
3910b57cec5SDimitry Andric       .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
3920b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric   // For unsigned numbers, we have to do a separate comparison with zero.
3950b57cec5SDimitry Andric   if (IsUnsigned) {
3960b57cec5SDimitry Andric     Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
397*8bcb0991SDimitry Andric     Register SecondCmpReg =
3980b57cec5SDimitry Andric         MRI.createVirtualRegister(&WebAssembly::I32RegClass);
399*8bcb0991SDimitry Andric     Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
4000b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(FConst), Tmp1)
4010b57cec5SDimitry Andric         .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
4020b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
4030b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
4040b57cec5SDimitry Andric     CmpReg = AndReg;
4050b57cec5SDimitry Andric   }
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   // Create the CFG diamond to select between doing the conversion or using
4100b57cec5SDimitry Andric   // the substitute value.
4110b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
4120b57cec5SDimitry Andric   BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
4130b57cec5SDimitry Andric   BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
4140b57cec5SDimitry Andric   BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
4150b57cec5SDimitry Andric   BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
4160b57cec5SDimitry Andric       .addReg(FalseReg)
4170b57cec5SDimitry Andric       .addMBB(FalseMBB)
4180b57cec5SDimitry Andric       .addReg(TrueReg)
4190b57cec5SDimitry Andric       .addMBB(TrueMBB);
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric   return DoneMBB;
4220b57cec5SDimitry Andric }
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
4250b57cec5SDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB) const {
4260b57cec5SDimitry Andric   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
4270b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric   switch (MI.getOpcode()) {
4300b57cec5SDimitry Andric   default:
4310b57cec5SDimitry Andric     llvm_unreachable("Unexpected instr type to insert");
4320b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I32_F32:
4330b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, false, false,
4340b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_S_F32);
4350b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I32_F32:
4360b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, false, false,
4370b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_U_F32);
4380b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I64_F32:
4390b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, true, false,
4400b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_S_F32);
4410b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I64_F32:
4420b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, true, false,
4430b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_U_F32);
4440b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I32_F64:
4450b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, false, true,
4460b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_S_F64);
4470b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I32_F64:
4480b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, false, true,
4490b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_U_F64);
4500b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I64_F64:
4510b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, true, true,
4520b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_S_F64);
4530b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I64_F64:
4540b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, true, true,
4550b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_U_F64);
4560b57cec5SDimitry Andric     llvm_unreachable("Unexpected instruction to emit with custom inserter");
4570b57cec5SDimitry Andric   }
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric const char *
4610b57cec5SDimitry Andric WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
4620b57cec5SDimitry Andric   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
4630b57cec5SDimitry Andric   case WebAssemblyISD::FIRST_NUMBER:
4640b57cec5SDimitry Andric     break;
4650b57cec5SDimitry Andric #define HANDLE_NODETYPE(NODE)                                                  \
4660b57cec5SDimitry Andric   case WebAssemblyISD::NODE:                                                   \
4670b57cec5SDimitry Andric     return "WebAssemblyISD::" #NODE;
4680b57cec5SDimitry Andric #include "WebAssemblyISD.def"
4690b57cec5SDimitry Andric #undef HANDLE_NODETYPE
4700b57cec5SDimitry Andric   }
4710b57cec5SDimitry Andric   return nullptr;
4720b57cec5SDimitry Andric }
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric std::pair<unsigned, const TargetRegisterClass *>
4750b57cec5SDimitry Andric WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
4760b57cec5SDimitry Andric     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
4770b57cec5SDimitry Andric   // First, see if this is a constraint that directly corresponds to a
4780b57cec5SDimitry Andric   // WebAssembly register class.
4790b57cec5SDimitry Andric   if (Constraint.size() == 1) {
4800b57cec5SDimitry Andric     switch (Constraint[0]) {
4810b57cec5SDimitry Andric     case 'r':
4820b57cec5SDimitry Andric       assert(VT != MVT::iPTR && "Pointer MVT not expected here");
4830b57cec5SDimitry Andric       if (Subtarget->hasSIMD128() && VT.isVector()) {
4840b57cec5SDimitry Andric         if (VT.getSizeInBits() == 128)
4850b57cec5SDimitry Andric           return std::make_pair(0U, &WebAssembly::V128RegClass);
4860b57cec5SDimitry Andric       }
4870b57cec5SDimitry Andric       if (VT.isInteger() && !VT.isVector()) {
4880b57cec5SDimitry Andric         if (VT.getSizeInBits() <= 32)
4890b57cec5SDimitry Andric           return std::make_pair(0U, &WebAssembly::I32RegClass);
4900b57cec5SDimitry Andric         if (VT.getSizeInBits() <= 64)
4910b57cec5SDimitry Andric           return std::make_pair(0U, &WebAssembly::I64RegClass);
4920b57cec5SDimitry Andric       }
4930b57cec5SDimitry Andric       break;
4940b57cec5SDimitry Andric     default:
4950b57cec5SDimitry Andric       break;
4960b57cec5SDimitry Andric     }
4970b57cec5SDimitry Andric   }
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
5030b57cec5SDimitry Andric   // Assume ctz is a relatively cheap operation.
5040b57cec5SDimitry Andric   return true;
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
5080b57cec5SDimitry Andric   // Assume clz is a relatively cheap operation.
5090b57cec5SDimitry Andric   return true;
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
5130b57cec5SDimitry Andric                                                       const AddrMode &AM,
5140b57cec5SDimitry Andric                                                       Type *Ty, unsigned AS,
5150b57cec5SDimitry Andric                                                       Instruction *I) const {
5160b57cec5SDimitry Andric   // WebAssembly offsets are added as unsigned without wrapping. The
5170b57cec5SDimitry Andric   // isLegalAddressingMode gives us no way to determine if wrapping could be
5180b57cec5SDimitry Andric   // happening, so we approximate this by accepting only non-negative offsets.
5190b57cec5SDimitry Andric   if (AM.BaseOffs < 0)
5200b57cec5SDimitry Andric     return false;
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   // WebAssembly has no scale register operands.
5230b57cec5SDimitry Andric   if (AM.Scale != 0)
5240b57cec5SDimitry Andric     return false;
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric   // Everything else is legal.
5270b57cec5SDimitry Andric   return true;
5280b57cec5SDimitry Andric }
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
5310b57cec5SDimitry Andric     EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/,
5320b57cec5SDimitry Andric     MachineMemOperand::Flags /*Flags*/, bool *Fast) const {
5330b57cec5SDimitry Andric   // WebAssembly supports unaligned accesses, though it should be declared
5340b57cec5SDimitry Andric   // with the p2align attribute on loads and stores which do so, and there
5350b57cec5SDimitry Andric   // may be a performance impact. We tell LLVM they're "fast" because
5360b57cec5SDimitry Andric   // for the kinds of things that LLVM uses this for (merging adjacent stores
5370b57cec5SDimitry Andric   // of constants, etc.), WebAssembly implementations will either want the
5380b57cec5SDimitry Andric   // unaligned access or they'll split anyway.
5390b57cec5SDimitry Andric   if (Fast)
5400b57cec5SDimitry Andric     *Fast = true;
5410b57cec5SDimitry Andric   return true;
5420b57cec5SDimitry Andric }
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
5450b57cec5SDimitry Andric                                               AttributeList Attr) const {
5460b57cec5SDimitry Andric   // The current thinking is that wasm engines will perform this optimization,
5470b57cec5SDimitry Andric   // so we can save on code size.
5480b57cec5SDimitry Andric   return true;
5490b57cec5SDimitry Andric }
5500b57cec5SDimitry Andric 
551*8bcb0991SDimitry Andric bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
552*8bcb0991SDimitry Andric   if (!Subtarget->hasUnimplementedSIMD128())
553*8bcb0991SDimitry Andric     return false;
554*8bcb0991SDimitry Andric   MVT ExtT = ExtVal.getSimpleValueType();
555*8bcb0991SDimitry Andric   MVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getSimpleValueType(0);
556*8bcb0991SDimitry Andric   return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
557*8bcb0991SDimitry Andric          (ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
558*8bcb0991SDimitry Andric          (ExtT == MVT::v2i64 && MemT == MVT::v2i32);
559*8bcb0991SDimitry Andric }
560*8bcb0991SDimitry Andric 
5610b57cec5SDimitry Andric EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
5620b57cec5SDimitry Andric                                                   LLVMContext &C,
5630b57cec5SDimitry Andric                                                   EVT VT) const {
5640b57cec5SDimitry Andric   if (VT.isVector())
5650b57cec5SDimitry Andric     return VT.changeVectorElementTypeToInteger();
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric   return TargetLowering::getSetCCResultType(DL, C, VT);
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
5710b57cec5SDimitry Andric                                                    const CallInst &I,
5720b57cec5SDimitry Andric                                                    MachineFunction &MF,
5730b57cec5SDimitry Andric                                                    unsigned Intrinsic) const {
5740b57cec5SDimitry Andric   switch (Intrinsic) {
5750b57cec5SDimitry Andric   case Intrinsic::wasm_atomic_notify:
5760b57cec5SDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
5770b57cec5SDimitry Andric     Info.memVT = MVT::i32;
5780b57cec5SDimitry Andric     Info.ptrVal = I.getArgOperand(0);
5790b57cec5SDimitry Andric     Info.offset = 0;
580*8bcb0991SDimitry Andric     Info.align = Align(4);
5810b57cec5SDimitry Andric     // atomic.notify instruction does not really load the memory specified with
5820b57cec5SDimitry Andric     // this argument, but MachineMemOperand should either be load or store, so
5830b57cec5SDimitry Andric     // we set this to a load.
5840b57cec5SDimitry Andric     // FIXME Volatile isn't really correct, but currently all LLVM atomic
5850b57cec5SDimitry Andric     // instructions are treated as volatiles in the backend, so we should be
5860b57cec5SDimitry Andric     // consistent. The same applies for wasm_atomic_wait intrinsics too.
5870b57cec5SDimitry Andric     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
5880b57cec5SDimitry Andric     return true;
5890b57cec5SDimitry Andric   case Intrinsic::wasm_atomic_wait_i32:
5900b57cec5SDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
5910b57cec5SDimitry Andric     Info.memVT = MVT::i32;
5920b57cec5SDimitry Andric     Info.ptrVal = I.getArgOperand(0);
5930b57cec5SDimitry Andric     Info.offset = 0;
594*8bcb0991SDimitry Andric     Info.align = Align(4);
5950b57cec5SDimitry Andric     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
5960b57cec5SDimitry Andric     return true;
5970b57cec5SDimitry Andric   case Intrinsic::wasm_atomic_wait_i64:
5980b57cec5SDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
5990b57cec5SDimitry Andric     Info.memVT = MVT::i64;
6000b57cec5SDimitry Andric     Info.ptrVal = I.getArgOperand(0);
6010b57cec5SDimitry Andric     Info.offset = 0;
602*8bcb0991SDimitry Andric     Info.align = Align(8);
6030b57cec5SDimitry Andric     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
6040b57cec5SDimitry Andric     return true;
6050b57cec5SDimitry Andric   default:
6060b57cec5SDimitry Andric     return false;
6070b57cec5SDimitry Andric   }
6080b57cec5SDimitry Andric }
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6110b57cec5SDimitry Andric // WebAssembly Lowering private implementation.
6120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6150b57cec5SDimitry Andric // Lowering Code
6160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
6190b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
6200b57cec5SDimitry Andric   DAG.getContext()->diagnose(
6210b57cec5SDimitry Andric       DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
6220b57cec5SDimitry Andric }
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric // Test whether the given calling convention is supported.
6250b57cec5SDimitry Andric static bool callingConvSupported(CallingConv::ID CallConv) {
6260b57cec5SDimitry Andric   // We currently support the language-independent target-independent
6270b57cec5SDimitry Andric   // conventions. We don't yet have a way to annotate calls with properties like
6280b57cec5SDimitry Andric   // "cold", and we don't have any call-clobbered registers, so these are mostly
6290b57cec5SDimitry Andric   // all handled the same.
6300b57cec5SDimitry Andric   return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
6310b57cec5SDimitry Andric          CallConv == CallingConv::Cold ||
6320b57cec5SDimitry Andric          CallConv == CallingConv::PreserveMost ||
6330b57cec5SDimitry Andric          CallConv == CallingConv::PreserveAll ||
634*8bcb0991SDimitry Andric          CallConv == CallingConv::CXX_FAST_TLS ||
635*8bcb0991SDimitry Andric          CallConv == CallingConv::WASM_EmscriptenInvoke;
6360b57cec5SDimitry Andric }
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric SDValue
6390b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
6400b57cec5SDimitry Andric                                      SmallVectorImpl<SDValue> &InVals) const {
6410b57cec5SDimitry Andric   SelectionDAG &DAG = CLI.DAG;
6420b57cec5SDimitry Andric   SDLoc DL = CLI.DL;
6430b57cec5SDimitry Andric   SDValue Chain = CLI.Chain;
6440b57cec5SDimitry Andric   SDValue Callee = CLI.Callee;
6450b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
6460b57cec5SDimitry Andric   auto Layout = MF.getDataLayout();
6470b57cec5SDimitry Andric 
6480b57cec5SDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
6490b57cec5SDimitry Andric   if (!callingConvSupported(CallConv))
6500b57cec5SDimitry Andric     fail(DL, DAG,
6510b57cec5SDimitry Andric          "WebAssembly doesn't support language-specific or target-specific "
6520b57cec5SDimitry Andric          "calling conventions yet");
6530b57cec5SDimitry Andric   if (CLI.IsPatchPoint)
6540b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
6550b57cec5SDimitry Andric 
656*8bcb0991SDimitry Andric   if (CLI.IsTailCall) {
657*8bcb0991SDimitry Andric     bool MustTail = CLI.CS && CLI.CS.isMustTailCall();
658*8bcb0991SDimitry Andric     if (Subtarget->hasTailCall() && !CLI.IsVarArg) {
659*8bcb0991SDimitry Andric       // Do not tail call unless caller and callee return types match
660*8bcb0991SDimitry Andric       const Function &F = MF.getFunction();
661*8bcb0991SDimitry Andric       const TargetMachine &TM = getTargetMachine();
662*8bcb0991SDimitry Andric       Type *RetTy = F.getReturnType();
663*8bcb0991SDimitry Andric       SmallVector<MVT, 4> CallerRetTys;
664*8bcb0991SDimitry Andric       SmallVector<MVT, 4> CalleeRetTys;
665*8bcb0991SDimitry Andric       computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
666*8bcb0991SDimitry Andric       computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys);
667*8bcb0991SDimitry Andric       bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() &&
668*8bcb0991SDimitry Andric                         std::equal(CallerRetTys.begin(), CallerRetTys.end(),
669*8bcb0991SDimitry Andric                                    CalleeRetTys.begin());
670*8bcb0991SDimitry Andric       if (!TypesMatch) {
671*8bcb0991SDimitry Andric         // musttail in this case would be an LLVM IR validation failure
672*8bcb0991SDimitry Andric         assert(!MustTail);
6730b57cec5SDimitry Andric         CLI.IsTailCall = false;
6740b57cec5SDimitry Andric       }
675*8bcb0991SDimitry Andric     } else {
676*8bcb0991SDimitry Andric       CLI.IsTailCall = false;
677*8bcb0991SDimitry Andric       if (MustTail) {
678*8bcb0991SDimitry Andric         if (CLI.IsVarArg) {
679*8bcb0991SDimitry Andric           // The return would pop the argument buffer
680*8bcb0991SDimitry Andric           fail(DL, DAG, "WebAssembly does not support varargs tail calls");
681*8bcb0991SDimitry Andric         } else {
682*8bcb0991SDimitry Andric           fail(DL, DAG, "WebAssembly 'tail-call' feature not enabled");
683*8bcb0991SDimitry Andric         }
684*8bcb0991SDimitry Andric       }
685*8bcb0991SDimitry Andric     }
686*8bcb0991SDimitry Andric   }
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
6890b57cec5SDimitry Andric   if (Ins.size() > 1)
6900b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
6930b57cec5SDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
694*8bcb0991SDimitry Andric 
695*8bcb0991SDimitry Andric   // The generic code may have added an sret argument. If we're lowering an
696*8bcb0991SDimitry Andric   // invoke function, the ABI requires that the function pointer be the first
697*8bcb0991SDimitry Andric   // argument, so we may have to swap the arguments.
698*8bcb0991SDimitry Andric   if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 &&
699*8bcb0991SDimitry Andric       Outs[0].Flags.isSRet()) {
700*8bcb0991SDimitry Andric     std::swap(Outs[0], Outs[1]);
701*8bcb0991SDimitry Andric     std::swap(OutVals[0], OutVals[1]);
702*8bcb0991SDimitry Andric   }
703*8bcb0991SDimitry Andric 
7040b57cec5SDimitry Andric   unsigned NumFixedArgs = 0;
7050b57cec5SDimitry Andric   for (unsigned I = 0; I < Outs.size(); ++I) {
7060b57cec5SDimitry Andric     const ISD::OutputArg &Out = Outs[I];
7070b57cec5SDimitry Andric     SDValue &OutVal = OutVals[I];
7080b57cec5SDimitry Andric     if (Out.Flags.isNest())
7090b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
7100b57cec5SDimitry Andric     if (Out.Flags.isInAlloca())
7110b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
7120b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegs())
7130b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
7140b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegsLast())
7150b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
7160b57cec5SDimitry Andric     if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
7170b57cec5SDimitry Andric       auto &MFI = MF.getFrameInfo();
7180b57cec5SDimitry Andric       int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
7190b57cec5SDimitry Andric                                      Out.Flags.getByValAlign(),
7200b57cec5SDimitry Andric                                      /*isSS=*/false);
7210b57cec5SDimitry Andric       SDValue SizeNode =
7220b57cec5SDimitry Andric           DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
7230b57cec5SDimitry Andric       SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
7240b57cec5SDimitry Andric       Chain = DAG.getMemcpy(
7250b57cec5SDimitry Andric           Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(),
7260b57cec5SDimitry Andric           /*isVolatile*/ false, /*AlwaysInline=*/false,
7270b57cec5SDimitry Andric           /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
7280b57cec5SDimitry Andric       OutVal = FINode;
7290b57cec5SDimitry Andric     }
7300b57cec5SDimitry Andric     // Count the number of fixed args *after* legalization.
7310b57cec5SDimitry Andric     NumFixedArgs += Out.IsFixed;
7320b57cec5SDimitry Andric   }
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric   bool IsVarArg = CLI.IsVarArg;
7350b57cec5SDimitry Andric   auto PtrVT = getPointerTy(Layout);
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   // Analyze operands of the call, assigning locations to each operand.
7380b57cec5SDimitry Andric   SmallVector<CCValAssign, 16> ArgLocs;
7390b57cec5SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
7400b57cec5SDimitry Andric 
7410b57cec5SDimitry Andric   if (IsVarArg) {
7420b57cec5SDimitry Andric     // Outgoing non-fixed arguments are placed in a buffer. First
7430b57cec5SDimitry Andric     // compute their offsets and the total amount of buffer space needed.
7440b57cec5SDimitry Andric     for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
7450b57cec5SDimitry Andric       const ISD::OutputArg &Out = Outs[I];
7460b57cec5SDimitry Andric       SDValue &Arg = OutVals[I];
7470b57cec5SDimitry Andric       EVT VT = Arg.getValueType();
7480b57cec5SDimitry Andric       assert(VT != MVT::iPTR && "Legalized args should be concrete");
7490b57cec5SDimitry Andric       Type *Ty = VT.getTypeForEVT(*DAG.getContext());
7500b57cec5SDimitry Andric       unsigned Align = std::max(Out.Flags.getOrigAlign(),
7510b57cec5SDimitry Andric                                 Layout.getABITypeAlignment(Ty));
7520b57cec5SDimitry Andric       unsigned Offset = CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty),
7530b57cec5SDimitry Andric                                              Align);
7540b57cec5SDimitry Andric       CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
7550b57cec5SDimitry Andric                                         Offset, VT.getSimpleVT(),
7560b57cec5SDimitry Andric                                         CCValAssign::Full));
7570b57cec5SDimitry Andric     }
7580b57cec5SDimitry Andric   }
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric   unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric   SDValue FINode;
7630b57cec5SDimitry Andric   if (IsVarArg && NumBytes) {
7640b57cec5SDimitry Andric     // For non-fixed arguments, next emit stores to store the argument values
7650b57cec5SDimitry Andric     // to the stack buffer at the offsets computed above.
7660b57cec5SDimitry Andric     int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
7670b57cec5SDimitry Andric                                                  Layout.getStackAlignment(),
7680b57cec5SDimitry Andric                                                  /*isSS=*/false);
7690b57cec5SDimitry Andric     unsigned ValNo = 0;
7700b57cec5SDimitry Andric     SmallVector<SDValue, 8> Chains;
7710b57cec5SDimitry Andric     for (SDValue Arg :
7720b57cec5SDimitry Andric          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
7730b57cec5SDimitry Andric       assert(ArgLocs[ValNo].getValNo() == ValNo &&
7740b57cec5SDimitry Andric              "ArgLocs should remain in order and only hold varargs args");
7750b57cec5SDimitry Andric       unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
7760b57cec5SDimitry Andric       FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
7770b57cec5SDimitry Andric       SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
7780b57cec5SDimitry Andric                                 DAG.getConstant(Offset, DL, PtrVT));
7790b57cec5SDimitry Andric       Chains.push_back(
7800b57cec5SDimitry Andric           DAG.getStore(Chain, DL, Arg, Add,
7810b57cec5SDimitry Andric                        MachinePointerInfo::getFixedStack(MF, FI, Offset), 0));
7820b57cec5SDimitry Andric     }
7830b57cec5SDimitry Andric     if (!Chains.empty())
7840b57cec5SDimitry Andric       Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
7850b57cec5SDimitry Andric   } else if (IsVarArg) {
7860b57cec5SDimitry Andric     FINode = DAG.getIntPtrConstant(0, DL);
7870b57cec5SDimitry Andric   }
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   if (Callee->getOpcode() == ISD::GlobalAddress) {
7900b57cec5SDimitry Andric     // If the callee is a GlobalAddress node (quite common, every direct call
7910b57cec5SDimitry Andric     // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
7920b57cec5SDimitry Andric     // doesn't at MO_GOT which is not needed for direct calls.
7930b57cec5SDimitry Andric     GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee);
7940b57cec5SDimitry Andric     Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL,
7950b57cec5SDimitry Andric                                         getPointerTy(DAG.getDataLayout()),
7960b57cec5SDimitry Andric                                         GA->getOffset());
7970b57cec5SDimitry Andric     Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
7980b57cec5SDimitry Andric                          getPointerTy(DAG.getDataLayout()), Callee);
7990b57cec5SDimitry Andric   }
8000b57cec5SDimitry Andric 
8010b57cec5SDimitry Andric   // Compute the operands for the CALLn node.
8020b57cec5SDimitry Andric   SmallVector<SDValue, 16> Ops;
8030b57cec5SDimitry Andric   Ops.push_back(Chain);
8040b57cec5SDimitry Andric   Ops.push_back(Callee);
8050b57cec5SDimitry Andric 
8060b57cec5SDimitry Andric   // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
8070b57cec5SDimitry Andric   // isn't reliable.
8080b57cec5SDimitry Andric   Ops.append(OutVals.begin(),
8090b57cec5SDimitry Andric              IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
8100b57cec5SDimitry Andric   // Add a pointer to the vararg buffer.
8110b57cec5SDimitry Andric   if (IsVarArg)
8120b57cec5SDimitry Andric     Ops.push_back(FINode);
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric   SmallVector<EVT, 8> InTys;
8150b57cec5SDimitry Andric   for (const auto &In : Ins) {
8160b57cec5SDimitry Andric     assert(!In.Flags.isByVal() && "byval is not valid for return values");
8170b57cec5SDimitry Andric     assert(!In.Flags.isNest() && "nest is not valid for return values");
8180b57cec5SDimitry Andric     if (In.Flags.isInAlloca())
8190b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
8200b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegs())
8210b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
8220b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegsLast())
8230b57cec5SDimitry Andric       fail(DL, DAG,
8240b57cec5SDimitry Andric            "WebAssembly hasn't implemented cons regs last return values");
8250b57cec5SDimitry Andric     // Ignore In.getOrigAlign() because all our arguments are passed in
8260b57cec5SDimitry Andric     // registers.
8270b57cec5SDimitry Andric     InTys.push_back(In.VT);
8280b57cec5SDimitry Andric   }
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric   if (CLI.IsTailCall) {
8310b57cec5SDimitry Andric     // ret_calls do not return values to the current frame
8320b57cec5SDimitry Andric     SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
8330b57cec5SDimitry Andric     return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops);
8340b57cec5SDimitry Andric   }
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   InTys.push_back(MVT::Other);
8370b57cec5SDimitry Andric   SDVTList InTyList = DAG.getVTList(InTys);
8380b57cec5SDimitry Andric   SDValue Res =
8390b57cec5SDimitry Andric       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
8400b57cec5SDimitry Andric                   DL, InTyList, Ops);
8410b57cec5SDimitry Andric   if (Ins.empty()) {
8420b57cec5SDimitry Andric     Chain = Res;
8430b57cec5SDimitry Andric   } else {
8440b57cec5SDimitry Andric     InVals.push_back(Res);
8450b57cec5SDimitry Andric     Chain = Res.getValue(1);
8460b57cec5SDimitry Andric   }
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric   return Chain;
8490b57cec5SDimitry Andric }
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric bool WebAssemblyTargetLowering::CanLowerReturn(
8520b57cec5SDimitry Andric     CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
8530b57cec5SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
8540b57cec5SDimitry Andric     LLVMContext & /*Context*/) const {
855*8bcb0991SDimitry Andric   // WebAssembly can only handle returning tuples with multivalue enabled
856*8bcb0991SDimitry Andric   return Subtarget->hasMultivalue() || Outs.size() <= 1;
8570b57cec5SDimitry Andric }
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerReturn(
8600b57cec5SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
8610b57cec5SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
8620b57cec5SDimitry Andric     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
8630b57cec5SDimitry Andric     SelectionDAG &DAG) const {
864*8bcb0991SDimitry Andric   assert((Subtarget->hasMultivalue() || Outs.size() <= 1) &&
865*8bcb0991SDimitry Andric          "MVP WebAssembly can only return up to one value");
8660b57cec5SDimitry Andric   if (!callingConvSupported(CallConv))
8670b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
8680b57cec5SDimitry Andric 
8690b57cec5SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
8700b57cec5SDimitry Andric   RetOps.append(OutVals.begin(), OutVals.end());
8710b57cec5SDimitry Andric   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric   // Record the number and types of the return values.
8740b57cec5SDimitry Andric   for (const ISD::OutputArg &Out : Outs) {
8750b57cec5SDimitry Andric     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
8760b57cec5SDimitry Andric     assert(!Out.Flags.isNest() && "nest is not valid for return values");
8770b57cec5SDimitry Andric     assert(Out.IsFixed && "non-fixed return value is not valid");
8780b57cec5SDimitry Andric     if (Out.Flags.isInAlloca())
8790b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
8800b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegs())
8810b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
8820b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegsLast())
8830b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
8840b57cec5SDimitry Andric   }
8850b57cec5SDimitry Andric 
8860b57cec5SDimitry Andric   return Chain;
8870b57cec5SDimitry Andric }
8880b57cec5SDimitry Andric 
8890b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFormalArguments(
8900b57cec5SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
8910b57cec5SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
8920b57cec5SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
8930b57cec5SDimitry Andric   if (!callingConvSupported(CallConv))
8940b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
8970b57cec5SDimitry Andric   auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
8980b57cec5SDimitry Andric 
8990b57cec5SDimitry Andric   // Set up the incoming ARGUMENTS value, which serves to represent the liveness
9000b57cec5SDimitry Andric   // of the incoming values before they're represented by virtual registers.
9010b57cec5SDimitry Andric   MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
9020b57cec5SDimitry Andric 
9030b57cec5SDimitry Andric   for (const ISD::InputArg &In : Ins) {
9040b57cec5SDimitry Andric     if (In.Flags.isInAlloca())
9050b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
9060b57cec5SDimitry Andric     if (In.Flags.isNest())
9070b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
9080b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegs())
9090b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
9100b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegsLast())
9110b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
9120b57cec5SDimitry Andric     // Ignore In.getOrigAlign() because all our arguments are passed in
9130b57cec5SDimitry Andric     // registers.
9140b57cec5SDimitry Andric     InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
9150b57cec5SDimitry Andric                                            DAG.getTargetConstant(InVals.size(),
9160b57cec5SDimitry Andric                                                                  DL, MVT::i32))
9170b57cec5SDimitry Andric                              : DAG.getUNDEF(In.VT));
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric     // Record the number and types of arguments.
9200b57cec5SDimitry Andric     MFI->addParam(In.VT);
9210b57cec5SDimitry Andric   }
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric   // Varargs are copied into a buffer allocated by the caller, and a pointer to
9240b57cec5SDimitry Andric   // the buffer is passed as an argument.
9250b57cec5SDimitry Andric   if (IsVarArg) {
9260b57cec5SDimitry Andric     MVT PtrVT = getPointerTy(MF.getDataLayout());
927*8bcb0991SDimitry Andric     Register VarargVreg =
9280b57cec5SDimitry Andric         MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT));
9290b57cec5SDimitry Andric     MFI->setVarargBufferVreg(VarargVreg);
9300b57cec5SDimitry Andric     Chain = DAG.getCopyToReg(
9310b57cec5SDimitry Andric         Chain, DL, VarargVreg,
9320b57cec5SDimitry Andric         DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
9330b57cec5SDimitry Andric                     DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
9340b57cec5SDimitry Andric     MFI->addParam(PtrVT);
9350b57cec5SDimitry Andric   }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric   // Record the number and types of arguments and results.
9380b57cec5SDimitry Andric   SmallVector<MVT, 4> Params;
9390b57cec5SDimitry Andric   SmallVector<MVT, 4> Results;
9400b57cec5SDimitry Andric   computeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(),
9410b57cec5SDimitry Andric                       DAG.getTarget(), Params, Results);
9420b57cec5SDimitry Andric   for (MVT VT : Results)
9430b57cec5SDimitry Andric     MFI->addResult(VT);
9440b57cec5SDimitry Andric   // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
9450b57cec5SDimitry Andric   // the param logic here with ComputeSignatureVTs
9460b57cec5SDimitry Andric   assert(MFI->getParams().size() == Params.size() &&
9470b57cec5SDimitry Andric          std::equal(MFI->getParams().begin(), MFI->getParams().end(),
9480b57cec5SDimitry Andric                     Params.begin()));
9490b57cec5SDimitry Andric 
9500b57cec5SDimitry Andric   return Chain;
9510b57cec5SDimitry Andric }
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric void WebAssemblyTargetLowering::ReplaceNodeResults(
9540b57cec5SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
9550b57cec5SDimitry Andric   switch (N->getOpcode()) {
9560b57cec5SDimitry Andric   case ISD::SIGN_EXTEND_INREG:
9570b57cec5SDimitry Andric     // Do not add any results, signifying that N should not be custom lowered
9580b57cec5SDimitry Andric     // after all. This happens because simd128 turns on custom lowering for
9590b57cec5SDimitry Andric     // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
9600b57cec5SDimitry Andric     // illegal type.
9610b57cec5SDimitry Andric     break;
9620b57cec5SDimitry Andric   default:
9630b57cec5SDimitry Andric     llvm_unreachable(
9640b57cec5SDimitry Andric         "ReplaceNodeResults not implemented for this op for WebAssembly!");
9650b57cec5SDimitry Andric   }
9660b57cec5SDimitry Andric }
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
9690b57cec5SDimitry Andric //  Custom lowering hooks.
9700b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
9710b57cec5SDimitry Andric 
9720b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
9730b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
9740b57cec5SDimitry Andric   SDLoc DL(Op);
9750b57cec5SDimitry Andric   switch (Op.getOpcode()) {
9760b57cec5SDimitry Andric   default:
9770b57cec5SDimitry Andric     llvm_unreachable("unimplemented operation lowering");
9780b57cec5SDimitry Andric     return SDValue();
9790b57cec5SDimitry Andric   case ISD::FrameIndex:
9800b57cec5SDimitry Andric     return LowerFrameIndex(Op, DAG);
9810b57cec5SDimitry Andric   case ISD::GlobalAddress:
9820b57cec5SDimitry Andric     return LowerGlobalAddress(Op, DAG);
9830b57cec5SDimitry Andric   case ISD::ExternalSymbol:
9840b57cec5SDimitry Andric     return LowerExternalSymbol(Op, DAG);
9850b57cec5SDimitry Andric   case ISD::JumpTable:
9860b57cec5SDimitry Andric     return LowerJumpTable(Op, DAG);
9870b57cec5SDimitry Andric   case ISD::BR_JT:
9880b57cec5SDimitry Andric     return LowerBR_JT(Op, DAG);
9890b57cec5SDimitry Andric   case ISD::VASTART:
9900b57cec5SDimitry Andric     return LowerVASTART(Op, DAG);
9910b57cec5SDimitry Andric   case ISD::BlockAddress:
9920b57cec5SDimitry Andric   case ISD::BRIND:
9930b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
9940b57cec5SDimitry Andric     return SDValue();
9950b57cec5SDimitry Andric   case ISD::RETURNADDR:
9960b57cec5SDimitry Andric     return LowerRETURNADDR(Op, DAG);
9970b57cec5SDimitry Andric   case ISD::FRAMEADDR:
9980b57cec5SDimitry Andric     return LowerFRAMEADDR(Op, DAG);
9990b57cec5SDimitry Andric   case ISD::CopyToReg:
10000b57cec5SDimitry Andric     return LowerCopyToReg(Op, DAG);
10010b57cec5SDimitry Andric   case ISD::EXTRACT_VECTOR_ELT:
10020b57cec5SDimitry Andric   case ISD::INSERT_VECTOR_ELT:
10030b57cec5SDimitry Andric     return LowerAccessVectorElement(Op, DAG);
10040b57cec5SDimitry Andric   case ISD::INTRINSIC_VOID:
10050b57cec5SDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
10060b57cec5SDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
10070b57cec5SDimitry Andric     return LowerIntrinsic(Op, DAG);
10080b57cec5SDimitry Andric   case ISD::SIGN_EXTEND_INREG:
10090b57cec5SDimitry Andric     return LowerSIGN_EXTEND_INREG(Op, DAG);
10100b57cec5SDimitry Andric   case ISD::BUILD_VECTOR:
10110b57cec5SDimitry Andric     return LowerBUILD_VECTOR(Op, DAG);
10120b57cec5SDimitry Andric   case ISD::VECTOR_SHUFFLE:
10130b57cec5SDimitry Andric     return LowerVECTOR_SHUFFLE(Op, DAG);
10140b57cec5SDimitry Andric   case ISD::SHL:
10150b57cec5SDimitry Andric   case ISD::SRA:
10160b57cec5SDimitry Andric   case ISD::SRL:
10170b57cec5SDimitry Andric     return LowerShift(Op, DAG);
10180b57cec5SDimitry Andric   }
10190b57cec5SDimitry Andric }
10200b57cec5SDimitry Andric 
10210b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
10220b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
10230b57cec5SDimitry Andric   SDValue Src = Op.getOperand(2);
10240b57cec5SDimitry Andric   if (isa<FrameIndexSDNode>(Src.getNode())) {
10250b57cec5SDimitry Andric     // CopyToReg nodes don't support FrameIndex operands. Other targets select
10260b57cec5SDimitry Andric     // the FI to some LEA-like instruction, but since we don't have that, we
10270b57cec5SDimitry Andric     // need to insert some kind of instruction that can take an FI operand and
10280b57cec5SDimitry Andric     // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
10290b57cec5SDimitry Andric     // local.copy between Op and its FI operand.
10300b57cec5SDimitry Andric     SDValue Chain = Op.getOperand(0);
10310b57cec5SDimitry Andric     SDLoc DL(Op);
10320b57cec5SDimitry Andric     unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
10330b57cec5SDimitry Andric     EVT VT = Src.getValueType();
10340b57cec5SDimitry Andric     SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
10350b57cec5SDimitry Andric                                                    : WebAssembly::COPY_I64,
10360b57cec5SDimitry Andric                                     DL, VT, Src),
10370b57cec5SDimitry Andric                  0);
10380b57cec5SDimitry Andric     return Op.getNode()->getNumValues() == 1
10390b57cec5SDimitry Andric                ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
10400b57cec5SDimitry Andric                : DAG.getCopyToReg(Chain, DL, Reg, Copy,
10410b57cec5SDimitry Andric                                   Op.getNumOperands() == 4 ? Op.getOperand(3)
10420b57cec5SDimitry Andric                                                            : SDValue());
10430b57cec5SDimitry Andric   }
10440b57cec5SDimitry Andric   return SDValue();
10450b57cec5SDimitry Andric }
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
10480b57cec5SDimitry Andric                                                    SelectionDAG &DAG) const {
10490b57cec5SDimitry Andric   int FI = cast<FrameIndexSDNode>(Op)->getIndex();
10500b57cec5SDimitry Andric   return DAG.getTargetFrameIndex(FI, Op.getValueType());
10510b57cec5SDimitry Andric }
10520b57cec5SDimitry Andric 
10530b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op,
10540b57cec5SDimitry Andric                                                    SelectionDAG &DAG) const {
10550b57cec5SDimitry Andric   SDLoc DL(Op);
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric   if (!Subtarget->getTargetTriple().isOSEmscripten()) {
10580b57cec5SDimitry Andric     fail(DL, DAG,
10590b57cec5SDimitry Andric          "Non-Emscripten WebAssembly hasn't implemented "
10600b57cec5SDimitry Andric          "__builtin_return_address");
10610b57cec5SDimitry Andric     return SDValue();
10620b57cec5SDimitry Andric   }
10630b57cec5SDimitry Andric 
10640b57cec5SDimitry Andric   if (verifyReturnAddressArgumentIsConstant(Op, DAG))
10650b57cec5SDimitry Andric     return SDValue();
10660b57cec5SDimitry Andric 
10670b57cec5SDimitry Andric   unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
1068*8bcb0991SDimitry Andric   MakeLibCallOptions CallOptions;
10690b57cec5SDimitry Andric   return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(),
1070*8bcb0991SDimitry Andric                      {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL)
10710b57cec5SDimitry Andric       .first;
10720b57cec5SDimitry Andric }
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
10750b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
10760b57cec5SDimitry Andric   // Non-zero depths are not supported by WebAssembly currently. Use the
10770b57cec5SDimitry Andric   // legalizer's default expansion, which is to return 0 (what this function is
10780b57cec5SDimitry Andric   // documented to do).
10790b57cec5SDimitry Andric   if (Op.getConstantOperandVal(0) > 0)
10800b57cec5SDimitry Andric     return SDValue();
10810b57cec5SDimitry Andric 
10820b57cec5SDimitry Andric   DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
10830b57cec5SDimitry Andric   EVT VT = Op.getValueType();
1084*8bcb0991SDimitry Andric   Register FP =
10850b57cec5SDimitry Andric       Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
10860b57cec5SDimitry Andric   return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
10870b57cec5SDimitry Andric }
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
10900b57cec5SDimitry Andric                                                       SelectionDAG &DAG) const {
10910b57cec5SDimitry Andric   SDLoc DL(Op);
10920b57cec5SDimitry Andric   const auto *GA = cast<GlobalAddressSDNode>(Op);
10930b57cec5SDimitry Andric   EVT VT = Op.getValueType();
10940b57cec5SDimitry Andric   assert(GA->getTargetFlags() == 0 &&
10950b57cec5SDimitry Andric          "Unexpected target flags on generic GlobalAddressSDNode");
10960b57cec5SDimitry Andric   if (GA->getAddressSpace() != 0)
10970b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly only expects the 0 address space");
10980b57cec5SDimitry Andric 
10990b57cec5SDimitry Andric   unsigned OperandFlags = 0;
11000b57cec5SDimitry Andric   if (isPositionIndependent()) {
11010b57cec5SDimitry Andric     const GlobalValue *GV = GA->getGlobal();
11020b57cec5SDimitry Andric     if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) {
11030b57cec5SDimitry Andric       MachineFunction &MF = DAG.getMachineFunction();
11040b57cec5SDimitry Andric       MVT PtrVT = getPointerTy(MF.getDataLayout());
11050b57cec5SDimitry Andric       const char *BaseName;
11060b57cec5SDimitry Andric       if (GV->getValueType()->isFunctionTy()) {
11070b57cec5SDimitry Andric         BaseName = MF.createExternalSymbolName("__table_base");
11080b57cec5SDimitry Andric         OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL;
11090b57cec5SDimitry Andric       }
11100b57cec5SDimitry Andric       else {
11110b57cec5SDimitry Andric         BaseName = MF.createExternalSymbolName("__memory_base");
11120b57cec5SDimitry Andric         OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL;
11130b57cec5SDimitry Andric       }
11140b57cec5SDimitry Andric       SDValue BaseAddr =
11150b57cec5SDimitry Andric           DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
11160b57cec5SDimitry Andric                       DAG.getTargetExternalSymbol(BaseName, PtrVT));
11170b57cec5SDimitry Andric 
11180b57cec5SDimitry Andric       SDValue SymAddr = DAG.getNode(
11190b57cec5SDimitry Andric           WebAssemblyISD::WrapperPIC, DL, VT,
11200b57cec5SDimitry Andric           DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
11210b57cec5SDimitry Andric                                      OperandFlags));
11220b57cec5SDimitry Andric 
11230b57cec5SDimitry Andric       return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
11240b57cec5SDimitry Andric     } else {
11250b57cec5SDimitry Andric       OperandFlags = WebAssemblyII::MO_GOT;
11260b57cec5SDimitry Andric     }
11270b57cec5SDimitry Andric   }
11280b57cec5SDimitry Andric 
11290b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
11300b57cec5SDimitry Andric                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
11310b57cec5SDimitry Andric                                                 GA->getOffset(), OperandFlags));
11320b57cec5SDimitry Andric }
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric SDValue
11350b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
11360b57cec5SDimitry Andric                                                SelectionDAG &DAG) const {
11370b57cec5SDimitry Andric   SDLoc DL(Op);
11380b57cec5SDimitry Andric   const auto *ES = cast<ExternalSymbolSDNode>(Op);
11390b57cec5SDimitry Andric   EVT VT = Op.getValueType();
11400b57cec5SDimitry Andric   assert(ES->getTargetFlags() == 0 &&
11410b57cec5SDimitry Andric          "Unexpected target flags on generic ExternalSymbolSDNode");
11420b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
11430b57cec5SDimitry Andric                      DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
11440b57cec5SDimitry Andric }
11450b57cec5SDimitry Andric 
11460b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
11470b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
11480b57cec5SDimitry Andric   // There's no need for a Wrapper node because we always incorporate a jump
11490b57cec5SDimitry Andric   // table operand into a BR_TABLE instruction, rather than ever
11500b57cec5SDimitry Andric   // materializing it in a register.
11510b57cec5SDimitry Andric   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
11520b57cec5SDimitry Andric   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
11530b57cec5SDimitry Andric                                 JT->getTargetFlags());
11540b57cec5SDimitry Andric }
11550b57cec5SDimitry Andric 
11560b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
11570b57cec5SDimitry Andric                                               SelectionDAG &DAG) const {
11580b57cec5SDimitry Andric   SDLoc DL(Op);
11590b57cec5SDimitry Andric   SDValue Chain = Op.getOperand(0);
11600b57cec5SDimitry Andric   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
11610b57cec5SDimitry Andric   SDValue Index = Op.getOperand(2);
11620b57cec5SDimitry Andric   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
11630b57cec5SDimitry Andric 
11640b57cec5SDimitry Andric   SmallVector<SDValue, 8> Ops;
11650b57cec5SDimitry Andric   Ops.push_back(Chain);
11660b57cec5SDimitry Andric   Ops.push_back(Index);
11670b57cec5SDimitry Andric 
11680b57cec5SDimitry Andric   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
11690b57cec5SDimitry Andric   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
11700b57cec5SDimitry Andric 
11710b57cec5SDimitry Andric   // Add an operand for each case.
11720b57cec5SDimitry Andric   for (auto MBB : MBBs)
11730b57cec5SDimitry Andric     Ops.push_back(DAG.getBasicBlock(MBB));
11740b57cec5SDimitry Andric 
11750b57cec5SDimitry Andric   // TODO: For now, we just pick something arbitrary for a default case for now.
11760b57cec5SDimitry Andric   // We really want to sniff out the guard and put in the real default case (and
11770b57cec5SDimitry Andric   // delete the guard).
11780b57cec5SDimitry Andric   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
11840b57cec5SDimitry Andric                                                 SelectionDAG &DAG) const {
11850b57cec5SDimitry Andric   SDLoc DL(Op);
11860b57cec5SDimitry Andric   EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
11870b57cec5SDimitry Andric 
11880b57cec5SDimitry Andric   auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
11890b57cec5SDimitry Andric   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
11900b57cec5SDimitry Andric 
11910b57cec5SDimitry Andric   SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
11920b57cec5SDimitry Andric                                     MFI->getVarargBufferVreg(), PtrVT);
11930b57cec5SDimitry Andric   return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
11940b57cec5SDimitry Andric                       MachinePointerInfo(SV), 0);
11950b57cec5SDimitry Andric }
11960b57cec5SDimitry Andric 
11970b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
11980b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
11990b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
12000b57cec5SDimitry Andric   unsigned IntNo;
12010b57cec5SDimitry Andric   switch (Op.getOpcode()) {
12020b57cec5SDimitry Andric   case ISD::INTRINSIC_VOID:
12030b57cec5SDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
12040b57cec5SDimitry Andric     IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
12050b57cec5SDimitry Andric     break;
12060b57cec5SDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
12070b57cec5SDimitry Andric     IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
12080b57cec5SDimitry Andric     break;
12090b57cec5SDimitry Andric   default:
12100b57cec5SDimitry Andric     llvm_unreachable("Invalid intrinsic");
12110b57cec5SDimitry Andric   }
12120b57cec5SDimitry Andric   SDLoc DL(Op);
12130b57cec5SDimitry Andric 
12140b57cec5SDimitry Andric   switch (IntNo) {
12150b57cec5SDimitry Andric   default:
12160b57cec5SDimitry Andric     return SDValue(); // Don't custom lower most intrinsics.
12170b57cec5SDimitry Andric 
12180b57cec5SDimitry Andric   case Intrinsic::wasm_lsda: {
12190b57cec5SDimitry Andric     EVT VT = Op.getValueType();
12200b57cec5SDimitry Andric     const TargetLowering &TLI = DAG.getTargetLoweringInfo();
12210b57cec5SDimitry Andric     MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
12220b57cec5SDimitry Andric     auto &Context = MF.getMMI().getContext();
12230b57cec5SDimitry Andric     MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
12240b57cec5SDimitry Andric                                             Twine(MF.getFunctionNumber()));
12250b57cec5SDimitry Andric     return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
12260b57cec5SDimitry Andric                        DAG.getMCSymbol(S, PtrVT));
12270b57cec5SDimitry Andric   }
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric   case Intrinsic::wasm_throw: {
12300b57cec5SDimitry Andric     // We only support C++ exceptions for now
12310b57cec5SDimitry Andric     int Tag = cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
12320b57cec5SDimitry Andric     if (Tag != CPP_EXCEPTION)
12330b57cec5SDimitry Andric       llvm_unreachable("Invalid tag!");
12340b57cec5SDimitry Andric     const TargetLowering &TLI = DAG.getTargetLoweringInfo();
12350b57cec5SDimitry Andric     MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
12360b57cec5SDimitry Andric     const char *SymName = MF.createExternalSymbolName("__cpp_exception");
12370b57cec5SDimitry Andric     SDValue SymNode = DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
12380b57cec5SDimitry Andric                                   DAG.getTargetExternalSymbol(SymName, PtrVT));
12390b57cec5SDimitry Andric     return DAG.getNode(WebAssemblyISD::THROW, DL,
12400b57cec5SDimitry Andric                        MVT::Other, // outchain type
12410b57cec5SDimitry Andric                        {
12420b57cec5SDimitry Andric                            Op.getOperand(0), // inchain
12430b57cec5SDimitry Andric                            SymNode,          // exception symbol
12440b57cec5SDimitry Andric                            Op.getOperand(3)  // thrown value
12450b57cec5SDimitry Andric                        });
12460b57cec5SDimitry Andric   }
12470b57cec5SDimitry Andric   }
12480b57cec5SDimitry Andric }
12490b57cec5SDimitry Andric 
12500b57cec5SDimitry Andric SDValue
12510b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
12520b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
12530b57cec5SDimitry Andric   SDLoc DL(Op);
12540b57cec5SDimitry Andric   // If sign extension operations are disabled, allow sext_inreg only if operand
12550b57cec5SDimitry Andric   // is a vector extract. SIMD does not depend on sign extension operations, but
12560b57cec5SDimitry Andric   // allowing sext_inreg in this context lets us have simple patterns to select
12570b57cec5SDimitry Andric   // extract_lane_s instructions. Expanding sext_inreg everywhere would be
12580b57cec5SDimitry Andric   // simpler in this file, but would necessitate large and brittle patterns to
12590b57cec5SDimitry Andric   // undo the expansion and select extract_lane_s instructions.
12600b57cec5SDimitry Andric   assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
12610b57cec5SDimitry Andric   if (Op.getOperand(0).getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
12620b57cec5SDimitry Andric     const SDValue &Extract = Op.getOperand(0);
12630b57cec5SDimitry Andric     MVT VecT = Extract.getOperand(0).getSimpleValueType();
12640b57cec5SDimitry Andric     MVT ExtractedLaneT = static_cast<VTSDNode *>(Op.getOperand(1).getNode())
12650b57cec5SDimitry Andric                              ->getVT()
12660b57cec5SDimitry Andric                              .getSimpleVT();
12670b57cec5SDimitry Andric     MVT ExtractedVecT =
12680b57cec5SDimitry Andric         MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits());
12690b57cec5SDimitry Andric     if (ExtractedVecT == VecT)
12700b57cec5SDimitry Andric       return Op;
12710b57cec5SDimitry Andric     // Bitcast vector to appropriate type to ensure ISel pattern coverage
12720b57cec5SDimitry Andric     const SDValue &Index = Extract.getOperand(1);
12730b57cec5SDimitry Andric     unsigned IndexVal =
12740b57cec5SDimitry Andric         static_cast<ConstantSDNode *>(Index.getNode())->getZExtValue();
12750b57cec5SDimitry Andric     unsigned Scale =
12760b57cec5SDimitry Andric         ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements();
12770b57cec5SDimitry Andric     assert(Scale > 1);
12780b57cec5SDimitry Andric     SDValue NewIndex =
12790b57cec5SDimitry Andric         DAG.getConstant(IndexVal * Scale, DL, Index.getValueType());
12800b57cec5SDimitry Andric     SDValue NewExtract = DAG.getNode(
12810b57cec5SDimitry Andric         ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(),
12820b57cec5SDimitry Andric         DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex);
12830b57cec5SDimitry Andric     return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(),
12840b57cec5SDimitry Andric                        NewExtract, Op.getOperand(1));
12850b57cec5SDimitry Andric   }
12860b57cec5SDimitry Andric   // Otherwise expand
12870b57cec5SDimitry Andric   return SDValue();
12880b57cec5SDimitry Andric }
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
12910b57cec5SDimitry Andric                                                      SelectionDAG &DAG) const {
12920b57cec5SDimitry Andric   SDLoc DL(Op);
12930b57cec5SDimitry Andric   const EVT VecT = Op.getValueType();
12940b57cec5SDimitry Andric   const EVT LaneT = Op.getOperand(0).getValueType();
12950b57cec5SDimitry Andric   const size_t Lanes = Op.getNumOperands();
1296*8bcb0991SDimitry Andric   bool CanSwizzle = Subtarget->hasUnimplementedSIMD128() && VecT == MVT::v16i8;
1297*8bcb0991SDimitry Andric 
1298*8bcb0991SDimitry Andric   // BUILD_VECTORs are lowered to the instruction that initializes the highest
1299*8bcb0991SDimitry Andric   // possible number of lanes at once followed by a sequence of replace_lane
1300*8bcb0991SDimitry Andric   // instructions to individually initialize any remaining lanes.
1301*8bcb0991SDimitry Andric 
1302*8bcb0991SDimitry Andric   // TODO: Tune this. For example, lanewise swizzling is very expensive, so
1303*8bcb0991SDimitry Andric   // swizzled lanes should be given greater weight.
1304*8bcb0991SDimitry Andric 
1305*8bcb0991SDimitry Andric   // TODO: Investigate building vectors by shuffling together vectors built by
1306*8bcb0991SDimitry Andric   // separately specialized means.
1307*8bcb0991SDimitry Andric 
13080b57cec5SDimitry Andric   auto IsConstant = [](const SDValue &V) {
13090b57cec5SDimitry Andric     return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
13100b57cec5SDimitry Andric   };
13110b57cec5SDimitry Andric 
1312*8bcb0991SDimitry Andric   // Returns the source vector and index vector pair if they exist. Checks for:
1313*8bcb0991SDimitry Andric   //   (extract_vector_elt
1314*8bcb0991SDimitry Andric   //     $src,
1315*8bcb0991SDimitry Andric   //     (sign_extend_inreg (extract_vector_elt $indices, $i))
1316*8bcb0991SDimitry Andric   //   )
1317*8bcb0991SDimitry Andric   auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) {
1318*8bcb0991SDimitry Andric     auto Bail = std::make_pair(SDValue(), SDValue());
1319*8bcb0991SDimitry Andric     if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
1320*8bcb0991SDimitry Andric       return Bail;
1321*8bcb0991SDimitry Andric     const SDValue &SwizzleSrc = Lane->getOperand(0);
1322*8bcb0991SDimitry Andric     const SDValue &IndexExt = Lane->getOperand(1);
1323*8bcb0991SDimitry Andric     if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG)
1324*8bcb0991SDimitry Andric       return Bail;
1325*8bcb0991SDimitry Andric     const SDValue &Index = IndexExt->getOperand(0);
1326*8bcb0991SDimitry Andric     if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
1327*8bcb0991SDimitry Andric       return Bail;
1328*8bcb0991SDimitry Andric     const SDValue &SwizzleIndices = Index->getOperand(0);
1329*8bcb0991SDimitry Andric     if (SwizzleSrc.getValueType() != MVT::v16i8 ||
1330*8bcb0991SDimitry Andric         SwizzleIndices.getValueType() != MVT::v16i8 ||
1331*8bcb0991SDimitry Andric         Index->getOperand(1)->getOpcode() != ISD::Constant ||
1332*8bcb0991SDimitry Andric         Index->getConstantOperandVal(1) != I)
1333*8bcb0991SDimitry Andric       return Bail;
1334*8bcb0991SDimitry Andric     return std::make_pair(SwizzleSrc, SwizzleIndices);
1335*8bcb0991SDimitry Andric   };
1336*8bcb0991SDimitry Andric 
1337*8bcb0991SDimitry Andric   using ValueEntry = std::pair<SDValue, size_t>;
1338*8bcb0991SDimitry Andric   SmallVector<ValueEntry, 16> SplatValueCounts;
1339*8bcb0991SDimitry Andric 
1340*8bcb0991SDimitry Andric   using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>;
1341*8bcb0991SDimitry Andric   SmallVector<SwizzleEntry, 16> SwizzleCounts;
1342*8bcb0991SDimitry Andric 
1343*8bcb0991SDimitry Andric   auto AddCount = [](auto &Counts, const auto &Val) {
1344*8bcb0991SDimitry Andric     auto CountIt = std::find_if(Counts.begin(), Counts.end(),
1345*8bcb0991SDimitry Andric                                 [&Val](auto E) { return E.first == Val; });
1346*8bcb0991SDimitry Andric     if (CountIt == Counts.end()) {
1347*8bcb0991SDimitry Andric       Counts.emplace_back(Val, 1);
13480b57cec5SDimitry Andric     } else {
13490b57cec5SDimitry Andric       CountIt->second++;
13500b57cec5SDimitry Andric     }
1351*8bcb0991SDimitry Andric   };
13520b57cec5SDimitry Andric 
1353*8bcb0991SDimitry Andric   auto GetMostCommon = [](auto &Counts) {
1354*8bcb0991SDimitry Andric     auto CommonIt =
1355*8bcb0991SDimitry Andric         std::max_element(Counts.begin(), Counts.end(),
1356*8bcb0991SDimitry Andric                          [](auto A, auto B) { return A.second < B.second; });
1357*8bcb0991SDimitry Andric     assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
1358*8bcb0991SDimitry Andric     return *CommonIt;
1359*8bcb0991SDimitry Andric   };
1360*8bcb0991SDimitry Andric 
1361*8bcb0991SDimitry Andric   size_t NumConstantLanes = 0;
1362*8bcb0991SDimitry Andric 
1363*8bcb0991SDimitry Andric   // Count eligible lanes for each type of vector creation op
1364*8bcb0991SDimitry Andric   for (size_t I = 0; I < Lanes; ++I) {
1365*8bcb0991SDimitry Andric     const SDValue &Lane = Op->getOperand(I);
1366*8bcb0991SDimitry Andric     if (Lane.isUndef())
1367*8bcb0991SDimitry Andric       continue;
1368*8bcb0991SDimitry Andric 
1369*8bcb0991SDimitry Andric     AddCount(SplatValueCounts, Lane);
1370*8bcb0991SDimitry Andric 
1371*8bcb0991SDimitry Andric     if (IsConstant(Lane)) {
1372*8bcb0991SDimitry Andric       NumConstantLanes++;
1373*8bcb0991SDimitry Andric     } else if (CanSwizzle) {
1374*8bcb0991SDimitry Andric       auto SwizzleSrcs = GetSwizzleSrcs(I, Lane);
1375*8bcb0991SDimitry Andric       if (SwizzleSrcs.first)
1376*8bcb0991SDimitry Andric         AddCount(SwizzleCounts, SwizzleSrcs);
1377*8bcb0991SDimitry Andric     }
1378*8bcb0991SDimitry Andric   }
1379*8bcb0991SDimitry Andric 
1380*8bcb0991SDimitry Andric   SDValue SplatValue;
1381*8bcb0991SDimitry Andric   size_t NumSplatLanes;
1382*8bcb0991SDimitry Andric   std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts);
1383*8bcb0991SDimitry Andric 
1384*8bcb0991SDimitry Andric   SDValue SwizzleSrc;
1385*8bcb0991SDimitry Andric   SDValue SwizzleIndices;
1386*8bcb0991SDimitry Andric   size_t NumSwizzleLanes = 0;
1387*8bcb0991SDimitry Andric   if (SwizzleCounts.size())
1388*8bcb0991SDimitry Andric     std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices),
1389*8bcb0991SDimitry Andric                           NumSwizzleLanes) = GetMostCommon(SwizzleCounts);
1390*8bcb0991SDimitry Andric 
1391*8bcb0991SDimitry Andric   // Predicate returning true if the lane is properly initialized by the
1392*8bcb0991SDimitry Andric   // original instruction
1393*8bcb0991SDimitry Andric   std::function<bool(size_t, const SDValue &)> IsLaneConstructed;
1394*8bcb0991SDimitry Andric   SDValue Result;
13950b57cec5SDimitry Andric   if (Subtarget->hasUnimplementedSIMD128()) {
1396*8bcb0991SDimitry Andric     // Prefer swizzles over vector consts over splats
1397*8bcb0991SDimitry Andric     if (NumSwizzleLanes >= NumSplatLanes &&
1398*8bcb0991SDimitry Andric         NumSwizzleLanes >= NumConstantLanes) {
1399*8bcb0991SDimitry Andric       Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc,
1400*8bcb0991SDimitry Andric                            SwizzleIndices);
1401*8bcb0991SDimitry Andric       auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices);
1402*8bcb0991SDimitry Andric       IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) {
1403*8bcb0991SDimitry Andric         return Swizzled == GetSwizzleSrcs(I, Lane);
1404*8bcb0991SDimitry Andric       };
1405*8bcb0991SDimitry Andric     } else if (NumConstantLanes >= NumSplatLanes) {
14060b57cec5SDimitry Andric       SmallVector<SDValue, 16> ConstLanes;
14070b57cec5SDimitry Andric       for (const SDValue &Lane : Op->op_values()) {
14080b57cec5SDimitry Andric         if (IsConstant(Lane)) {
14090b57cec5SDimitry Andric           ConstLanes.push_back(Lane);
14100b57cec5SDimitry Andric         } else if (LaneT.isFloatingPoint()) {
14110b57cec5SDimitry Andric           ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
14120b57cec5SDimitry Andric         } else {
14130b57cec5SDimitry Andric           ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
14140b57cec5SDimitry Andric         }
14150b57cec5SDimitry Andric       }
1416*8bcb0991SDimitry Andric       Result = DAG.getBuildVector(VecT, DL, ConstLanes);
1417*8bcb0991SDimitry Andric       IsLaneConstructed = [&](size_t _, const SDValue &Lane) {
1418*8bcb0991SDimitry Andric         return IsConstant(Lane);
1419*8bcb0991SDimitry Andric       };
1420*8bcb0991SDimitry Andric     }
1421*8bcb0991SDimitry Andric   }
1422*8bcb0991SDimitry Andric   if (!Result) {
1423*8bcb0991SDimitry Andric     // Use a splat, but possibly a load_splat
1424*8bcb0991SDimitry Andric     LoadSDNode *SplattedLoad;
1425*8bcb0991SDimitry Andric     if (Subtarget->hasUnimplementedSIMD128() &&
1426*8bcb0991SDimitry Andric         (SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) &&
1427*8bcb0991SDimitry Andric         SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) {
1428*8bcb0991SDimitry Andric       Result = DAG.getNode(WebAssemblyISD::LOAD_SPLAT, DL, VecT, SplatValue);
1429*8bcb0991SDimitry Andric     } else {
1430*8bcb0991SDimitry Andric       Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
1431*8bcb0991SDimitry Andric     }
1432*8bcb0991SDimitry Andric     IsLaneConstructed = [&](size_t _, const SDValue &Lane) {
1433*8bcb0991SDimitry Andric       return Lane == SplatValue;
1434*8bcb0991SDimitry Andric     };
1435*8bcb0991SDimitry Andric   }
1436*8bcb0991SDimitry Andric 
1437*8bcb0991SDimitry Andric   // Add replace_lane instructions for any unhandled values
14380b57cec5SDimitry Andric   for (size_t I = 0; I < Lanes; ++I) {
14390b57cec5SDimitry Andric     const SDValue &Lane = Op->getOperand(I);
1440*8bcb0991SDimitry Andric     if (!Lane.isUndef() && !IsLaneConstructed(I, Lane))
14410b57cec5SDimitry Andric       Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
14420b57cec5SDimitry Andric                            DAG.getConstant(I, DL, MVT::i32));
14430b57cec5SDimitry Andric   }
1444*8bcb0991SDimitry Andric 
14450b57cec5SDimitry Andric   return Result;
14460b57cec5SDimitry Andric }
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric SDValue
14490b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
14500b57cec5SDimitry Andric                                                SelectionDAG &DAG) const {
14510b57cec5SDimitry Andric   SDLoc DL(Op);
14520b57cec5SDimitry Andric   ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
14530b57cec5SDimitry Andric   MVT VecType = Op.getOperand(0).getSimpleValueType();
14540b57cec5SDimitry Andric   assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
14550b57cec5SDimitry Andric   size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
14560b57cec5SDimitry Andric 
14570b57cec5SDimitry Andric   // Space for two vector args and sixteen mask indices
14580b57cec5SDimitry Andric   SDValue Ops[18];
14590b57cec5SDimitry Andric   size_t OpIdx = 0;
14600b57cec5SDimitry Andric   Ops[OpIdx++] = Op.getOperand(0);
14610b57cec5SDimitry Andric   Ops[OpIdx++] = Op.getOperand(1);
14620b57cec5SDimitry Andric 
14630b57cec5SDimitry Andric   // Expand mask indices to byte indices and materialize them as operands
14640b57cec5SDimitry Andric   for (int M : Mask) {
14650b57cec5SDimitry Andric     for (size_t J = 0; J < LaneBytes; ++J) {
14660b57cec5SDimitry Andric       // Lower undefs (represented by -1 in mask) to zero
14670b57cec5SDimitry Andric       uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J;
14680b57cec5SDimitry Andric       Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
14690b57cec5SDimitry Andric     }
14700b57cec5SDimitry Andric   }
14710b57cec5SDimitry Andric 
14720b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
14730b57cec5SDimitry Andric }
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric SDValue
14760b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
14770b57cec5SDimitry Andric                                                     SelectionDAG &DAG) const {
14780b57cec5SDimitry Andric   // Allow constant lane indices, expand variable lane indices
14790b57cec5SDimitry Andric   SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
14800b57cec5SDimitry Andric   if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef())
14810b57cec5SDimitry Andric     return Op;
14820b57cec5SDimitry Andric   else
14830b57cec5SDimitry Andric     // Perform default expansion
14840b57cec5SDimitry Andric     return SDValue();
14850b57cec5SDimitry Andric }
14860b57cec5SDimitry Andric 
14870b57cec5SDimitry Andric static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) {
14880b57cec5SDimitry Andric   EVT LaneT = Op.getSimpleValueType().getVectorElementType();
14890b57cec5SDimitry Andric   // 32-bit and 64-bit unrolled shifts will have proper semantics
14900b57cec5SDimitry Andric   if (LaneT.bitsGE(MVT::i32))
14910b57cec5SDimitry Andric     return DAG.UnrollVectorOp(Op.getNode());
14920b57cec5SDimitry Andric   // Otherwise mask the shift value to get proper semantics from 32-bit shift
14930b57cec5SDimitry Andric   SDLoc DL(Op);
14940b57cec5SDimitry Andric   SDValue ShiftVal = Op.getOperand(1);
14950b57cec5SDimitry Andric   uint64_t MaskVal = LaneT.getSizeInBits() - 1;
14960b57cec5SDimitry Andric   SDValue MaskedShiftVal = DAG.getNode(
14970b57cec5SDimitry Andric       ISD::AND,                    // mask opcode
14980b57cec5SDimitry Andric       DL, ShiftVal.getValueType(), // masked value type
14990b57cec5SDimitry Andric       ShiftVal,                    // original shift value operand
15000b57cec5SDimitry Andric       DAG.getConstant(MaskVal, DL, ShiftVal.getValueType()) // mask operand
15010b57cec5SDimitry Andric   );
15020b57cec5SDimitry Andric 
15030b57cec5SDimitry Andric   return DAG.UnrollVectorOp(
15040b57cec5SDimitry Andric       DAG.getNode(Op.getOpcode(),        // original shift opcode
15050b57cec5SDimitry Andric                   DL, Op.getValueType(), // original return type
15060b57cec5SDimitry Andric                   Op.getOperand(0),      // original vector operand,
15070b57cec5SDimitry Andric                   MaskedShiftVal         // new masked shift value operand
15080b57cec5SDimitry Andric                   )
15090b57cec5SDimitry Andric           .getNode());
15100b57cec5SDimitry Andric }
15110b57cec5SDimitry Andric 
15120b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
15130b57cec5SDimitry Andric                                               SelectionDAG &DAG) const {
15140b57cec5SDimitry Andric   SDLoc DL(Op);
15150b57cec5SDimitry Andric 
15160b57cec5SDimitry Andric   // Only manually lower vector shifts
15170b57cec5SDimitry Andric   assert(Op.getSimpleValueType().isVector());
15180b57cec5SDimitry Andric 
15190b57cec5SDimitry Andric   // Unroll non-splat vector shifts
15200b57cec5SDimitry Andric   BuildVectorSDNode *ShiftVec;
15210b57cec5SDimitry Andric   SDValue SplatVal;
15220b57cec5SDimitry Andric   if (!(ShiftVec = dyn_cast<BuildVectorSDNode>(Op.getOperand(1).getNode())) ||
15230b57cec5SDimitry Andric       !(SplatVal = ShiftVec->getSplatValue()))
15240b57cec5SDimitry Andric     return unrollVectorShift(Op, DAG);
15250b57cec5SDimitry Andric 
15260b57cec5SDimitry Andric   // All splats except i64x2 const splats are handled by patterns
15270b57cec5SDimitry Andric   auto *SplatConst = dyn_cast<ConstantSDNode>(SplatVal);
15280b57cec5SDimitry Andric   if (!SplatConst || Op.getSimpleValueType() != MVT::v2i64)
15290b57cec5SDimitry Andric     return Op;
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric   // i64x2 const splats are custom lowered to avoid unnecessary wraps
15320b57cec5SDimitry Andric   unsigned Opcode;
15330b57cec5SDimitry Andric   switch (Op.getOpcode()) {
15340b57cec5SDimitry Andric   case ISD::SHL:
15350b57cec5SDimitry Andric     Opcode = WebAssemblyISD::VEC_SHL;
15360b57cec5SDimitry Andric     break;
15370b57cec5SDimitry Andric   case ISD::SRA:
15380b57cec5SDimitry Andric     Opcode = WebAssemblyISD::VEC_SHR_S;
15390b57cec5SDimitry Andric     break;
15400b57cec5SDimitry Andric   case ISD::SRL:
15410b57cec5SDimitry Andric     Opcode = WebAssemblyISD::VEC_SHR_U;
15420b57cec5SDimitry Andric     break;
15430b57cec5SDimitry Andric   default:
15440b57cec5SDimitry Andric     llvm_unreachable("unexpected opcode");
15450b57cec5SDimitry Andric   }
15460b57cec5SDimitry Andric   APInt Shift = SplatConst->getAPIntValue().zextOrTrunc(32);
15470b57cec5SDimitry Andric   return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0),
15480b57cec5SDimitry Andric                      DAG.getConstant(Shift, DL, MVT::i32));
15490b57cec5SDimitry Andric }
15500b57cec5SDimitry Andric 
15510b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
15520b57cec5SDimitry Andric //                          WebAssembly Optimization Hooks
15530b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1554