xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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"
31480093f4SDimitry Andric #include "llvm/IR/IntrinsicsWebAssembly.h"
320b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
330b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
340b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
350b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
360b57cec5SDimitry Andric using namespace llvm;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-lower"
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric WebAssemblyTargetLowering::WebAssemblyTargetLowering(
410b57cec5SDimitry Andric     const TargetMachine &TM, const WebAssemblySubtarget &STI)
420b57cec5SDimitry Andric     : TargetLowering(TM), Subtarget(&STI) {
430b57cec5SDimitry Andric   auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   // Booleans always contain 0 or 1.
460b57cec5SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
470b57cec5SDimitry Andric   // Except in SIMD vectors
480b57cec5SDimitry Andric   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
490b57cec5SDimitry Andric   // We don't know the microarchitecture here, so just reduce register pressure.
500b57cec5SDimitry Andric   setSchedulingPreference(Sched::RegPressure);
510b57cec5SDimitry Andric   // Tell ISel that we have a stack pointer.
520b57cec5SDimitry Andric   setStackPointerRegisterToSaveRestore(
530b57cec5SDimitry Andric       Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
540b57cec5SDimitry Andric   // Set up the register classes.
550b57cec5SDimitry Andric   addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
560b57cec5SDimitry Andric   addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
570b57cec5SDimitry Andric   addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
580b57cec5SDimitry Andric   addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
590b57cec5SDimitry Andric   if (Subtarget->hasSIMD128()) {
600b57cec5SDimitry Andric     addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
610b57cec5SDimitry Andric     addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
620b57cec5SDimitry Andric     addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
630b57cec5SDimitry Andric     addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
640b57cec5SDimitry Andric     addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
650b57cec5SDimitry Andric     addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric   // Compute derived properties from the register classes.
680b57cec5SDimitry Andric   computeRegisterProperties(Subtarget->getRegisterInfo());
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
710b57cec5SDimitry Andric   setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
720b57cec5SDimitry Andric   setOperationAction(ISD::JumpTable, MVTPtr, Custom);
730b57cec5SDimitry Andric   setOperationAction(ISD::BlockAddress, MVTPtr, Custom);
740b57cec5SDimitry Andric   setOperationAction(ISD::BRIND, MVT::Other, Custom);
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   // Take the default expansion for va_arg, va_copy, and va_end. There is no
770b57cec5SDimitry Andric   // default action for va_start, so we do that custom.
780b57cec5SDimitry Andric   setOperationAction(ISD::VASTART, MVT::Other, Custom);
790b57cec5SDimitry Andric   setOperationAction(ISD::VAARG, MVT::Other, Expand);
800b57cec5SDimitry Andric   setOperationAction(ISD::VACOPY, MVT::Other, Expand);
810b57cec5SDimitry Andric   setOperationAction(ISD::VAEND, MVT::Other, Expand);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
840b57cec5SDimitry Andric     // Don't expand the floating-point types to constant pools.
850b57cec5SDimitry Andric     setOperationAction(ISD::ConstantFP, T, Legal);
860b57cec5SDimitry Andric     // Expand floating-point comparisons.
870b57cec5SDimitry Andric     for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
880b57cec5SDimitry Andric                     ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
890b57cec5SDimitry Andric       setCondCodeAction(CC, T, Expand);
900b57cec5SDimitry Andric     // Expand floating-point library function operators.
910b57cec5SDimitry Andric     for (auto Op :
920b57cec5SDimitry Andric          {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
930b57cec5SDimitry Andric       setOperationAction(Op, T, Expand);
940b57cec5SDimitry Andric     // Note supported floating-point library function operators that otherwise
950b57cec5SDimitry Andric     // default to expand.
960b57cec5SDimitry Andric     for (auto Op :
970b57cec5SDimitry Andric          {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
980b57cec5SDimitry Andric       setOperationAction(Op, T, Legal);
990b57cec5SDimitry Andric     // Support minimum and maximum, which otherwise default to expand.
1000b57cec5SDimitry Andric     setOperationAction(ISD::FMINIMUM, T, Legal);
1010b57cec5SDimitry Andric     setOperationAction(ISD::FMAXIMUM, T, Legal);
1020b57cec5SDimitry Andric     // WebAssembly currently has no builtin f16 support.
1030b57cec5SDimitry Andric     setOperationAction(ISD::FP16_TO_FP, T, Expand);
1040b57cec5SDimitry Andric     setOperationAction(ISD::FP_TO_FP16, T, Expand);
1050b57cec5SDimitry Andric     setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand);
1060b57cec5SDimitry Andric     setTruncStoreAction(T, MVT::f16, Expand);
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // Expand unavailable integer operations.
1100b57cec5SDimitry Andric   for (auto Op :
1110b57cec5SDimitry Andric        {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU,
1120b57cec5SDimitry Andric         ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS,
1130b57cec5SDimitry Andric         ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
1140b57cec5SDimitry Andric     for (auto T : {MVT::i32, MVT::i64})
1150b57cec5SDimitry Andric       setOperationAction(Op, T, Expand);
1160b57cec5SDimitry Andric     if (Subtarget->hasSIMD128())
117*5ffd83dbSDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
1180b57cec5SDimitry Andric         setOperationAction(Op, T, Expand);
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // SIMD-specific configuration
1220b57cec5SDimitry Andric   if (Subtarget->hasSIMD128()) {
123*5ffd83dbSDimitry Andric     // Hoist bitcasts out of shuffles
124*5ffd83dbSDimitry Andric     setTargetDAGCombine(ISD::VECTOR_SHUFFLE);
125*5ffd83dbSDimitry Andric 
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 
131*5ffd83dbSDimitry Andric     // Support integer abs
132*5ffd83dbSDimitry Andric     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
133*5ffd83dbSDimitry Andric       setOperationAction(ISD::ABS, T, Legal);
134*5ffd83dbSDimitry Andric 
1350b57cec5SDimitry Andric     // Custom lower BUILD_VECTORs to minimize number of replace_lanes
136*5ffd83dbSDimitry Andric     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
137*5ffd83dbSDimitry Andric                    MVT::v2f64})
1380b57cec5SDimitry Andric       setOperationAction(ISD::BUILD_VECTOR, T, Custom);
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric     // We have custom shuffle lowering to expose the shuffle mask
141*5ffd83dbSDimitry Andric     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
142*5ffd83dbSDimitry Andric                    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
146*5ffd83dbSDimitry Andric     for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
147*5ffd83dbSDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
1480b57cec5SDimitry Andric         setOperationAction(Op, T, Custom);
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric     // Custom lower lane accesses to expand out variable indices
151*5ffd83dbSDimitry Andric     for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT})
152*5ffd83dbSDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
153*5ffd83dbSDimitry Andric                      MVT::v2f64})
1540b57cec5SDimitry Andric         setOperationAction(Op, T, Custom);
1550b57cec5SDimitry Andric 
156*5ffd83dbSDimitry Andric     // There is no i8x16.mul instruction
157*5ffd83dbSDimitry Andric     setOperationAction(ISD::MUL, MVT::v16i8, Expand);
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric     // There are no vector select instructions
160*5ffd83dbSDimitry Andric     for (auto Op : {ISD::VSELECT, ISD::SELECT_CC, ISD::SELECT})
161*5ffd83dbSDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
162*5ffd83dbSDimitry Andric                      MVT::v2f64})
1630b57cec5SDimitry Andric         setOperationAction(Op, T, Expand);
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric     // Expand integer operations supported for scalars but not SIMD
1660b57cec5SDimitry Andric     for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP, ISD::SDIV, ISD::UDIV,
167*5ffd83dbSDimitry Andric                     ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR})
168*5ffd83dbSDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
1690b57cec5SDimitry Andric         setOperationAction(Op, T, Expand);
1700b57cec5SDimitry Andric 
171480093f4SDimitry Andric     // But we do have integer min and max operations
172480093f4SDimitry Andric     for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX})
173480093f4SDimitry Andric       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
174480093f4SDimitry Andric         setOperationAction(Op, T, Legal);
175480093f4SDimitry Andric 
1760b57cec5SDimitry Andric     // Expand float operations supported for scalars but not SIMD
1770b57cec5SDimitry Andric     for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
1780b57cec5SDimitry Andric                     ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10,
179*5ffd83dbSDimitry Andric                     ISD::FEXP, ISD::FEXP2, ISD::FRINT})
180*5ffd83dbSDimitry Andric       for (auto T : {MVT::v4f32, MVT::v2f64})
181*5ffd83dbSDimitry Andric         setOperationAction(Op, T, Expand);
1820b57cec5SDimitry Andric 
183480093f4SDimitry Andric     // Expand operations not supported for i64x2 vectors
184480093f4SDimitry Andric     for (unsigned CC = 0; CC < ISD::SETCC_INVALID; ++CC)
185480093f4SDimitry Andric       setCondCodeAction(static_cast<ISD::CondCode>(CC), MVT::v2i64, Custom);
186480093f4SDimitry Andric 
187*5ffd83dbSDimitry Andric     // 64x2 conversions are not in the spec
188*5ffd83dbSDimitry Andric     for (auto Op :
189*5ffd83dbSDimitry Andric          {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT})
190*5ffd83dbSDimitry Andric       for (auto T : {MVT::v2i64, MVT::v2f64})
191*5ffd83dbSDimitry Andric         setOperationAction(Op, T, Expand);
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   // As a special case, these operators use the type to mean the type to
1950b57cec5SDimitry Andric   // sign-extend from.
1960b57cec5SDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
1970b57cec5SDimitry Andric   if (!Subtarget->hasSignExt()) {
1980b57cec5SDimitry Andric     // Sign extends are legal only when extending a vector extract
1990b57cec5SDimitry Andric     auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
2000b57cec5SDimitry Andric     for (auto T : {MVT::i8, MVT::i16, MVT::i32})
2010b57cec5SDimitry Andric       setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action);
2020b57cec5SDimitry Andric   }
2038bcb0991SDimitry Andric   for (auto T : MVT::integer_fixedlen_vector_valuetypes())
2040b57cec5SDimitry Andric     setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   // Dynamic stack allocation: use the default expansion.
2070b57cec5SDimitry Andric   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
2080b57cec5SDimitry Andric   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
2090b57cec5SDimitry Andric   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
212*5ffd83dbSDimitry Andric   setOperationAction(ISD::FrameIndex, MVT::i64, Custom);
2130b57cec5SDimitry Andric   setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   // Expand these forms; we pattern-match the forms that we can handle in isel.
2160b57cec5SDimitry Andric   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
2170b57cec5SDimitry Andric     for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
2180b57cec5SDimitry Andric       setOperationAction(Op, T, Expand);
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // We have custom switch handling.
2210b57cec5SDimitry Andric   setOperationAction(ISD::BR_JT, MVT::Other, Custom);
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   // WebAssembly doesn't have:
2240b57cec5SDimitry Andric   //  - Floating-point extending loads.
2250b57cec5SDimitry Andric   //  - Floating-point truncating stores.
2260b57cec5SDimitry Andric   //  - i1 extending loads.
2278bcb0991SDimitry Andric   //  - truncating SIMD stores and most extending loads
2280b57cec5SDimitry Andric   setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
2290b57cec5SDimitry Andric   setTruncStoreAction(MVT::f64, MVT::f32, Expand);
2300b57cec5SDimitry Andric   for (auto T : MVT::integer_valuetypes())
2310b57cec5SDimitry Andric     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
2320b57cec5SDimitry Andric       setLoadExtAction(Ext, T, MVT::i1, Promote);
2330b57cec5SDimitry Andric   if (Subtarget->hasSIMD128()) {
2340b57cec5SDimitry Andric     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
2350b57cec5SDimitry Andric                    MVT::v2f64}) {
2368bcb0991SDimitry Andric       for (auto MemT : MVT::fixedlen_vector_valuetypes()) {
2370b57cec5SDimitry Andric         if (MVT(T) != MemT) {
2380b57cec5SDimitry Andric           setTruncStoreAction(T, MemT, Expand);
2390b57cec5SDimitry Andric           for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
2400b57cec5SDimitry Andric             setLoadExtAction(Ext, T, MemT, Expand);
2410b57cec5SDimitry Andric         }
2420b57cec5SDimitry Andric       }
2430b57cec5SDimitry Andric     }
2448bcb0991SDimitry Andric     // But some vector extending loads are legal
2458bcb0991SDimitry Andric     for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
2468bcb0991SDimitry Andric       setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal);
2478bcb0991SDimitry Andric       setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal);
2488bcb0991SDimitry Andric       setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal);
2498bcb0991SDimitry Andric     }
2508bcb0991SDimitry Andric   }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   // Don't do anything clever with build_pairs
2530b57cec5SDimitry Andric   setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand);
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   // Trap lowers to wasm unreachable
2560b57cec5SDimitry Andric   setOperationAction(ISD::TRAP, MVT::Other, Legal);
257*5ffd83dbSDimitry Andric   setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   // Exception handling intrinsics
2600b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
2610b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   setMaxAtomicSizeInBitsSupported(64);
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is
2660b57cec5SDimitry Andric   // consistent with the f64 and f128 names.
2670b57cec5SDimitry Andric   setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
2680b57cec5SDimitry Andric   setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // Define the emscripten name for return address helper.
2710b57cec5SDimitry Andric   // TODO: when implementing other WASM backends, make this generic or only do
2720b57cec5SDimitry Andric   // this on emscripten depending on what they end up doing.
2730b57cec5SDimitry Andric   setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address");
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   // Always convert switches to br_tables unless there is only one case, which
2760b57cec5SDimitry Andric   // is equivalent to a simple branch. This reduces code size for wasm, and we
2770b57cec5SDimitry Andric   // defer possible jump table optimizations to the VM.
2780b57cec5SDimitry Andric   setMinimumJumpTableEntries(2);
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric TargetLowering::AtomicExpansionKind
2820b57cec5SDimitry Andric WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
2830b57cec5SDimitry Andric   // We have wasm instructions for these
2840b57cec5SDimitry Andric   switch (AI->getOperation()) {
2850b57cec5SDimitry Andric   case AtomicRMWInst::Add:
2860b57cec5SDimitry Andric   case AtomicRMWInst::Sub:
2870b57cec5SDimitry Andric   case AtomicRMWInst::And:
2880b57cec5SDimitry Andric   case AtomicRMWInst::Or:
2890b57cec5SDimitry Andric   case AtomicRMWInst::Xor:
2900b57cec5SDimitry Andric   case AtomicRMWInst::Xchg:
2910b57cec5SDimitry Andric     return AtomicExpansionKind::None;
2920b57cec5SDimitry Andric   default:
2930b57cec5SDimitry Andric     break;
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric   return AtomicExpansionKind::CmpXChg;
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric FastISel *WebAssemblyTargetLowering::createFastISel(
2990b57cec5SDimitry Andric     FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
3000b57cec5SDimitry Andric   return WebAssembly::createFastISel(FuncInfo, LibInfo);
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
3040b57cec5SDimitry Andric                                                       EVT VT) const {
3050b57cec5SDimitry Andric   unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
3060b57cec5SDimitry Andric   if (BitWidth > 1 && BitWidth < 8)
3070b57cec5SDimitry Andric     BitWidth = 8;
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   if (BitWidth > 64) {
3100b57cec5SDimitry Andric     // The shift will be lowered to a libcall, and compiler-rt libcalls expect
3110b57cec5SDimitry Andric     // the count to be an i32.
3120b57cec5SDimitry Andric     BitWidth = 32;
3130b57cec5SDimitry Andric     assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&
3140b57cec5SDimitry Andric            "32-bit shift counts ought to be enough for anyone");
3150b57cec5SDimitry Andric   }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   MVT Result = MVT::getIntegerVT(BitWidth);
3180b57cec5SDimitry Andric   assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
3190b57cec5SDimitry Andric          "Unable to represent scalar shift amount type");
3200b57cec5SDimitry Andric   return Result;
3210b57cec5SDimitry Andric }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric // Lower an fp-to-int conversion operator from the LLVM opcode, which has an
3240b57cec5SDimitry Andric // undefined result on invalid/overflow, to the WebAssembly opcode, which
3250b57cec5SDimitry Andric // traps on invalid/overflow.
3260b57cec5SDimitry Andric static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
3270b57cec5SDimitry Andric                                        MachineBasicBlock *BB,
3280b57cec5SDimitry Andric                                        const TargetInstrInfo &TII,
3290b57cec5SDimitry Andric                                        bool IsUnsigned, bool Int64,
3300b57cec5SDimitry Andric                                        bool Float64, unsigned LoweredOpcode) {
3310b57cec5SDimitry Andric   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
3320b57cec5SDimitry Andric 
3338bcb0991SDimitry Andric   Register OutReg = MI.getOperand(0).getReg();
3348bcb0991SDimitry Andric   Register InReg = MI.getOperand(1).getReg();
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
3370b57cec5SDimitry Andric   unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
3380b57cec5SDimitry Andric   unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
3390b57cec5SDimitry Andric   unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
3400b57cec5SDimitry Andric   unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
3410b57cec5SDimitry Andric   unsigned Eqz = WebAssembly::EQZ_I32;
3420b57cec5SDimitry Andric   unsigned And = WebAssembly::AND_I32;
3430b57cec5SDimitry Andric   int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
3440b57cec5SDimitry Andric   int64_t Substitute = IsUnsigned ? 0 : Limit;
3450b57cec5SDimitry Andric   double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
3460b57cec5SDimitry Andric   auto &Context = BB->getParent()->getFunction().getContext();
3470b57cec5SDimitry Andric   Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric   const BasicBlock *LLVMBB = BB->getBasicBlock();
3500b57cec5SDimitry Andric   MachineFunction *F = BB->getParent();
3510b57cec5SDimitry Andric   MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
3520b57cec5SDimitry Andric   MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB);
3530b57cec5SDimitry Andric   MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   MachineFunction::iterator It = ++BB->getIterator();
3560b57cec5SDimitry Andric   F->insert(It, FalseMBB);
3570b57cec5SDimitry Andric   F->insert(It, TrueMBB);
3580b57cec5SDimitry Andric   F->insert(It, DoneMBB);
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   // Transfer the remainder of BB and its successor edges to DoneMBB.
3610b57cec5SDimitry Andric   DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
3620b57cec5SDimitry Andric   DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   BB->addSuccessor(TrueMBB);
3650b57cec5SDimitry Andric   BB->addSuccessor(FalseMBB);
3660b57cec5SDimitry Andric   TrueMBB->addSuccessor(DoneMBB);
3670b57cec5SDimitry Andric   FalseMBB->addSuccessor(DoneMBB);
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
3700b57cec5SDimitry Andric   Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
3710b57cec5SDimitry Andric   Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
3720b57cec5SDimitry Andric   CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
3730b57cec5SDimitry Andric   EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
3740b57cec5SDimitry Andric   FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
3750b57cec5SDimitry Andric   TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric   MI.eraseFromParent();
3780b57cec5SDimitry Andric   // For signed numbers, we can do a single comparison to determine whether
3790b57cec5SDimitry Andric   // fabs(x) is within range.
3800b57cec5SDimitry Andric   if (IsUnsigned) {
3810b57cec5SDimitry Andric     Tmp0 = InReg;
3820b57cec5SDimitry Andric   } else {
3830b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(FConst), Tmp1)
3860b57cec5SDimitry Andric       .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
3870b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   // For unsigned numbers, we have to do a separate comparison with zero.
3900b57cec5SDimitry Andric   if (IsUnsigned) {
3910b57cec5SDimitry Andric     Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
3928bcb0991SDimitry Andric     Register SecondCmpReg =
3930b57cec5SDimitry Andric         MRI.createVirtualRegister(&WebAssembly::I32RegClass);
3948bcb0991SDimitry Andric     Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
3950b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(FConst), Tmp1)
3960b57cec5SDimitry Andric         .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
3970b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
3980b57cec5SDimitry Andric     BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
3990b57cec5SDimitry Andric     CmpReg = AndReg;
4000b57cec5SDimitry Andric   }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   // Create the CFG diamond to select between doing the conversion or using
4050b57cec5SDimitry Andric   // the substitute value.
4060b57cec5SDimitry Andric   BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
4070b57cec5SDimitry Andric   BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
4080b57cec5SDimitry Andric   BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
4090b57cec5SDimitry Andric   BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
4100b57cec5SDimitry Andric   BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
4110b57cec5SDimitry Andric       .addReg(FalseReg)
4120b57cec5SDimitry Andric       .addMBB(FalseMBB)
4130b57cec5SDimitry Andric       .addReg(TrueReg)
4140b57cec5SDimitry Andric       .addMBB(TrueMBB);
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   return DoneMBB;
4170b57cec5SDimitry Andric }
4180b57cec5SDimitry Andric 
419*5ffd83dbSDimitry Andric static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
420*5ffd83dbSDimitry Andric                                            DebugLoc DL, MachineBasicBlock *BB,
421*5ffd83dbSDimitry Andric                                            const TargetInstrInfo &TII) {
422*5ffd83dbSDimitry Andric   MachineInstr &CallParams = *CallResults.getPrevNode();
423*5ffd83dbSDimitry Andric   assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
424*5ffd83dbSDimitry Andric   assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||
425*5ffd83dbSDimitry Andric          CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS);
426*5ffd83dbSDimitry Andric 
427*5ffd83dbSDimitry Andric   bool IsIndirect = CallParams.getOperand(0).isReg();
428*5ffd83dbSDimitry Andric   bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
429*5ffd83dbSDimitry Andric 
430*5ffd83dbSDimitry Andric   unsigned CallOp;
431*5ffd83dbSDimitry Andric   if (IsIndirect && IsRetCall) {
432*5ffd83dbSDimitry Andric     CallOp = WebAssembly::RET_CALL_INDIRECT;
433*5ffd83dbSDimitry Andric   } else if (IsIndirect) {
434*5ffd83dbSDimitry Andric     CallOp = WebAssembly::CALL_INDIRECT;
435*5ffd83dbSDimitry Andric   } else if (IsRetCall) {
436*5ffd83dbSDimitry Andric     CallOp = WebAssembly::RET_CALL;
437*5ffd83dbSDimitry Andric   } else {
438*5ffd83dbSDimitry Andric     CallOp = WebAssembly::CALL;
439*5ffd83dbSDimitry Andric   }
440*5ffd83dbSDimitry Andric 
441*5ffd83dbSDimitry Andric   MachineFunction &MF = *BB->getParent();
442*5ffd83dbSDimitry Andric   const MCInstrDesc &MCID = TII.get(CallOp);
443*5ffd83dbSDimitry Andric   MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
444*5ffd83dbSDimitry Andric 
445*5ffd83dbSDimitry Andric   // Move the function pointer to the end of the arguments for indirect calls
446*5ffd83dbSDimitry Andric   if (IsIndirect) {
447*5ffd83dbSDimitry Andric     auto FnPtr = CallParams.getOperand(0);
448*5ffd83dbSDimitry Andric     CallParams.RemoveOperand(0);
449*5ffd83dbSDimitry Andric     CallParams.addOperand(FnPtr);
450*5ffd83dbSDimitry Andric   }
451*5ffd83dbSDimitry Andric 
452*5ffd83dbSDimitry Andric   for (auto Def : CallResults.defs())
453*5ffd83dbSDimitry Andric     MIB.add(Def);
454*5ffd83dbSDimitry Andric 
455*5ffd83dbSDimitry Andric   // Add placeholders for the type index and immediate flags
456*5ffd83dbSDimitry Andric   if (IsIndirect) {
457*5ffd83dbSDimitry Andric     MIB.addImm(0);
458*5ffd83dbSDimitry Andric     MIB.addImm(0);
459*5ffd83dbSDimitry Andric   }
460*5ffd83dbSDimitry Andric 
461*5ffd83dbSDimitry Andric   for (auto Use : CallParams.uses())
462*5ffd83dbSDimitry Andric     MIB.add(Use);
463*5ffd83dbSDimitry Andric 
464*5ffd83dbSDimitry Andric   BB->insert(CallResults.getIterator(), MIB);
465*5ffd83dbSDimitry Andric   CallParams.eraseFromParent();
466*5ffd83dbSDimitry Andric   CallResults.eraseFromParent();
467*5ffd83dbSDimitry Andric 
468*5ffd83dbSDimitry Andric   return BB;
469*5ffd83dbSDimitry Andric }
470*5ffd83dbSDimitry Andric 
4710b57cec5SDimitry Andric MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
4720b57cec5SDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB) const {
4730b57cec5SDimitry Andric   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
4740b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   switch (MI.getOpcode()) {
4770b57cec5SDimitry Andric   default:
4780b57cec5SDimitry Andric     llvm_unreachable("Unexpected instr type to insert");
4790b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I32_F32:
4800b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, false, false,
4810b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_S_F32);
4820b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I32_F32:
4830b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, false, false,
4840b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_U_F32);
4850b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I64_F32:
4860b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, true, false,
4870b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_S_F32);
4880b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I64_F32:
4890b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, true, false,
4900b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_U_F32);
4910b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I32_F64:
4920b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, false, true,
4930b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_S_F64);
4940b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I32_F64:
4950b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, false, true,
4960b57cec5SDimitry Andric                         WebAssembly::I32_TRUNC_U_F64);
4970b57cec5SDimitry Andric   case WebAssembly::FP_TO_SINT_I64_F64:
4980b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, false, true, true,
4990b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_S_F64);
5000b57cec5SDimitry Andric   case WebAssembly::FP_TO_UINT_I64_F64:
5010b57cec5SDimitry Andric     return LowerFPToInt(MI, DL, BB, TII, true, true, true,
5020b57cec5SDimitry Andric                         WebAssembly::I64_TRUNC_U_F64);
503*5ffd83dbSDimitry Andric   case WebAssembly::CALL_RESULTS:
504*5ffd83dbSDimitry Andric   case WebAssembly::RET_CALL_RESULTS:
505*5ffd83dbSDimitry Andric     return LowerCallResults(MI, DL, BB, TII);
5060b57cec5SDimitry Andric   }
5070b57cec5SDimitry Andric }
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric const char *
5100b57cec5SDimitry Andric WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
5110b57cec5SDimitry Andric   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
5120b57cec5SDimitry Andric   case WebAssemblyISD::FIRST_NUMBER:
513480093f4SDimitry Andric   case WebAssemblyISD::FIRST_MEM_OPCODE:
5140b57cec5SDimitry Andric     break;
5150b57cec5SDimitry Andric #define HANDLE_NODETYPE(NODE)                                                  \
5160b57cec5SDimitry Andric   case WebAssemblyISD::NODE:                                                   \
5170b57cec5SDimitry Andric     return "WebAssemblyISD::" #NODE;
518480093f4SDimitry Andric #define HANDLE_MEM_NODETYPE(NODE) HANDLE_NODETYPE(NODE)
5190b57cec5SDimitry Andric #include "WebAssemblyISD.def"
520480093f4SDimitry Andric #undef HANDLE_MEM_NODETYPE
5210b57cec5SDimitry Andric #undef HANDLE_NODETYPE
5220b57cec5SDimitry Andric   }
5230b57cec5SDimitry Andric   return nullptr;
5240b57cec5SDimitry Andric }
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric std::pair<unsigned, const TargetRegisterClass *>
5270b57cec5SDimitry Andric WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
5280b57cec5SDimitry Andric     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
5290b57cec5SDimitry Andric   // First, see if this is a constraint that directly corresponds to a
5300b57cec5SDimitry Andric   // WebAssembly register class.
5310b57cec5SDimitry Andric   if (Constraint.size() == 1) {
5320b57cec5SDimitry Andric     switch (Constraint[0]) {
5330b57cec5SDimitry Andric     case 'r':
5340b57cec5SDimitry Andric       assert(VT != MVT::iPTR && "Pointer MVT not expected here");
5350b57cec5SDimitry Andric       if (Subtarget->hasSIMD128() && VT.isVector()) {
5360b57cec5SDimitry Andric         if (VT.getSizeInBits() == 128)
5370b57cec5SDimitry Andric           return std::make_pair(0U, &WebAssembly::V128RegClass);
5380b57cec5SDimitry Andric       }
5390b57cec5SDimitry Andric       if (VT.isInteger() && !VT.isVector()) {
5400b57cec5SDimitry Andric         if (VT.getSizeInBits() <= 32)
5410b57cec5SDimitry Andric           return std::make_pair(0U, &WebAssembly::I32RegClass);
5420b57cec5SDimitry Andric         if (VT.getSizeInBits() <= 64)
5430b57cec5SDimitry Andric           return std::make_pair(0U, &WebAssembly::I64RegClass);
5440b57cec5SDimitry Andric       }
5450b57cec5SDimitry Andric       break;
5460b57cec5SDimitry Andric     default:
5470b57cec5SDimitry Andric       break;
5480b57cec5SDimitry Andric     }
5490b57cec5SDimitry Andric   }
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
5550b57cec5SDimitry Andric   // Assume ctz is a relatively cheap operation.
5560b57cec5SDimitry Andric   return true;
5570b57cec5SDimitry Andric }
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
5600b57cec5SDimitry Andric   // Assume clz is a relatively cheap operation.
5610b57cec5SDimitry Andric   return true;
5620b57cec5SDimitry Andric }
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
5650b57cec5SDimitry Andric                                                       const AddrMode &AM,
5660b57cec5SDimitry Andric                                                       Type *Ty, unsigned AS,
5670b57cec5SDimitry Andric                                                       Instruction *I) const {
5680b57cec5SDimitry Andric   // WebAssembly offsets are added as unsigned without wrapping. The
5690b57cec5SDimitry Andric   // isLegalAddressingMode gives us no way to determine if wrapping could be
5700b57cec5SDimitry Andric   // happening, so we approximate this by accepting only non-negative offsets.
5710b57cec5SDimitry Andric   if (AM.BaseOffs < 0)
5720b57cec5SDimitry Andric     return false;
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric   // WebAssembly has no scale register operands.
5750b57cec5SDimitry Andric   if (AM.Scale != 0)
5760b57cec5SDimitry Andric     return false;
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric   // Everything else is legal.
5790b57cec5SDimitry Andric   return true;
5800b57cec5SDimitry Andric }
5810b57cec5SDimitry Andric 
5820b57cec5SDimitry Andric bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
5830b57cec5SDimitry Andric     EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/,
5840b57cec5SDimitry Andric     MachineMemOperand::Flags /*Flags*/, bool *Fast) const {
5850b57cec5SDimitry Andric   // WebAssembly supports unaligned accesses, though it should be declared
5860b57cec5SDimitry Andric   // with the p2align attribute on loads and stores which do so, and there
5870b57cec5SDimitry Andric   // may be a performance impact. We tell LLVM they're "fast" because
5880b57cec5SDimitry Andric   // for the kinds of things that LLVM uses this for (merging adjacent stores
5890b57cec5SDimitry Andric   // of constants, etc.), WebAssembly implementations will either want the
5900b57cec5SDimitry Andric   // unaligned access or they'll split anyway.
5910b57cec5SDimitry Andric   if (Fast)
5920b57cec5SDimitry Andric     *Fast = true;
5930b57cec5SDimitry Andric   return true;
5940b57cec5SDimitry Andric }
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
5970b57cec5SDimitry Andric                                               AttributeList Attr) const {
5980b57cec5SDimitry Andric   // The current thinking is that wasm engines will perform this optimization,
5990b57cec5SDimitry Andric   // so we can save on code size.
6000b57cec5SDimitry Andric   return true;
6010b57cec5SDimitry Andric }
6020b57cec5SDimitry Andric 
6038bcb0991SDimitry Andric bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
6048bcb0991SDimitry Andric   MVT ExtT = ExtVal.getSimpleValueType();
6058bcb0991SDimitry Andric   MVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getSimpleValueType(0);
6068bcb0991SDimitry Andric   return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
6078bcb0991SDimitry Andric          (ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
6088bcb0991SDimitry Andric          (ExtT == MVT::v2i64 && MemT == MVT::v2i32);
6098bcb0991SDimitry Andric }
6108bcb0991SDimitry Andric 
6110b57cec5SDimitry Andric EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
6120b57cec5SDimitry Andric                                                   LLVMContext &C,
6130b57cec5SDimitry Andric                                                   EVT VT) const {
6140b57cec5SDimitry Andric   if (VT.isVector())
6150b57cec5SDimitry Andric     return VT.changeVectorElementTypeToInteger();
6160b57cec5SDimitry Andric 
617*5ffd83dbSDimitry Andric   // So far, all branch instructions in Wasm take an I32 condition.
618*5ffd83dbSDimitry Andric   // The default TargetLowering::getSetCCResultType returns the pointer size,
619*5ffd83dbSDimitry Andric   // which would be useful to reduce instruction counts when testing
620*5ffd83dbSDimitry Andric   // against 64-bit pointers/values if at some point Wasm supports that.
621*5ffd83dbSDimitry Andric   return EVT::getIntegerVT(C, 32);
6220b57cec5SDimitry Andric }
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
6250b57cec5SDimitry Andric                                                    const CallInst &I,
6260b57cec5SDimitry Andric                                                    MachineFunction &MF,
6270b57cec5SDimitry Andric                                                    unsigned Intrinsic) const {
6280b57cec5SDimitry Andric   switch (Intrinsic) {
6290b57cec5SDimitry Andric   case Intrinsic::wasm_atomic_notify:
6300b57cec5SDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
6310b57cec5SDimitry Andric     Info.memVT = MVT::i32;
6320b57cec5SDimitry Andric     Info.ptrVal = I.getArgOperand(0);
6330b57cec5SDimitry Andric     Info.offset = 0;
6348bcb0991SDimitry Andric     Info.align = Align(4);
6350b57cec5SDimitry Andric     // atomic.notify instruction does not really load the memory specified with
6360b57cec5SDimitry Andric     // this argument, but MachineMemOperand should either be load or store, so
6370b57cec5SDimitry Andric     // we set this to a load.
6380b57cec5SDimitry Andric     // FIXME Volatile isn't really correct, but currently all LLVM atomic
6390b57cec5SDimitry Andric     // instructions are treated as volatiles in the backend, so we should be
6400b57cec5SDimitry Andric     // consistent. The same applies for wasm_atomic_wait intrinsics too.
6410b57cec5SDimitry Andric     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
6420b57cec5SDimitry Andric     return true;
6430b57cec5SDimitry Andric   case Intrinsic::wasm_atomic_wait_i32:
6440b57cec5SDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
6450b57cec5SDimitry Andric     Info.memVT = MVT::i32;
6460b57cec5SDimitry Andric     Info.ptrVal = I.getArgOperand(0);
6470b57cec5SDimitry Andric     Info.offset = 0;
6488bcb0991SDimitry Andric     Info.align = Align(4);
6490b57cec5SDimitry Andric     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
6500b57cec5SDimitry Andric     return true;
6510b57cec5SDimitry Andric   case Intrinsic::wasm_atomic_wait_i64:
6520b57cec5SDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
6530b57cec5SDimitry Andric     Info.memVT = MVT::i64;
6540b57cec5SDimitry Andric     Info.ptrVal = I.getArgOperand(0);
6550b57cec5SDimitry Andric     Info.offset = 0;
6568bcb0991SDimitry Andric     Info.align = Align(8);
6570b57cec5SDimitry Andric     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
6580b57cec5SDimitry Andric     return true;
6590b57cec5SDimitry Andric   default:
6600b57cec5SDimitry Andric     return false;
6610b57cec5SDimitry Andric   }
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6650b57cec5SDimitry Andric // WebAssembly Lowering private implementation.
6660b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6690b57cec5SDimitry Andric // Lowering Code
6700b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6710b57cec5SDimitry Andric 
6720b57cec5SDimitry Andric static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
6730b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
6740b57cec5SDimitry Andric   DAG.getContext()->diagnose(
6750b57cec5SDimitry Andric       DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
6760b57cec5SDimitry Andric }
6770b57cec5SDimitry Andric 
6780b57cec5SDimitry Andric // Test whether the given calling convention is supported.
6790b57cec5SDimitry Andric static bool callingConvSupported(CallingConv::ID CallConv) {
6800b57cec5SDimitry Andric   // We currently support the language-independent target-independent
6810b57cec5SDimitry Andric   // conventions. We don't yet have a way to annotate calls with properties like
6820b57cec5SDimitry Andric   // "cold", and we don't have any call-clobbered registers, so these are mostly
6830b57cec5SDimitry Andric   // all handled the same.
6840b57cec5SDimitry Andric   return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
6850b57cec5SDimitry Andric          CallConv == CallingConv::Cold ||
6860b57cec5SDimitry Andric          CallConv == CallingConv::PreserveMost ||
6870b57cec5SDimitry Andric          CallConv == CallingConv::PreserveAll ||
6888bcb0991SDimitry Andric          CallConv == CallingConv::CXX_FAST_TLS ||
689*5ffd83dbSDimitry Andric          CallConv == CallingConv::WASM_EmscriptenInvoke ||
690*5ffd83dbSDimitry Andric          CallConv == CallingConv::Swift;
6910b57cec5SDimitry Andric }
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric SDValue
6940b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
6950b57cec5SDimitry Andric                                      SmallVectorImpl<SDValue> &InVals) const {
6960b57cec5SDimitry Andric   SelectionDAG &DAG = CLI.DAG;
6970b57cec5SDimitry Andric   SDLoc DL = CLI.DL;
6980b57cec5SDimitry Andric   SDValue Chain = CLI.Chain;
6990b57cec5SDimitry Andric   SDValue Callee = CLI.Callee;
7000b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
7010b57cec5SDimitry Andric   auto Layout = MF.getDataLayout();
7020b57cec5SDimitry Andric 
7030b57cec5SDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
7040b57cec5SDimitry Andric   if (!callingConvSupported(CallConv))
7050b57cec5SDimitry Andric     fail(DL, DAG,
7060b57cec5SDimitry Andric          "WebAssembly doesn't support language-specific or target-specific "
7070b57cec5SDimitry Andric          "calling conventions yet");
7080b57cec5SDimitry Andric   if (CLI.IsPatchPoint)
7090b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
7100b57cec5SDimitry Andric 
7118bcb0991SDimitry Andric   if (CLI.IsTailCall) {
712*5ffd83dbSDimitry Andric     auto NoTail = [&](const char *Msg) {
713*5ffd83dbSDimitry Andric       if (CLI.CB && CLI.CB->isMustTailCall())
714*5ffd83dbSDimitry Andric         fail(DL, DAG, Msg);
715*5ffd83dbSDimitry Andric       CLI.IsTailCall = false;
716*5ffd83dbSDimitry Andric     };
717*5ffd83dbSDimitry Andric 
718*5ffd83dbSDimitry Andric     if (!Subtarget->hasTailCall())
719*5ffd83dbSDimitry Andric       NoTail("WebAssembly 'tail-call' feature not enabled");
720*5ffd83dbSDimitry Andric 
721*5ffd83dbSDimitry Andric     // Varargs calls cannot be tail calls because the buffer is on the stack
722*5ffd83dbSDimitry Andric     if (CLI.IsVarArg)
723*5ffd83dbSDimitry Andric       NoTail("WebAssembly does not support varargs tail calls");
724*5ffd83dbSDimitry Andric 
7258bcb0991SDimitry Andric     // Do not tail call unless caller and callee return types match
7268bcb0991SDimitry Andric     const Function &F = MF.getFunction();
7278bcb0991SDimitry Andric     const TargetMachine &TM = getTargetMachine();
7288bcb0991SDimitry Andric     Type *RetTy = F.getReturnType();
7298bcb0991SDimitry Andric     SmallVector<MVT, 4> CallerRetTys;
7308bcb0991SDimitry Andric     SmallVector<MVT, 4> CalleeRetTys;
7318bcb0991SDimitry Andric     computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
7328bcb0991SDimitry Andric     computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys);
7338bcb0991SDimitry Andric     bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() &&
7348bcb0991SDimitry Andric                       std::equal(CallerRetTys.begin(), CallerRetTys.end(),
7358bcb0991SDimitry Andric                                  CalleeRetTys.begin());
736*5ffd83dbSDimitry Andric     if (!TypesMatch)
737*5ffd83dbSDimitry Andric       NoTail("WebAssembly tail call requires caller and callee return types to "
738*5ffd83dbSDimitry Andric              "match");
739*5ffd83dbSDimitry Andric 
740*5ffd83dbSDimitry Andric     // If pointers to local stack values are passed, we cannot tail call
741*5ffd83dbSDimitry Andric     if (CLI.CB) {
742*5ffd83dbSDimitry Andric       for (auto &Arg : CLI.CB->args()) {
743*5ffd83dbSDimitry Andric         Value *Val = Arg.get();
744*5ffd83dbSDimitry Andric         // Trace the value back through pointer operations
745*5ffd83dbSDimitry Andric         while (true) {
746*5ffd83dbSDimitry Andric           Value *Src = Val->stripPointerCastsAndAliases();
747*5ffd83dbSDimitry Andric           if (auto *GEP = dyn_cast<GetElementPtrInst>(Src))
748*5ffd83dbSDimitry Andric             Src = GEP->getPointerOperand();
749*5ffd83dbSDimitry Andric           if (Val == Src)
750*5ffd83dbSDimitry Andric             break;
751*5ffd83dbSDimitry Andric           Val = Src;
7520b57cec5SDimitry Andric         }
753*5ffd83dbSDimitry Andric         if (isa<AllocaInst>(Val)) {
754*5ffd83dbSDimitry Andric           NoTail(
755*5ffd83dbSDimitry Andric               "WebAssembly does not support tail calling with stack arguments");
756*5ffd83dbSDimitry Andric           break;
7578bcb0991SDimitry Andric         }
7588bcb0991SDimitry Andric       }
7598bcb0991SDimitry Andric     }
7608bcb0991SDimitry Andric   }
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
7630b57cec5SDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
7640b57cec5SDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
7658bcb0991SDimitry Andric 
7668bcb0991SDimitry Andric   // The generic code may have added an sret argument. If we're lowering an
7678bcb0991SDimitry Andric   // invoke function, the ABI requires that the function pointer be the first
7688bcb0991SDimitry Andric   // argument, so we may have to swap the arguments.
7698bcb0991SDimitry Andric   if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 &&
7708bcb0991SDimitry Andric       Outs[0].Flags.isSRet()) {
7718bcb0991SDimitry Andric     std::swap(Outs[0], Outs[1]);
7728bcb0991SDimitry Andric     std::swap(OutVals[0], OutVals[1]);
7738bcb0991SDimitry Andric   }
7748bcb0991SDimitry Andric 
775*5ffd83dbSDimitry Andric   bool HasSwiftSelfArg = false;
776*5ffd83dbSDimitry Andric   bool HasSwiftErrorArg = false;
7770b57cec5SDimitry Andric   unsigned NumFixedArgs = 0;
7780b57cec5SDimitry Andric   for (unsigned I = 0; I < Outs.size(); ++I) {
7790b57cec5SDimitry Andric     const ISD::OutputArg &Out = Outs[I];
7800b57cec5SDimitry Andric     SDValue &OutVal = OutVals[I];
781*5ffd83dbSDimitry Andric     HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
782*5ffd83dbSDimitry Andric     HasSwiftErrorArg |= Out.Flags.isSwiftError();
7830b57cec5SDimitry Andric     if (Out.Flags.isNest())
7840b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
7850b57cec5SDimitry Andric     if (Out.Flags.isInAlloca())
7860b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
7870b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegs())
7880b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
7890b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegsLast())
7900b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
7910b57cec5SDimitry Andric     if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
7920b57cec5SDimitry Andric       auto &MFI = MF.getFrameInfo();
7930b57cec5SDimitry Andric       int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
794*5ffd83dbSDimitry Andric                                      Out.Flags.getNonZeroByValAlign(),
7950b57cec5SDimitry Andric                                      /*isSS=*/false);
7960b57cec5SDimitry Andric       SDValue SizeNode =
7970b57cec5SDimitry Andric           DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
7980b57cec5SDimitry Andric       SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
7990b57cec5SDimitry Andric       Chain = DAG.getMemcpy(
800*5ffd83dbSDimitry Andric           Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getNonZeroByValAlign(),
8010b57cec5SDimitry Andric           /*isVolatile*/ false, /*AlwaysInline=*/false,
8020b57cec5SDimitry Andric           /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
8030b57cec5SDimitry Andric       OutVal = FINode;
8040b57cec5SDimitry Andric     }
8050b57cec5SDimitry Andric     // Count the number of fixed args *after* legalization.
8060b57cec5SDimitry Andric     NumFixedArgs += Out.IsFixed;
8070b57cec5SDimitry Andric   }
8080b57cec5SDimitry Andric 
8090b57cec5SDimitry Andric   bool IsVarArg = CLI.IsVarArg;
8100b57cec5SDimitry Andric   auto PtrVT = getPointerTy(Layout);
8110b57cec5SDimitry Andric 
812*5ffd83dbSDimitry Andric   // For swiftcc, emit additional swiftself and swifterror arguments
813*5ffd83dbSDimitry Andric   // if there aren't. These additional arguments are also added for callee
814*5ffd83dbSDimitry Andric   // signature They are necessary to match callee and caller signature for
815*5ffd83dbSDimitry Andric   // indirect call.
816*5ffd83dbSDimitry Andric   if (CallConv == CallingConv::Swift) {
817*5ffd83dbSDimitry Andric     if (!HasSwiftSelfArg) {
818*5ffd83dbSDimitry Andric       NumFixedArgs++;
819*5ffd83dbSDimitry Andric       ISD::OutputArg Arg;
820*5ffd83dbSDimitry Andric       Arg.Flags.setSwiftSelf();
821*5ffd83dbSDimitry Andric       CLI.Outs.push_back(Arg);
822*5ffd83dbSDimitry Andric       SDValue ArgVal = DAG.getUNDEF(PtrVT);
823*5ffd83dbSDimitry Andric       CLI.OutVals.push_back(ArgVal);
824*5ffd83dbSDimitry Andric     }
825*5ffd83dbSDimitry Andric     if (!HasSwiftErrorArg) {
826*5ffd83dbSDimitry Andric       NumFixedArgs++;
827*5ffd83dbSDimitry Andric       ISD::OutputArg Arg;
828*5ffd83dbSDimitry Andric       Arg.Flags.setSwiftError();
829*5ffd83dbSDimitry Andric       CLI.Outs.push_back(Arg);
830*5ffd83dbSDimitry Andric       SDValue ArgVal = DAG.getUNDEF(PtrVT);
831*5ffd83dbSDimitry Andric       CLI.OutVals.push_back(ArgVal);
832*5ffd83dbSDimitry Andric     }
833*5ffd83dbSDimitry Andric   }
834*5ffd83dbSDimitry Andric 
8350b57cec5SDimitry Andric   // Analyze operands of the call, assigning locations to each operand.
8360b57cec5SDimitry Andric   SmallVector<CCValAssign, 16> ArgLocs;
8370b57cec5SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric   if (IsVarArg) {
8400b57cec5SDimitry Andric     // Outgoing non-fixed arguments are placed in a buffer. First
8410b57cec5SDimitry Andric     // compute their offsets and the total amount of buffer space needed.
8420b57cec5SDimitry Andric     for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
8430b57cec5SDimitry Andric       const ISD::OutputArg &Out = Outs[I];
8440b57cec5SDimitry Andric       SDValue &Arg = OutVals[I];
8450b57cec5SDimitry Andric       EVT VT = Arg.getValueType();
8460b57cec5SDimitry Andric       assert(VT != MVT::iPTR && "Legalized args should be concrete");
8470b57cec5SDimitry Andric       Type *Ty = VT.getTypeForEVT(*DAG.getContext());
848*5ffd83dbSDimitry Andric       Align Alignment =
849*5ffd83dbSDimitry Andric           std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty));
850*5ffd83dbSDimitry Andric       unsigned Offset =
851*5ffd83dbSDimitry Andric           CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment);
8520b57cec5SDimitry Andric       CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
8530b57cec5SDimitry Andric                                         Offset, VT.getSimpleVT(),
8540b57cec5SDimitry Andric                                         CCValAssign::Full));
8550b57cec5SDimitry Andric     }
8560b57cec5SDimitry Andric   }
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric   unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric   SDValue FINode;
8610b57cec5SDimitry Andric   if (IsVarArg && NumBytes) {
8620b57cec5SDimitry Andric     // For non-fixed arguments, next emit stores to store the argument values
8630b57cec5SDimitry Andric     // to the stack buffer at the offsets computed above.
8640b57cec5SDimitry Andric     int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
8650b57cec5SDimitry Andric                                                  Layout.getStackAlignment(),
8660b57cec5SDimitry Andric                                                  /*isSS=*/false);
8670b57cec5SDimitry Andric     unsigned ValNo = 0;
8680b57cec5SDimitry Andric     SmallVector<SDValue, 8> Chains;
8690b57cec5SDimitry Andric     for (SDValue Arg :
8700b57cec5SDimitry Andric          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
8710b57cec5SDimitry Andric       assert(ArgLocs[ValNo].getValNo() == ValNo &&
8720b57cec5SDimitry Andric              "ArgLocs should remain in order and only hold varargs args");
8730b57cec5SDimitry Andric       unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
8740b57cec5SDimitry Andric       FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
8750b57cec5SDimitry Andric       SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
8760b57cec5SDimitry Andric                                 DAG.getConstant(Offset, DL, PtrVT));
8770b57cec5SDimitry Andric       Chains.push_back(
8780b57cec5SDimitry Andric           DAG.getStore(Chain, DL, Arg, Add,
8790b57cec5SDimitry Andric                        MachinePointerInfo::getFixedStack(MF, FI, Offset), 0));
8800b57cec5SDimitry Andric     }
8810b57cec5SDimitry Andric     if (!Chains.empty())
8820b57cec5SDimitry Andric       Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
8830b57cec5SDimitry Andric   } else if (IsVarArg) {
8840b57cec5SDimitry Andric     FINode = DAG.getIntPtrConstant(0, DL);
8850b57cec5SDimitry Andric   }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric   if (Callee->getOpcode() == ISD::GlobalAddress) {
8880b57cec5SDimitry Andric     // If the callee is a GlobalAddress node (quite common, every direct call
8890b57cec5SDimitry Andric     // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
8900b57cec5SDimitry Andric     // doesn't at MO_GOT which is not needed for direct calls.
8910b57cec5SDimitry Andric     GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee);
8920b57cec5SDimitry Andric     Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL,
8930b57cec5SDimitry Andric                                         getPointerTy(DAG.getDataLayout()),
8940b57cec5SDimitry Andric                                         GA->getOffset());
8950b57cec5SDimitry Andric     Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
8960b57cec5SDimitry Andric                          getPointerTy(DAG.getDataLayout()), Callee);
8970b57cec5SDimitry Andric   }
8980b57cec5SDimitry Andric 
8990b57cec5SDimitry Andric   // Compute the operands for the CALLn node.
9000b57cec5SDimitry Andric   SmallVector<SDValue, 16> Ops;
9010b57cec5SDimitry Andric   Ops.push_back(Chain);
9020b57cec5SDimitry Andric   Ops.push_back(Callee);
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric   // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
9050b57cec5SDimitry Andric   // isn't reliable.
9060b57cec5SDimitry Andric   Ops.append(OutVals.begin(),
9070b57cec5SDimitry Andric              IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
9080b57cec5SDimitry Andric   // Add a pointer to the vararg buffer.
9090b57cec5SDimitry Andric   if (IsVarArg)
9100b57cec5SDimitry Andric     Ops.push_back(FINode);
9110b57cec5SDimitry Andric 
9120b57cec5SDimitry Andric   SmallVector<EVT, 8> InTys;
9130b57cec5SDimitry Andric   for (const auto &In : Ins) {
9140b57cec5SDimitry Andric     assert(!In.Flags.isByVal() && "byval is not valid for return values");
9150b57cec5SDimitry Andric     assert(!In.Flags.isNest() && "nest is not valid for return values");
9160b57cec5SDimitry Andric     if (In.Flags.isInAlloca())
9170b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
9180b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegs())
9190b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
9200b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegsLast())
9210b57cec5SDimitry Andric       fail(DL, DAG,
9220b57cec5SDimitry Andric            "WebAssembly hasn't implemented cons regs last return values");
923*5ffd83dbSDimitry Andric     // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
9240b57cec5SDimitry Andric     // registers.
9250b57cec5SDimitry Andric     InTys.push_back(In.VT);
9260b57cec5SDimitry Andric   }
9270b57cec5SDimitry Andric 
9280b57cec5SDimitry Andric   if (CLI.IsTailCall) {
9290b57cec5SDimitry Andric     // ret_calls do not return values to the current frame
9300b57cec5SDimitry Andric     SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
9310b57cec5SDimitry Andric     return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops);
9320b57cec5SDimitry Andric   }
9330b57cec5SDimitry Andric 
9340b57cec5SDimitry Andric   InTys.push_back(MVT::Other);
9350b57cec5SDimitry Andric   SDVTList InTyList = DAG.getVTList(InTys);
936*5ffd83dbSDimitry Andric   SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops);
9370b57cec5SDimitry Andric 
938*5ffd83dbSDimitry Andric   for (size_t I = 0; I < Ins.size(); ++I)
939*5ffd83dbSDimitry Andric     InVals.push_back(Res.getValue(I));
940*5ffd83dbSDimitry Andric 
941*5ffd83dbSDimitry Andric   // Return the chain
942*5ffd83dbSDimitry Andric   return Res.getValue(Ins.size());
9430b57cec5SDimitry Andric }
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric bool WebAssemblyTargetLowering::CanLowerReturn(
9460b57cec5SDimitry Andric     CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
9470b57cec5SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
9480b57cec5SDimitry Andric     LLVMContext & /*Context*/) const {
9498bcb0991SDimitry Andric   // WebAssembly can only handle returning tuples with multivalue enabled
9508bcb0991SDimitry Andric   return Subtarget->hasMultivalue() || Outs.size() <= 1;
9510b57cec5SDimitry Andric }
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerReturn(
9540b57cec5SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
9550b57cec5SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
9560b57cec5SDimitry Andric     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
9570b57cec5SDimitry Andric     SelectionDAG &DAG) const {
9588bcb0991SDimitry Andric   assert((Subtarget->hasMultivalue() || Outs.size() <= 1) &&
9598bcb0991SDimitry Andric          "MVP WebAssembly can only return up to one value");
9600b57cec5SDimitry Andric   if (!callingConvSupported(CallConv))
9610b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
9620b57cec5SDimitry Andric 
9630b57cec5SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
9640b57cec5SDimitry Andric   RetOps.append(OutVals.begin(), OutVals.end());
9650b57cec5SDimitry Andric   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric   // Record the number and types of the return values.
9680b57cec5SDimitry Andric   for (const ISD::OutputArg &Out : Outs) {
9690b57cec5SDimitry Andric     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
9700b57cec5SDimitry Andric     assert(!Out.Flags.isNest() && "nest is not valid for return values");
9710b57cec5SDimitry Andric     assert(Out.IsFixed && "non-fixed return value is not valid");
9720b57cec5SDimitry Andric     if (Out.Flags.isInAlloca())
9730b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
9740b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegs())
9750b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
9760b57cec5SDimitry Andric     if (Out.Flags.isInConsecutiveRegsLast())
9770b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
9780b57cec5SDimitry Andric   }
9790b57cec5SDimitry Andric 
9800b57cec5SDimitry Andric   return Chain;
9810b57cec5SDimitry Andric }
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFormalArguments(
9840b57cec5SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
9850b57cec5SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
9860b57cec5SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
9870b57cec5SDimitry Andric   if (!callingConvSupported(CallConv))
9880b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
9890b57cec5SDimitry Andric 
9900b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
9910b57cec5SDimitry Andric   auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
9920b57cec5SDimitry Andric 
9930b57cec5SDimitry Andric   // Set up the incoming ARGUMENTS value, which serves to represent the liveness
9940b57cec5SDimitry Andric   // of the incoming values before they're represented by virtual registers.
9950b57cec5SDimitry Andric   MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
9960b57cec5SDimitry Andric 
997*5ffd83dbSDimitry Andric   bool HasSwiftErrorArg = false;
998*5ffd83dbSDimitry Andric   bool HasSwiftSelfArg = false;
9990b57cec5SDimitry Andric   for (const ISD::InputArg &In : Ins) {
1000*5ffd83dbSDimitry Andric     HasSwiftSelfArg |= In.Flags.isSwiftSelf();
1001*5ffd83dbSDimitry Andric     HasSwiftErrorArg |= In.Flags.isSwiftError();
10020b57cec5SDimitry Andric     if (In.Flags.isInAlloca())
10030b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
10040b57cec5SDimitry Andric     if (In.Flags.isNest())
10050b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
10060b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegs())
10070b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
10080b57cec5SDimitry Andric     if (In.Flags.isInConsecutiveRegsLast())
10090b57cec5SDimitry Andric       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1010*5ffd83dbSDimitry Andric     // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
10110b57cec5SDimitry Andric     // registers.
10120b57cec5SDimitry Andric     InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
10130b57cec5SDimitry Andric                                            DAG.getTargetConstant(InVals.size(),
10140b57cec5SDimitry Andric                                                                  DL, MVT::i32))
10150b57cec5SDimitry Andric                              : DAG.getUNDEF(In.VT));
10160b57cec5SDimitry Andric 
10170b57cec5SDimitry Andric     // Record the number and types of arguments.
10180b57cec5SDimitry Andric     MFI->addParam(In.VT);
10190b57cec5SDimitry Andric   }
10200b57cec5SDimitry Andric 
1021*5ffd83dbSDimitry Andric   // For swiftcc, emit additional swiftself and swifterror arguments
1022*5ffd83dbSDimitry Andric   // if there aren't. These additional arguments are also added for callee
1023*5ffd83dbSDimitry Andric   // signature They are necessary to match callee and caller signature for
1024*5ffd83dbSDimitry Andric   // indirect call.
1025*5ffd83dbSDimitry Andric   auto PtrVT = getPointerTy(MF.getDataLayout());
1026*5ffd83dbSDimitry Andric   if (CallConv == CallingConv::Swift) {
1027*5ffd83dbSDimitry Andric     if (!HasSwiftSelfArg) {
1028*5ffd83dbSDimitry Andric       MFI->addParam(PtrVT);
1029*5ffd83dbSDimitry Andric     }
1030*5ffd83dbSDimitry Andric     if (!HasSwiftErrorArg) {
1031*5ffd83dbSDimitry Andric       MFI->addParam(PtrVT);
1032*5ffd83dbSDimitry Andric     }
1033*5ffd83dbSDimitry Andric   }
10340b57cec5SDimitry Andric   // Varargs are copied into a buffer allocated by the caller, and a pointer to
10350b57cec5SDimitry Andric   // the buffer is passed as an argument.
10360b57cec5SDimitry Andric   if (IsVarArg) {
10370b57cec5SDimitry Andric     MVT PtrVT = getPointerTy(MF.getDataLayout());
10388bcb0991SDimitry Andric     Register VarargVreg =
10390b57cec5SDimitry Andric         MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT));
10400b57cec5SDimitry Andric     MFI->setVarargBufferVreg(VarargVreg);
10410b57cec5SDimitry Andric     Chain = DAG.getCopyToReg(
10420b57cec5SDimitry Andric         Chain, DL, VarargVreg,
10430b57cec5SDimitry Andric         DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
10440b57cec5SDimitry Andric                     DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
10450b57cec5SDimitry Andric     MFI->addParam(PtrVT);
10460b57cec5SDimitry Andric   }
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric   // Record the number and types of arguments and results.
10490b57cec5SDimitry Andric   SmallVector<MVT, 4> Params;
10500b57cec5SDimitry Andric   SmallVector<MVT, 4> Results;
1051*5ffd83dbSDimitry Andric   computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(),
1052*5ffd83dbSDimitry Andric                       MF.getFunction(), DAG.getTarget(), Params, Results);
10530b57cec5SDimitry Andric   for (MVT VT : Results)
10540b57cec5SDimitry Andric     MFI->addResult(VT);
10550b57cec5SDimitry Andric   // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
10560b57cec5SDimitry Andric   // the param logic here with ComputeSignatureVTs
10570b57cec5SDimitry Andric   assert(MFI->getParams().size() == Params.size() &&
10580b57cec5SDimitry Andric          std::equal(MFI->getParams().begin(), MFI->getParams().end(),
10590b57cec5SDimitry Andric                     Params.begin()));
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric   return Chain;
10620b57cec5SDimitry Andric }
10630b57cec5SDimitry Andric 
10640b57cec5SDimitry Andric void WebAssemblyTargetLowering::ReplaceNodeResults(
10650b57cec5SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
10660b57cec5SDimitry Andric   switch (N->getOpcode()) {
10670b57cec5SDimitry Andric   case ISD::SIGN_EXTEND_INREG:
10680b57cec5SDimitry Andric     // Do not add any results, signifying that N should not be custom lowered
10690b57cec5SDimitry Andric     // after all. This happens because simd128 turns on custom lowering for
10700b57cec5SDimitry Andric     // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
10710b57cec5SDimitry Andric     // illegal type.
10720b57cec5SDimitry Andric     break;
10730b57cec5SDimitry Andric   default:
10740b57cec5SDimitry Andric     llvm_unreachable(
10750b57cec5SDimitry Andric         "ReplaceNodeResults not implemented for this op for WebAssembly!");
10760b57cec5SDimitry Andric   }
10770b57cec5SDimitry Andric }
10780b57cec5SDimitry Andric 
10790b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
10800b57cec5SDimitry Andric //  Custom lowering hooks.
10810b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
10820b57cec5SDimitry Andric 
10830b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
10840b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
10850b57cec5SDimitry Andric   SDLoc DL(Op);
10860b57cec5SDimitry Andric   switch (Op.getOpcode()) {
10870b57cec5SDimitry Andric   default:
10880b57cec5SDimitry Andric     llvm_unreachable("unimplemented operation lowering");
10890b57cec5SDimitry Andric     return SDValue();
10900b57cec5SDimitry Andric   case ISD::FrameIndex:
10910b57cec5SDimitry Andric     return LowerFrameIndex(Op, DAG);
10920b57cec5SDimitry Andric   case ISD::GlobalAddress:
10930b57cec5SDimitry Andric     return LowerGlobalAddress(Op, DAG);
10940b57cec5SDimitry Andric   case ISD::ExternalSymbol:
10950b57cec5SDimitry Andric     return LowerExternalSymbol(Op, DAG);
10960b57cec5SDimitry Andric   case ISD::JumpTable:
10970b57cec5SDimitry Andric     return LowerJumpTable(Op, DAG);
10980b57cec5SDimitry Andric   case ISD::BR_JT:
10990b57cec5SDimitry Andric     return LowerBR_JT(Op, DAG);
11000b57cec5SDimitry Andric   case ISD::VASTART:
11010b57cec5SDimitry Andric     return LowerVASTART(Op, DAG);
11020b57cec5SDimitry Andric   case ISD::BlockAddress:
11030b57cec5SDimitry Andric   case ISD::BRIND:
11040b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
11050b57cec5SDimitry Andric     return SDValue();
11060b57cec5SDimitry Andric   case ISD::RETURNADDR:
11070b57cec5SDimitry Andric     return LowerRETURNADDR(Op, DAG);
11080b57cec5SDimitry Andric   case ISD::FRAMEADDR:
11090b57cec5SDimitry Andric     return LowerFRAMEADDR(Op, DAG);
11100b57cec5SDimitry Andric   case ISD::CopyToReg:
11110b57cec5SDimitry Andric     return LowerCopyToReg(Op, DAG);
11120b57cec5SDimitry Andric   case ISD::EXTRACT_VECTOR_ELT:
11130b57cec5SDimitry Andric   case ISD::INSERT_VECTOR_ELT:
11140b57cec5SDimitry Andric     return LowerAccessVectorElement(Op, DAG);
11150b57cec5SDimitry Andric   case ISD::INTRINSIC_VOID:
11160b57cec5SDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
11170b57cec5SDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
11180b57cec5SDimitry Andric     return LowerIntrinsic(Op, DAG);
11190b57cec5SDimitry Andric   case ISD::SIGN_EXTEND_INREG:
11200b57cec5SDimitry Andric     return LowerSIGN_EXTEND_INREG(Op, DAG);
11210b57cec5SDimitry Andric   case ISD::BUILD_VECTOR:
11220b57cec5SDimitry Andric     return LowerBUILD_VECTOR(Op, DAG);
11230b57cec5SDimitry Andric   case ISD::VECTOR_SHUFFLE:
11240b57cec5SDimitry Andric     return LowerVECTOR_SHUFFLE(Op, DAG);
1125480093f4SDimitry Andric   case ISD::SETCC:
1126480093f4SDimitry Andric     return LowerSETCC(Op, DAG);
11270b57cec5SDimitry Andric   case ISD::SHL:
11280b57cec5SDimitry Andric   case ISD::SRA:
11290b57cec5SDimitry Andric   case ISD::SRL:
11300b57cec5SDimitry Andric     return LowerShift(Op, DAG);
11310b57cec5SDimitry Andric   }
11320b57cec5SDimitry Andric }
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
11350b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
11360b57cec5SDimitry Andric   SDValue Src = Op.getOperand(2);
11370b57cec5SDimitry Andric   if (isa<FrameIndexSDNode>(Src.getNode())) {
11380b57cec5SDimitry Andric     // CopyToReg nodes don't support FrameIndex operands. Other targets select
11390b57cec5SDimitry Andric     // the FI to some LEA-like instruction, but since we don't have that, we
11400b57cec5SDimitry Andric     // need to insert some kind of instruction that can take an FI operand and
11410b57cec5SDimitry Andric     // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
11420b57cec5SDimitry Andric     // local.copy between Op and its FI operand.
11430b57cec5SDimitry Andric     SDValue Chain = Op.getOperand(0);
11440b57cec5SDimitry Andric     SDLoc DL(Op);
11450b57cec5SDimitry Andric     unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
11460b57cec5SDimitry Andric     EVT VT = Src.getValueType();
11470b57cec5SDimitry Andric     SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
11480b57cec5SDimitry Andric                                                    : WebAssembly::COPY_I64,
11490b57cec5SDimitry Andric                                     DL, VT, Src),
11500b57cec5SDimitry Andric                  0);
11510b57cec5SDimitry Andric     return Op.getNode()->getNumValues() == 1
11520b57cec5SDimitry Andric                ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
11530b57cec5SDimitry Andric                : DAG.getCopyToReg(Chain, DL, Reg, Copy,
11540b57cec5SDimitry Andric                                   Op.getNumOperands() == 4 ? Op.getOperand(3)
11550b57cec5SDimitry Andric                                                            : SDValue());
11560b57cec5SDimitry Andric   }
11570b57cec5SDimitry Andric   return SDValue();
11580b57cec5SDimitry Andric }
11590b57cec5SDimitry Andric 
11600b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
11610b57cec5SDimitry Andric                                                    SelectionDAG &DAG) const {
11620b57cec5SDimitry Andric   int FI = cast<FrameIndexSDNode>(Op)->getIndex();
11630b57cec5SDimitry Andric   return DAG.getTargetFrameIndex(FI, Op.getValueType());
11640b57cec5SDimitry Andric }
11650b57cec5SDimitry Andric 
11660b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op,
11670b57cec5SDimitry Andric                                                    SelectionDAG &DAG) const {
11680b57cec5SDimitry Andric   SDLoc DL(Op);
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric   if (!Subtarget->getTargetTriple().isOSEmscripten()) {
11710b57cec5SDimitry Andric     fail(DL, DAG,
11720b57cec5SDimitry Andric          "Non-Emscripten WebAssembly hasn't implemented "
11730b57cec5SDimitry Andric          "__builtin_return_address");
11740b57cec5SDimitry Andric     return SDValue();
11750b57cec5SDimitry Andric   }
11760b57cec5SDimitry Andric 
11770b57cec5SDimitry Andric   if (verifyReturnAddressArgumentIsConstant(Op, DAG))
11780b57cec5SDimitry Andric     return SDValue();
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric   unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
11818bcb0991SDimitry Andric   MakeLibCallOptions CallOptions;
11820b57cec5SDimitry Andric   return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(),
11838bcb0991SDimitry Andric                      {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL)
11840b57cec5SDimitry Andric       .first;
11850b57cec5SDimitry Andric }
11860b57cec5SDimitry Andric 
11870b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
11880b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
11890b57cec5SDimitry Andric   // Non-zero depths are not supported by WebAssembly currently. Use the
11900b57cec5SDimitry Andric   // legalizer's default expansion, which is to return 0 (what this function is
11910b57cec5SDimitry Andric   // documented to do).
11920b57cec5SDimitry Andric   if (Op.getConstantOperandVal(0) > 0)
11930b57cec5SDimitry Andric     return SDValue();
11940b57cec5SDimitry Andric 
11950b57cec5SDimitry Andric   DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
11960b57cec5SDimitry Andric   EVT VT = Op.getValueType();
11978bcb0991SDimitry Andric   Register FP =
11980b57cec5SDimitry Andric       Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
11990b57cec5SDimitry Andric   return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
12000b57cec5SDimitry Andric }
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
12030b57cec5SDimitry Andric                                                       SelectionDAG &DAG) const {
12040b57cec5SDimitry Andric   SDLoc DL(Op);
12050b57cec5SDimitry Andric   const auto *GA = cast<GlobalAddressSDNode>(Op);
12060b57cec5SDimitry Andric   EVT VT = Op.getValueType();
12070b57cec5SDimitry Andric   assert(GA->getTargetFlags() == 0 &&
12080b57cec5SDimitry Andric          "Unexpected target flags on generic GlobalAddressSDNode");
12090b57cec5SDimitry Andric   if (GA->getAddressSpace() != 0)
12100b57cec5SDimitry Andric     fail(DL, DAG, "WebAssembly only expects the 0 address space");
12110b57cec5SDimitry Andric 
12120b57cec5SDimitry Andric   unsigned OperandFlags = 0;
12130b57cec5SDimitry Andric   if (isPositionIndependent()) {
12140b57cec5SDimitry Andric     const GlobalValue *GV = GA->getGlobal();
12150b57cec5SDimitry Andric     if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) {
12160b57cec5SDimitry Andric       MachineFunction &MF = DAG.getMachineFunction();
12170b57cec5SDimitry Andric       MVT PtrVT = getPointerTy(MF.getDataLayout());
12180b57cec5SDimitry Andric       const char *BaseName;
12190b57cec5SDimitry Andric       if (GV->getValueType()->isFunctionTy()) {
12200b57cec5SDimitry Andric         BaseName = MF.createExternalSymbolName("__table_base");
12210b57cec5SDimitry Andric         OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL;
12220b57cec5SDimitry Andric       }
12230b57cec5SDimitry Andric       else {
12240b57cec5SDimitry Andric         BaseName = MF.createExternalSymbolName("__memory_base");
12250b57cec5SDimitry Andric         OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL;
12260b57cec5SDimitry Andric       }
12270b57cec5SDimitry Andric       SDValue BaseAddr =
12280b57cec5SDimitry Andric           DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
12290b57cec5SDimitry Andric                       DAG.getTargetExternalSymbol(BaseName, PtrVT));
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric       SDValue SymAddr = DAG.getNode(
12320b57cec5SDimitry Andric           WebAssemblyISD::WrapperPIC, DL, VT,
12330b57cec5SDimitry Andric           DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
12340b57cec5SDimitry Andric                                      OperandFlags));
12350b57cec5SDimitry Andric 
12360b57cec5SDimitry Andric       return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
12370b57cec5SDimitry Andric     } else {
12380b57cec5SDimitry Andric       OperandFlags = WebAssemblyII::MO_GOT;
12390b57cec5SDimitry Andric     }
12400b57cec5SDimitry Andric   }
12410b57cec5SDimitry Andric 
12420b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
12430b57cec5SDimitry Andric                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
12440b57cec5SDimitry Andric                                                 GA->getOffset(), OperandFlags));
12450b57cec5SDimitry Andric }
12460b57cec5SDimitry Andric 
12470b57cec5SDimitry Andric SDValue
12480b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
12490b57cec5SDimitry Andric                                                SelectionDAG &DAG) const {
12500b57cec5SDimitry Andric   SDLoc DL(Op);
12510b57cec5SDimitry Andric   const auto *ES = cast<ExternalSymbolSDNode>(Op);
12520b57cec5SDimitry Andric   EVT VT = Op.getValueType();
12530b57cec5SDimitry Andric   assert(ES->getTargetFlags() == 0 &&
12540b57cec5SDimitry Andric          "Unexpected target flags on generic ExternalSymbolSDNode");
12550b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
12560b57cec5SDimitry Andric                      DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
12570b57cec5SDimitry Andric }
12580b57cec5SDimitry Andric 
12590b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
12600b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
12610b57cec5SDimitry Andric   // There's no need for a Wrapper node because we always incorporate a jump
12620b57cec5SDimitry Andric   // table operand into a BR_TABLE instruction, rather than ever
12630b57cec5SDimitry Andric   // materializing it in a register.
12640b57cec5SDimitry Andric   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
12650b57cec5SDimitry Andric   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
12660b57cec5SDimitry Andric                                 JT->getTargetFlags());
12670b57cec5SDimitry Andric }
12680b57cec5SDimitry Andric 
12690b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
12700b57cec5SDimitry Andric                                               SelectionDAG &DAG) const {
12710b57cec5SDimitry Andric   SDLoc DL(Op);
12720b57cec5SDimitry Andric   SDValue Chain = Op.getOperand(0);
12730b57cec5SDimitry Andric   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
12740b57cec5SDimitry Andric   SDValue Index = Op.getOperand(2);
12750b57cec5SDimitry Andric   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric   SmallVector<SDValue, 8> Ops;
12780b57cec5SDimitry Andric   Ops.push_back(Chain);
12790b57cec5SDimitry Andric   Ops.push_back(Index);
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
12820b57cec5SDimitry Andric   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
12830b57cec5SDimitry Andric 
12840b57cec5SDimitry Andric   // Add an operand for each case.
12850b57cec5SDimitry Andric   for (auto MBB : MBBs)
12860b57cec5SDimitry Andric     Ops.push_back(DAG.getBasicBlock(MBB));
12870b57cec5SDimitry Andric 
1288*5ffd83dbSDimitry Andric   // Add the first MBB as a dummy default target for now. This will be replaced
1289*5ffd83dbSDimitry Andric   // with the proper default target (and the preceding range check eliminated)
1290*5ffd83dbSDimitry Andric   // if possible by WebAssemblyFixBrTableDefaults.
1291*5ffd83dbSDimitry Andric   Ops.push_back(DAG.getBasicBlock(*MBBs.begin()));
12920b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
12930b57cec5SDimitry Andric }
12940b57cec5SDimitry Andric 
12950b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
12960b57cec5SDimitry Andric                                                 SelectionDAG &DAG) const {
12970b57cec5SDimitry Andric   SDLoc DL(Op);
12980b57cec5SDimitry Andric   EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
12990b57cec5SDimitry Andric 
13000b57cec5SDimitry Andric   auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
13010b57cec5SDimitry Andric   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
13020b57cec5SDimitry Andric 
13030b57cec5SDimitry Andric   SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
13040b57cec5SDimitry Andric                                     MFI->getVarargBufferVreg(), PtrVT);
13050b57cec5SDimitry Andric   return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
13060b57cec5SDimitry Andric                       MachinePointerInfo(SV), 0);
13070b57cec5SDimitry Andric }
13080b57cec5SDimitry Andric 
13090b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
13100b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
13110b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
13120b57cec5SDimitry Andric   unsigned IntNo;
13130b57cec5SDimitry Andric   switch (Op.getOpcode()) {
13140b57cec5SDimitry Andric   case ISD::INTRINSIC_VOID:
13150b57cec5SDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
13160b57cec5SDimitry Andric     IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
13170b57cec5SDimitry Andric     break;
13180b57cec5SDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
13190b57cec5SDimitry Andric     IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
13200b57cec5SDimitry Andric     break;
13210b57cec5SDimitry Andric   default:
13220b57cec5SDimitry Andric     llvm_unreachable("Invalid intrinsic");
13230b57cec5SDimitry Andric   }
13240b57cec5SDimitry Andric   SDLoc DL(Op);
13250b57cec5SDimitry Andric 
13260b57cec5SDimitry Andric   switch (IntNo) {
13270b57cec5SDimitry Andric   default:
13280b57cec5SDimitry Andric     return SDValue(); // Don't custom lower most intrinsics.
13290b57cec5SDimitry Andric 
13300b57cec5SDimitry Andric   case Intrinsic::wasm_lsda: {
13310b57cec5SDimitry Andric     EVT VT = Op.getValueType();
13320b57cec5SDimitry Andric     const TargetLowering &TLI = DAG.getTargetLoweringInfo();
13330b57cec5SDimitry Andric     MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
13340b57cec5SDimitry Andric     auto &Context = MF.getMMI().getContext();
13350b57cec5SDimitry Andric     MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
13360b57cec5SDimitry Andric                                             Twine(MF.getFunctionNumber()));
13370b57cec5SDimitry Andric     return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
13380b57cec5SDimitry Andric                        DAG.getMCSymbol(S, PtrVT));
13390b57cec5SDimitry Andric   }
13400b57cec5SDimitry Andric 
13410b57cec5SDimitry Andric   case Intrinsic::wasm_throw: {
13420b57cec5SDimitry Andric     // We only support C++ exceptions for now
13430b57cec5SDimitry Andric     int Tag = cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
13440b57cec5SDimitry Andric     if (Tag != CPP_EXCEPTION)
13450b57cec5SDimitry Andric       llvm_unreachable("Invalid tag!");
13460b57cec5SDimitry Andric     const TargetLowering &TLI = DAG.getTargetLoweringInfo();
13470b57cec5SDimitry Andric     MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
13480b57cec5SDimitry Andric     const char *SymName = MF.createExternalSymbolName("__cpp_exception");
13490b57cec5SDimitry Andric     SDValue SymNode = DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
13500b57cec5SDimitry Andric                                   DAG.getTargetExternalSymbol(SymName, PtrVT));
13510b57cec5SDimitry Andric     return DAG.getNode(WebAssemblyISD::THROW, DL,
13520b57cec5SDimitry Andric                        MVT::Other, // outchain type
13530b57cec5SDimitry Andric                        {
13540b57cec5SDimitry Andric                            Op.getOperand(0), // inchain
13550b57cec5SDimitry Andric                            SymNode,          // exception symbol
13560b57cec5SDimitry Andric                            Op.getOperand(3)  // thrown value
13570b57cec5SDimitry Andric                        });
13580b57cec5SDimitry Andric   }
1359*5ffd83dbSDimitry Andric 
1360*5ffd83dbSDimitry Andric   case Intrinsic::wasm_shuffle: {
1361*5ffd83dbSDimitry Andric     // Drop in-chain and replace undefs, but otherwise pass through unchanged
1362*5ffd83dbSDimitry Andric     SDValue Ops[18];
1363*5ffd83dbSDimitry Andric     size_t OpIdx = 0;
1364*5ffd83dbSDimitry Andric     Ops[OpIdx++] = Op.getOperand(1);
1365*5ffd83dbSDimitry Andric     Ops[OpIdx++] = Op.getOperand(2);
1366*5ffd83dbSDimitry Andric     while (OpIdx < 18) {
1367*5ffd83dbSDimitry Andric       const SDValue &MaskIdx = Op.getOperand(OpIdx + 1);
1368*5ffd83dbSDimitry Andric       if (MaskIdx.isUndef() ||
1369*5ffd83dbSDimitry Andric           cast<ConstantSDNode>(MaskIdx.getNode())->getZExtValue() >= 32) {
1370*5ffd83dbSDimitry Andric         Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32);
1371*5ffd83dbSDimitry Andric       } else {
1372*5ffd83dbSDimitry Andric         Ops[OpIdx++] = MaskIdx;
1373*5ffd83dbSDimitry Andric       }
1374*5ffd83dbSDimitry Andric     }
1375*5ffd83dbSDimitry Andric     return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
1376*5ffd83dbSDimitry Andric   }
13770b57cec5SDimitry Andric   }
13780b57cec5SDimitry Andric }
13790b57cec5SDimitry Andric 
13800b57cec5SDimitry Andric SDValue
13810b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
13820b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
13830b57cec5SDimitry Andric   SDLoc DL(Op);
13840b57cec5SDimitry Andric   // If sign extension operations are disabled, allow sext_inreg only if operand
1385*5ffd83dbSDimitry Andric   // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign
1386*5ffd83dbSDimitry Andric   // extension operations, but allowing sext_inreg in this context lets us have
1387*5ffd83dbSDimitry Andric   // simple patterns to select extract_lane_s instructions. Expanding sext_inreg
1388*5ffd83dbSDimitry Andric   // everywhere would be simpler in this file, but would necessitate large and
1389*5ffd83dbSDimitry Andric   // brittle patterns to undo the expansion and select extract_lane_s
1390*5ffd83dbSDimitry Andric   // instructions.
13910b57cec5SDimitry Andric   assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
1392*5ffd83dbSDimitry Andric   if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT)
1393*5ffd83dbSDimitry Andric     return SDValue();
1394*5ffd83dbSDimitry Andric 
13950b57cec5SDimitry Andric   const SDValue &Extract = Op.getOperand(0);
13960b57cec5SDimitry Andric   MVT VecT = Extract.getOperand(0).getSimpleValueType();
1397*5ffd83dbSDimitry Andric   if (VecT.getVectorElementType().getSizeInBits() > 32)
1398*5ffd83dbSDimitry Andric     return SDValue();
1399*5ffd83dbSDimitry Andric   MVT ExtractedLaneT =
1400*5ffd83dbSDimitry Andric       cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT();
14010b57cec5SDimitry Andric   MVT ExtractedVecT =
14020b57cec5SDimitry Andric       MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits());
14030b57cec5SDimitry Andric   if (ExtractedVecT == VecT)
14040b57cec5SDimitry Andric     return Op;
1405*5ffd83dbSDimitry Andric 
14060b57cec5SDimitry Andric   // Bitcast vector to appropriate type to ensure ISel pattern coverage
1407*5ffd83dbSDimitry Andric   const SDNode *Index = Extract.getOperand(1).getNode();
1408*5ffd83dbSDimitry Andric   if (!isa<ConstantSDNode>(Index))
1409*5ffd83dbSDimitry Andric     return SDValue();
1410*5ffd83dbSDimitry Andric   unsigned IndexVal = cast<ConstantSDNode>(Index)->getZExtValue();
14110b57cec5SDimitry Andric   unsigned Scale =
14120b57cec5SDimitry Andric       ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements();
14130b57cec5SDimitry Andric   assert(Scale > 1);
14140b57cec5SDimitry Andric   SDValue NewIndex =
1415*5ffd83dbSDimitry Andric       DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0));
14160b57cec5SDimitry Andric   SDValue NewExtract = DAG.getNode(
14170b57cec5SDimitry Andric       ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(),
14180b57cec5SDimitry Andric       DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex);
1419*5ffd83dbSDimitry Andric   return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract,
1420*5ffd83dbSDimitry Andric                      Op.getOperand(1));
14210b57cec5SDimitry Andric }
14220b57cec5SDimitry Andric 
14230b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
14240b57cec5SDimitry Andric                                                      SelectionDAG &DAG) const {
14250b57cec5SDimitry Andric   SDLoc DL(Op);
14260b57cec5SDimitry Andric   const EVT VecT = Op.getValueType();
14270b57cec5SDimitry Andric   const EVT LaneT = Op.getOperand(0).getValueType();
14280b57cec5SDimitry Andric   const size_t Lanes = Op.getNumOperands();
1429*5ffd83dbSDimitry Andric   bool CanSwizzle = VecT == MVT::v16i8;
14308bcb0991SDimitry Andric 
14318bcb0991SDimitry Andric   // BUILD_VECTORs are lowered to the instruction that initializes the highest
14328bcb0991SDimitry Andric   // possible number of lanes at once followed by a sequence of replace_lane
14338bcb0991SDimitry Andric   // instructions to individually initialize any remaining lanes.
14348bcb0991SDimitry Andric 
14358bcb0991SDimitry Andric   // TODO: Tune this. For example, lanewise swizzling is very expensive, so
14368bcb0991SDimitry Andric   // swizzled lanes should be given greater weight.
14378bcb0991SDimitry Andric 
14388bcb0991SDimitry Andric   // TODO: Investigate building vectors by shuffling together vectors built by
14398bcb0991SDimitry Andric   // separately specialized means.
14408bcb0991SDimitry Andric 
14410b57cec5SDimitry Andric   auto IsConstant = [](const SDValue &V) {
14420b57cec5SDimitry Andric     return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
14430b57cec5SDimitry Andric   };
14440b57cec5SDimitry Andric 
14458bcb0991SDimitry Andric   // Returns the source vector and index vector pair if they exist. Checks for:
14468bcb0991SDimitry Andric   //   (extract_vector_elt
14478bcb0991SDimitry Andric   //     $src,
14488bcb0991SDimitry Andric   //     (sign_extend_inreg (extract_vector_elt $indices, $i))
14498bcb0991SDimitry Andric   //   )
14508bcb0991SDimitry Andric   auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) {
14518bcb0991SDimitry Andric     auto Bail = std::make_pair(SDValue(), SDValue());
14528bcb0991SDimitry Andric     if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
14538bcb0991SDimitry Andric       return Bail;
14548bcb0991SDimitry Andric     const SDValue &SwizzleSrc = Lane->getOperand(0);
14558bcb0991SDimitry Andric     const SDValue &IndexExt = Lane->getOperand(1);
14568bcb0991SDimitry Andric     if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG)
14578bcb0991SDimitry Andric       return Bail;
14588bcb0991SDimitry Andric     const SDValue &Index = IndexExt->getOperand(0);
14598bcb0991SDimitry Andric     if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
14608bcb0991SDimitry Andric       return Bail;
14618bcb0991SDimitry Andric     const SDValue &SwizzleIndices = Index->getOperand(0);
14628bcb0991SDimitry Andric     if (SwizzleSrc.getValueType() != MVT::v16i8 ||
14638bcb0991SDimitry Andric         SwizzleIndices.getValueType() != MVT::v16i8 ||
14648bcb0991SDimitry Andric         Index->getOperand(1)->getOpcode() != ISD::Constant ||
14658bcb0991SDimitry Andric         Index->getConstantOperandVal(1) != I)
14668bcb0991SDimitry Andric       return Bail;
14678bcb0991SDimitry Andric     return std::make_pair(SwizzleSrc, SwizzleIndices);
14688bcb0991SDimitry Andric   };
14698bcb0991SDimitry Andric 
14708bcb0991SDimitry Andric   using ValueEntry = std::pair<SDValue, size_t>;
14718bcb0991SDimitry Andric   SmallVector<ValueEntry, 16> SplatValueCounts;
14728bcb0991SDimitry Andric 
14738bcb0991SDimitry Andric   using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>;
14748bcb0991SDimitry Andric   SmallVector<SwizzleEntry, 16> SwizzleCounts;
14758bcb0991SDimitry Andric 
14768bcb0991SDimitry Andric   auto AddCount = [](auto &Counts, const auto &Val) {
14778bcb0991SDimitry Andric     auto CountIt = std::find_if(Counts.begin(), Counts.end(),
14788bcb0991SDimitry Andric                                 [&Val](auto E) { return E.first == Val; });
14798bcb0991SDimitry Andric     if (CountIt == Counts.end()) {
14808bcb0991SDimitry Andric       Counts.emplace_back(Val, 1);
14810b57cec5SDimitry Andric     } else {
14820b57cec5SDimitry Andric       CountIt->second++;
14830b57cec5SDimitry Andric     }
14848bcb0991SDimitry Andric   };
14850b57cec5SDimitry Andric 
14868bcb0991SDimitry Andric   auto GetMostCommon = [](auto &Counts) {
14878bcb0991SDimitry Andric     auto CommonIt =
14888bcb0991SDimitry Andric         std::max_element(Counts.begin(), Counts.end(),
14898bcb0991SDimitry Andric                          [](auto A, auto B) { return A.second < B.second; });
14908bcb0991SDimitry Andric     assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
14918bcb0991SDimitry Andric     return *CommonIt;
14928bcb0991SDimitry Andric   };
14938bcb0991SDimitry Andric 
14948bcb0991SDimitry Andric   size_t NumConstantLanes = 0;
14958bcb0991SDimitry Andric 
14968bcb0991SDimitry Andric   // Count eligible lanes for each type of vector creation op
14978bcb0991SDimitry Andric   for (size_t I = 0; I < Lanes; ++I) {
14988bcb0991SDimitry Andric     const SDValue &Lane = Op->getOperand(I);
14998bcb0991SDimitry Andric     if (Lane.isUndef())
15008bcb0991SDimitry Andric       continue;
15018bcb0991SDimitry Andric 
15028bcb0991SDimitry Andric     AddCount(SplatValueCounts, Lane);
15038bcb0991SDimitry Andric 
15048bcb0991SDimitry Andric     if (IsConstant(Lane)) {
15058bcb0991SDimitry Andric       NumConstantLanes++;
15068bcb0991SDimitry Andric     } else if (CanSwizzle) {
15078bcb0991SDimitry Andric       auto SwizzleSrcs = GetSwizzleSrcs(I, Lane);
15088bcb0991SDimitry Andric       if (SwizzleSrcs.first)
15098bcb0991SDimitry Andric         AddCount(SwizzleCounts, SwizzleSrcs);
15108bcb0991SDimitry Andric     }
15118bcb0991SDimitry Andric   }
15128bcb0991SDimitry Andric 
15138bcb0991SDimitry Andric   SDValue SplatValue;
15148bcb0991SDimitry Andric   size_t NumSplatLanes;
15158bcb0991SDimitry Andric   std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts);
15168bcb0991SDimitry Andric 
15178bcb0991SDimitry Andric   SDValue SwizzleSrc;
15188bcb0991SDimitry Andric   SDValue SwizzleIndices;
15198bcb0991SDimitry Andric   size_t NumSwizzleLanes = 0;
15208bcb0991SDimitry Andric   if (SwizzleCounts.size())
15218bcb0991SDimitry Andric     std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices),
15228bcb0991SDimitry Andric                           NumSwizzleLanes) = GetMostCommon(SwizzleCounts);
15238bcb0991SDimitry Andric 
15248bcb0991SDimitry Andric   // Predicate returning true if the lane is properly initialized by the
15258bcb0991SDimitry Andric   // original instruction
15268bcb0991SDimitry Andric   std::function<bool(size_t, const SDValue &)> IsLaneConstructed;
15278bcb0991SDimitry Andric   SDValue Result;
15288bcb0991SDimitry Andric   // Prefer swizzles over vector consts over splats
15298bcb0991SDimitry Andric   if (NumSwizzleLanes >= NumSplatLanes &&
1530*5ffd83dbSDimitry Andric       (!Subtarget->hasUnimplementedSIMD128() ||
1531*5ffd83dbSDimitry Andric        NumSwizzleLanes >= NumConstantLanes)) {
15328bcb0991SDimitry Andric     Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc,
15338bcb0991SDimitry Andric                          SwizzleIndices);
15348bcb0991SDimitry Andric     auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices);
15358bcb0991SDimitry Andric     IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) {
15368bcb0991SDimitry Andric       return Swizzled == GetSwizzleSrcs(I, Lane);
15378bcb0991SDimitry Andric     };
1538*5ffd83dbSDimitry Andric   } else if (NumConstantLanes >= NumSplatLanes &&
1539*5ffd83dbSDimitry Andric              Subtarget->hasUnimplementedSIMD128()) {
15400b57cec5SDimitry Andric     SmallVector<SDValue, 16> ConstLanes;
15410b57cec5SDimitry Andric     for (const SDValue &Lane : Op->op_values()) {
15420b57cec5SDimitry Andric       if (IsConstant(Lane)) {
15430b57cec5SDimitry Andric         ConstLanes.push_back(Lane);
15440b57cec5SDimitry Andric       } else if (LaneT.isFloatingPoint()) {
15450b57cec5SDimitry Andric         ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
15460b57cec5SDimitry Andric       } else {
15470b57cec5SDimitry Andric         ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
15480b57cec5SDimitry Andric       }
15490b57cec5SDimitry Andric     }
15508bcb0991SDimitry Andric     Result = DAG.getBuildVector(VecT, DL, ConstLanes);
15518bcb0991SDimitry Andric     IsLaneConstructed = [&](size_t _, const SDValue &Lane) {
15528bcb0991SDimitry Andric       return IsConstant(Lane);
15538bcb0991SDimitry Andric     };
15548bcb0991SDimitry Andric   }
15558bcb0991SDimitry Andric   if (!Result) {
15568bcb0991SDimitry Andric     // Use a splat, but possibly a load_splat
15578bcb0991SDimitry Andric     LoadSDNode *SplattedLoad;
1558*5ffd83dbSDimitry Andric     if ((SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) &&
15598bcb0991SDimitry Andric         SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) {
1560480093f4SDimitry Andric       Result = DAG.getMemIntrinsicNode(
1561480093f4SDimitry Andric           WebAssemblyISD::LOAD_SPLAT, DL, DAG.getVTList(VecT),
1562480093f4SDimitry Andric           {SplattedLoad->getChain(), SplattedLoad->getBasePtr(),
1563480093f4SDimitry Andric            SplattedLoad->getOffset()},
1564480093f4SDimitry Andric           SplattedLoad->getMemoryVT(), SplattedLoad->getMemOperand());
15658bcb0991SDimitry Andric     } else {
15668bcb0991SDimitry Andric       Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
15678bcb0991SDimitry Andric     }
15688bcb0991SDimitry Andric     IsLaneConstructed = [&](size_t _, const SDValue &Lane) {
15698bcb0991SDimitry Andric       return Lane == SplatValue;
15708bcb0991SDimitry Andric     };
15718bcb0991SDimitry Andric   }
15728bcb0991SDimitry Andric 
15738bcb0991SDimitry Andric   // Add replace_lane instructions for any unhandled values
15740b57cec5SDimitry Andric   for (size_t I = 0; I < Lanes; ++I) {
15750b57cec5SDimitry Andric     const SDValue &Lane = Op->getOperand(I);
15768bcb0991SDimitry Andric     if (!Lane.isUndef() && !IsLaneConstructed(I, Lane))
15770b57cec5SDimitry Andric       Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
15780b57cec5SDimitry Andric                            DAG.getConstant(I, DL, MVT::i32));
15790b57cec5SDimitry Andric   }
15808bcb0991SDimitry Andric 
15810b57cec5SDimitry Andric   return Result;
15820b57cec5SDimitry Andric }
15830b57cec5SDimitry Andric 
15840b57cec5SDimitry Andric SDValue
15850b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
15860b57cec5SDimitry Andric                                                SelectionDAG &DAG) const {
15870b57cec5SDimitry Andric   SDLoc DL(Op);
15880b57cec5SDimitry Andric   ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
15890b57cec5SDimitry Andric   MVT VecType = Op.getOperand(0).getSimpleValueType();
15900b57cec5SDimitry Andric   assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
15910b57cec5SDimitry Andric   size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
15920b57cec5SDimitry Andric 
15930b57cec5SDimitry Andric   // Space for two vector args and sixteen mask indices
15940b57cec5SDimitry Andric   SDValue Ops[18];
15950b57cec5SDimitry Andric   size_t OpIdx = 0;
15960b57cec5SDimitry Andric   Ops[OpIdx++] = Op.getOperand(0);
15970b57cec5SDimitry Andric   Ops[OpIdx++] = Op.getOperand(1);
15980b57cec5SDimitry Andric 
15990b57cec5SDimitry Andric   // Expand mask indices to byte indices and materialize them as operands
16000b57cec5SDimitry Andric   for (int M : Mask) {
16010b57cec5SDimitry Andric     for (size_t J = 0; J < LaneBytes; ++J) {
16020b57cec5SDimitry Andric       // Lower undefs (represented by -1 in mask) to zero
16030b57cec5SDimitry Andric       uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J;
16040b57cec5SDimitry Andric       Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
16050b57cec5SDimitry Andric     }
16060b57cec5SDimitry Andric   }
16070b57cec5SDimitry Andric 
16080b57cec5SDimitry Andric   return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
16090b57cec5SDimitry Andric }
16100b57cec5SDimitry Andric 
1611480093f4SDimitry Andric SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op,
1612480093f4SDimitry Andric                                               SelectionDAG &DAG) const {
1613480093f4SDimitry Andric   SDLoc DL(Op);
1614480093f4SDimitry Andric   // The legalizer does not know how to expand the comparison modes of i64x2
1615480093f4SDimitry Andric   // vectors because no comparison modes are supported. We could solve this by
1616480093f4SDimitry Andric   // expanding all i64x2 SETCC nodes, but that seems to expand f64x2 SETCC nodes
1617480093f4SDimitry Andric   // (which return i64x2 results) as well. So instead we manually unroll i64x2
1618480093f4SDimitry Andric   // comparisons here.
1619480093f4SDimitry Andric   assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64);
1620480093f4SDimitry Andric   SmallVector<SDValue, 2> LHS, RHS;
1621480093f4SDimitry Andric   DAG.ExtractVectorElements(Op->getOperand(0), LHS);
1622480093f4SDimitry Andric   DAG.ExtractVectorElements(Op->getOperand(1), RHS);
1623480093f4SDimitry Andric   const SDValue &CC = Op->getOperand(2);
1624480093f4SDimitry Andric   auto MakeLane = [&](unsigned I) {
1625480093f4SDimitry Andric     return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I],
1626480093f4SDimitry Andric                        DAG.getConstant(uint64_t(-1), DL, MVT::i64),
1627480093f4SDimitry Andric                        DAG.getConstant(uint64_t(0), DL, MVT::i64), CC);
1628480093f4SDimitry Andric   };
1629480093f4SDimitry Andric   return DAG.getBuildVector(Op->getValueType(0), DL,
1630480093f4SDimitry Andric                             {MakeLane(0), MakeLane(1)});
1631480093f4SDimitry Andric }
1632480093f4SDimitry Andric 
16330b57cec5SDimitry Andric SDValue
16340b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
16350b57cec5SDimitry Andric                                                     SelectionDAG &DAG) const {
16360b57cec5SDimitry Andric   // Allow constant lane indices, expand variable lane indices
16370b57cec5SDimitry Andric   SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
16380b57cec5SDimitry Andric   if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef())
16390b57cec5SDimitry Andric     return Op;
16400b57cec5SDimitry Andric   else
16410b57cec5SDimitry Andric     // Perform default expansion
16420b57cec5SDimitry Andric     return SDValue();
16430b57cec5SDimitry Andric }
16440b57cec5SDimitry Andric 
16450b57cec5SDimitry Andric static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) {
16460b57cec5SDimitry Andric   EVT LaneT = Op.getSimpleValueType().getVectorElementType();
16470b57cec5SDimitry Andric   // 32-bit and 64-bit unrolled shifts will have proper semantics
16480b57cec5SDimitry Andric   if (LaneT.bitsGE(MVT::i32))
16490b57cec5SDimitry Andric     return DAG.UnrollVectorOp(Op.getNode());
16500b57cec5SDimitry Andric   // Otherwise mask the shift value to get proper semantics from 32-bit shift
16510b57cec5SDimitry Andric   SDLoc DL(Op);
1652*5ffd83dbSDimitry Andric   size_t NumLanes = Op.getSimpleValueType().getVectorNumElements();
1653*5ffd83dbSDimitry Andric   SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32);
1654*5ffd83dbSDimitry Andric   unsigned ShiftOpcode = Op.getOpcode();
1655*5ffd83dbSDimitry Andric   SmallVector<SDValue, 16> ShiftedElements;
1656*5ffd83dbSDimitry Andric   DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32);
1657*5ffd83dbSDimitry Andric   SmallVector<SDValue, 16> ShiftElements;
1658*5ffd83dbSDimitry Andric   DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32);
1659*5ffd83dbSDimitry Andric   SmallVector<SDValue, 16> UnrolledOps;
1660*5ffd83dbSDimitry Andric   for (size_t i = 0; i < NumLanes; ++i) {
1661*5ffd83dbSDimitry Andric     SDValue MaskedShiftValue =
1662*5ffd83dbSDimitry Andric         DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask);
1663*5ffd83dbSDimitry Andric     SDValue ShiftedValue = ShiftedElements[i];
1664*5ffd83dbSDimitry Andric     if (ShiftOpcode == ISD::SRA)
1665*5ffd83dbSDimitry Andric       ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32,
1666*5ffd83dbSDimitry Andric                                  ShiftedValue, DAG.getValueType(LaneT));
1667*5ffd83dbSDimitry Andric     UnrolledOps.push_back(
1668*5ffd83dbSDimitry Andric         DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue));
1669*5ffd83dbSDimitry Andric   }
1670*5ffd83dbSDimitry Andric   return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps);
16710b57cec5SDimitry Andric }
16720b57cec5SDimitry Andric 
16730b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
16740b57cec5SDimitry Andric                                               SelectionDAG &DAG) const {
16750b57cec5SDimitry Andric   SDLoc DL(Op);
16760b57cec5SDimitry Andric 
16770b57cec5SDimitry Andric   // Only manually lower vector shifts
16780b57cec5SDimitry Andric   assert(Op.getSimpleValueType().isVector());
16790b57cec5SDimitry Andric 
1680*5ffd83dbSDimitry Andric   auto ShiftVal = DAG.getSplatValue(Op.getOperand(1));
1681*5ffd83dbSDimitry Andric   if (!ShiftVal)
16820b57cec5SDimitry Andric     return unrollVectorShift(Op, DAG);
16830b57cec5SDimitry Andric 
1684*5ffd83dbSDimitry Andric   // Use anyext because none of the high bits can affect the shift
1685*5ffd83dbSDimitry Andric   ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32);
16860b57cec5SDimitry Andric 
16870b57cec5SDimitry Andric   unsigned Opcode;
16880b57cec5SDimitry Andric   switch (Op.getOpcode()) {
16890b57cec5SDimitry Andric   case ISD::SHL:
16900b57cec5SDimitry Andric     Opcode = WebAssemblyISD::VEC_SHL;
16910b57cec5SDimitry Andric     break;
16920b57cec5SDimitry Andric   case ISD::SRA:
16930b57cec5SDimitry Andric     Opcode = WebAssemblyISD::VEC_SHR_S;
16940b57cec5SDimitry Andric     break;
16950b57cec5SDimitry Andric   case ISD::SRL:
16960b57cec5SDimitry Andric     Opcode = WebAssemblyISD::VEC_SHR_U;
16970b57cec5SDimitry Andric     break;
16980b57cec5SDimitry Andric   default:
16990b57cec5SDimitry Andric     llvm_unreachable("unexpected opcode");
17000b57cec5SDimitry Andric   }
1701*5ffd83dbSDimitry Andric 
1702*5ffd83dbSDimitry Andric   return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal);
17030b57cec5SDimitry Andric }
17040b57cec5SDimitry Andric 
17050b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1706*5ffd83dbSDimitry Andric //   Custom DAG combine hooks
17070b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1708*5ffd83dbSDimitry Andric static SDValue
1709*5ffd83dbSDimitry Andric performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
1710*5ffd83dbSDimitry Andric   auto &DAG = DCI.DAG;
1711*5ffd83dbSDimitry Andric   auto Shuffle = cast<ShuffleVectorSDNode>(N);
1712*5ffd83dbSDimitry Andric 
1713*5ffd83dbSDimitry Andric   // Hoist vector bitcasts that don't change the number of lanes out of unary
1714*5ffd83dbSDimitry Andric   // shuffles, where they are less likely to get in the way of other combines.
1715*5ffd83dbSDimitry Andric   // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) ->
1716*5ffd83dbSDimitry Andric   //  (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask))))
1717*5ffd83dbSDimitry Andric   SDValue Bitcast = N->getOperand(0);
1718*5ffd83dbSDimitry Andric   if (Bitcast.getOpcode() != ISD::BITCAST)
1719*5ffd83dbSDimitry Andric     return SDValue();
1720*5ffd83dbSDimitry Andric   if (!N->getOperand(1).isUndef())
1721*5ffd83dbSDimitry Andric     return SDValue();
1722*5ffd83dbSDimitry Andric   SDValue CastOp = Bitcast.getOperand(0);
1723*5ffd83dbSDimitry Andric   MVT SrcType = CastOp.getSimpleValueType();
1724*5ffd83dbSDimitry Andric   MVT DstType = Bitcast.getSimpleValueType();
1725*5ffd83dbSDimitry Andric   if (!SrcType.is128BitVector() ||
1726*5ffd83dbSDimitry Andric       SrcType.getVectorNumElements() != DstType.getVectorNumElements())
1727*5ffd83dbSDimitry Andric     return SDValue();
1728*5ffd83dbSDimitry Andric   SDValue NewShuffle = DAG.getVectorShuffle(
1729*5ffd83dbSDimitry Andric       SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask());
1730*5ffd83dbSDimitry Andric   return DAG.getBitcast(DstType, NewShuffle);
1731*5ffd83dbSDimitry Andric }
1732*5ffd83dbSDimitry Andric 
1733*5ffd83dbSDimitry Andric SDValue
1734*5ffd83dbSDimitry Andric WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N,
1735*5ffd83dbSDimitry Andric                                              DAGCombinerInfo &DCI) const {
1736*5ffd83dbSDimitry Andric   switch (N->getOpcode()) {
1737*5ffd83dbSDimitry Andric   default:
1738*5ffd83dbSDimitry Andric     return SDValue();
1739*5ffd83dbSDimitry Andric   case ISD::VECTOR_SHUFFLE:
1740*5ffd83dbSDimitry Andric     return performVECTOR_SHUFFLECombine(N, DCI);
1741*5ffd83dbSDimitry Andric   }
1742*5ffd83dbSDimitry Andric }
1743