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" 19*e8d8bef9SDimitry Andric #include "WebAssemblyUtilities.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/Analysis.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h" 280b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 290b57cec5SDimitry Andric #include "llvm/IR/DiagnosticPrinter.h" 300b57cec5SDimitry Andric #include "llvm/IR/Function.h" 310b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 32480093f4SDimitry Andric #include "llvm/IR/IntrinsicsWebAssembly.h" 330b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 340b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 35*e8d8bef9SDimitry Andric #include "llvm/Support/MathExtras.h" 360b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 370b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 380b57cec5SDimitry Andric using namespace llvm; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-lower" 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric WebAssemblyTargetLowering::WebAssemblyTargetLowering( 430b57cec5SDimitry Andric const TargetMachine &TM, const WebAssemblySubtarget &STI) 440b57cec5SDimitry Andric : TargetLowering(TM), Subtarget(&STI) { 450b57cec5SDimitry Andric auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric // Booleans always contain 0 or 1. 480b57cec5SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 490b57cec5SDimitry Andric // Except in SIMD vectors 500b57cec5SDimitry Andric setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); 510b57cec5SDimitry Andric // We don't know the microarchitecture here, so just reduce register pressure. 520b57cec5SDimitry Andric setSchedulingPreference(Sched::RegPressure); 530b57cec5SDimitry Andric // Tell ISel that we have a stack pointer. 540b57cec5SDimitry Andric setStackPointerRegisterToSaveRestore( 550b57cec5SDimitry Andric Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); 560b57cec5SDimitry Andric // Set up the register classes. 570b57cec5SDimitry Andric addRegisterClass(MVT::i32, &WebAssembly::I32RegClass); 580b57cec5SDimitry Andric addRegisterClass(MVT::i64, &WebAssembly::I64RegClass); 590b57cec5SDimitry Andric addRegisterClass(MVT::f32, &WebAssembly::F32RegClass); 600b57cec5SDimitry Andric addRegisterClass(MVT::f64, &WebAssembly::F64RegClass); 610b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) { 620b57cec5SDimitry Andric addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass); 630b57cec5SDimitry Andric addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass); 640b57cec5SDimitry Andric addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass); 650b57cec5SDimitry Andric addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass); 660b57cec5SDimitry Andric addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); 670b57cec5SDimitry Andric addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric // Compute derived properties from the register classes. 700b57cec5SDimitry Andric computeRegisterProperties(Subtarget->getRegisterInfo()); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); 73*e8d8bef9SDimitry Andric setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom); 740b57cec5SDimitry Andric setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); 750b57cec5SDimitry Andric setOperationAction(ISD::JumpTable, MVTPtr, Custom); 760b57cec5SDimitry Andric setOperationAction(ISD::BlockAddress, MVTPtr, Custom); 770b57cec5SDimitry Andric setOperationAction(ISD::BRIND, MVT::Other, Custom); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric // Take the default expansion for va_arg, va_copy, and va_end. There is no 800b57cec5SDimitry Andric // default action for va_start, so we do that custom. 810b57cec5SDimitry Andric setOperationAction(ISD::VASTART, MVT::Other, Custom); 820b57cec5SDimitry Andric setOperationAction(ISD::VAARG, MVT::Other, Expand); 830b57cec5SDimitry Andric setOperationAction(ISD::VACOPY, MVT::Other, Expand); 840b57cec5SDimitry Andric setOperationAction(ISD::VAEND, MVT::Other, Expand); 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) { 870b57cec5SDimitry Andric // Don't expand the floating-point types to constant pools. 880b57cec5SDimitry Andric setOperationAction(ISD::ConstantFP, T, Legal); 890b57cec5SDimitry Andric // Expand floating-point comparisons. 900b57cec5SDimitry Andric for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, 910b57cec5SDimitry Andric ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) 920b57cec5SDimitry Andric setCondCodeAction(CC, T, Expand); 930b57cec5SDimitry Andric // Expand floating-point library function operators. 940b57cec5SDimitry Andric for (auto Op : 950b57cec5SDimitry Andric {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA}) 960b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 970b57cec5SDimitry Andric // Note supported floating-point library function operators that otherwise 980b57cec5SDimitry Andric // default to expand. 990b57cec5SDimitry Andric for (auto Op : 1000b57cec5SDimitry Andric {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT}) 1010b57cec5SDimitry Andric setOperationAction(Op, T, Legal); 1020b57cec5SDimitry Andric // Support minimum and maximum, which otherwise default to expand. 1030b57cec5SDimitry Andric setOperationAction(ISD::FMINIMUM, T, Legal); 1040b57cec5SDimitry Andric setOperationAction(ISD::FMAXIMUM, T, Legal); 1050b57cec5SDimitry Andric // WebAssembly currently has no builtin f16 support. 1060b57cec5SDimitry Andric setOperationAction(ISD::FP16_TO_FP, T, Expand); 1070b57cec5SDimitry Andric setOperationAction(ISD::FP_TO_FP16, T, Expand); 1080b57cec5SDimitry Andric setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand); 1090b57cec5SDimitry Andric setTruncStoreAction(T, MVT::f16, Expand); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric // Expand unavailable integer operations. 1130b57cec5SDimitry Andric for (auto Op : 1140b57cec5SDimitry Andric {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU, 1150b57cec5SDimitry Andric ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS, 1160b57cec5SDimitry Andric ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) { 1170b57cec5SDimitry Andric for (auto T : {MVT::i32, MVT::i64}) 1180b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 1190b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) 1205ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 1210b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // SIMD-specific configuration 1250b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) { 1265ffd83dbSDimitry Andric // Hoist bitcasts out of shuffles 1275ffd83dbSDimitry Andric setTargetDAGCombine(ISD::VECTOR_SHUFFLE); 1285ffd83dbSDimitry Andric 129*e8d8bef9SDimitry Andric // Combine extends of extract_subvectors into widening ops 130*e8d8bef9SDimitry Andric setTargetDAGCombine(ISD::SIGN_EXTEND); 131*e8d8bef9SDimitry Andric setTargetDAGCombine(ISD::ZERO_EXTEND); 132*e8d8bef9SDimitry Andric 1330b57cec5SDimitry Andric // Support saturating add for i8x16 and i16x8 1340b57cec5SDimitry Andric for (auto Op : {ISD::SADDSAT, ISD::UADDSAT}) 1350b57cec5SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16}) 1360b57cec5SDimitry Andric setOperationAction(Op, T, Legal); 1370b57cec5SDimitry Andric 1385ffd83dbSDimitry Andric // Support integer abs 1395ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) 1405ffd83dbSDimitry Andric setOperationAction(ISD::ABS, T, Legal); 1415ffd83dbSDimitry Andric 1420b57cec5SDimitry Andric // Custom lower BUILD_VECTORs to minimize number of replace_lanes 1435ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 1445ffd83dbSDimitry Andric MVT::v2f64}) 1450b57cec5SDimitry Andric setOperationAction(ISD::BUILD_VECTOR, T, Custom); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric // We have custom shuffle lowering to expose the shuffle mask 1485ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 1495ffd83dbSDimitry Andric MVT::v2f64}) 1500b57cec5SDimitry Andric setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom); 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric // Custom lowering since wasm shifts must have a scalar shift amount 1535ffd83dbSDimitry Andric for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) 1545ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 1550b57cec5SDimitry Andric setOperationAction(Op, T, Custom); 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric // Custom lower lane accesses to expand out variable indices 1585ffd83dbSDimitry Andric for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT}) 1595ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 1605ffd83dbSDimitry Andric MVT::v2f64}) 1610b57cec5SDimitry Andric setOperationAction(Op, T, Custom); 1620b57cec5SDimitry Andric 1635ffd83dbSDimitry Andric // There is no i8x16.mul instruction 1645ffd83dbSDimitry Andric setOperationAction(ISD::MUL, MVT::v16i8, Expand); 1650b57cec5SDimitry Andric 166*e8d8bef9SDimitry Andric // There is no vector conditional select instruction 1675ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 1685ffd83dbSDimitry Andric MVT::v2f64}) 169*e8d8bef9SDimitry Andric setOperationAction(ISD::SELECT_CC, T, Expand); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric // Expand integer operations supported for scalars but not SIMD 1720b57cec5SDimitry Andric for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP, ISD::SDIV, ISD::UDIV, 1735ffd83dbSDimitry Andric ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR}) 1745ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 1750b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 1760b57cec5SDimitry Andric 177480093f4SDimitry Andric // But we do have integer min and max operations 178480093f4SDimitry Andric for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) 179480093f4SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) 180480093f4SDimitry Andric setOperationAction(Op, T, Legal); 181480093f4SDimitry Andric 1820b57cec5SDimitry Andric // Expand float operations supported for scalars but not SIMD 1830b57cec5SDimitry Andric for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, 1840b57cec5SDimitry Andric ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10, 1855ffd83dbSDimitry Andric ISD::FEXP, ISD::FEXP2, ISD::FRINT}) 1865ffd83dbSDimitry Andric for (auto T : {MVT::v4f32, MVT::v2f64}) 1875ffd83dbSDimitry Andric setOperationAction(Op, T, Expand); 1880b57cec5SDimitry Andric 189480093f4SDimitry Andric // Expand operations not supported for i64x2 vectors 190480093f4SDimitry Andric for (unsigned CC = 0; CC < ISD::SETCC_INVALID; ++CC) 191480093f4SDimitry Andric setCondCodeAction(static_cast<ISD::CondCode>(CC), MVT::v2i64, Custom); 192480093f4SDimitry Andric 1935ffd83dbSDimitry Andric // 64x2 conversions are not in the spec 1945ffd83dbSDimitry Andric for (auto Op : 1955ffd83dbSDimitry Andric {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT}) 1965ffd83dbSDimitry Andric for (auto T : {MVT::v2i64, MVT::v2f64}) 1975ffd83dbSDimitry Andric setOperationAction(Op, T, Expand); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric // As a special case, these operators use the type to mean the type to 2010b57cec5SDimitry Andric // sign-extend from. 2020b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 2030b57cec5SDimitry Andric if (!Subtarget->hasSignExt()) { 2040b57cec5SDimitry Andric // Sign extends are legal only when extending a vector extract 2050b57cec5SDimitry Andric auto Action = Subtarget->hasSIMD128() ? Custom : Expand; 2060b57cec5SDimitry Andric for (auto T : {MVT::i8, MVT::i16, MVT::i32}) 2070b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action); 2080b57cec5SDimitry Andric } 2098bcb0991SDimitry Andric for (auto T : MVT::integer_fixedlen_vector_valuetypes()) 2100b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric // Dynamic stack allocation: use the default expansion. 2130b57cec5SDimitry Andric setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 2140b57cec5SDimitry Andric setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 2150b57cec5SDimitry Andric setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric setOperationAction(ISD::FrameIndex, MVT::i32, Custom); 2185ffd83dbSDimitry Andric setOperationAction(ISD::FrameIndex, MVT::i64, Custom); 2190b57cec5SDimitry Andric setOperationAction(ISD::CopyToReg, MVT::Other, Custom); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric // Expand these forms; we pattern-match the forms that we can handle in isel. 2220b57cec5SDimitry Andric for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) 2230b57cec5SDimitry Andric for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) 2240b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric // We have custom switch handling. 2270b57cec5SDimitry Andric setOperationAction(ISD::BR_JT, MVT::Other, Custom); 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric // WebAssembly doesn't have: 2300b57cec5SDimitry Andric // - Floating-point extending loads. 2310b57cec5SDimitry Andric // - Floating-point truncating stores. 2320b57cec5SDimitry Andric // - i1 extending loads. 2338bcb0991SDimitry Andric // - truncating SIMD stores and most extending loads 2340b57cec5SDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 2350b57cec5SDimitry Andric setTruncStoreAction(MVT::f64, MVT::f32, Expand); 2360b57cec5SDimitry Andric for (auto T : MVT::integer_valuetypes()) 2370b57cec5SDimitry Andric for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 2380b57cec5SDimitry Andric setLoadExtAction(Ext, T, MVT::i1, Promote); 2390b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) { 2400b57cec5SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, 2410b57cec5SDimitry Andric MVT::v2f64}) { 2428bcb0991SDimitry Andric for (auto MemT : MVT::fixedlen_vector_valuetypes()) { 2430b57cec5SDimitry Andric if (MVT(T) != MemT) { 2440b57cec5SDimitry Andric setTruncStoreAction(T, MemT, Expand); 2450b57cec5SDimitry Andric for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 2460b57cec5SDimitry Andric setLoadExtAction(Ext, T, MemT, Expand); 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric } 2508bcb0991SDimitry Andric // But some vector extending loads are legal 2518bcb0991SDimitry Andric for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) { 2528bcb0991SDimitry Andric setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal); 2538bcb0991SDimitry Andric setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal); 2548bcb0991SDimitry Andric setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal); 2558bcb0991SDimitry Andric } 256*e8d8bef9SDimitry Andric // And some truncating stores are legal as well 257*e8d8bef9SDimitry Andric setTruncStoreAction(MVT::v8i16, MVT::v8i8, Legal); 258*e8d8bef9SDimitry Andric setTruncStoreAction(MVT::v4i32, MVT::v4i16, Legal); 2598bcb0991SDimitry Andric } 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric // Don't do anything clever with build_pairs 2620b57cec5SDimitry Andric setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand); 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric // Trap lowers to wasm unreachable 2650b57cec5SDimitry Andric setOperationAction(ISD::TRAP, MVT::Other, Legal); 2665ffd83dbSDimitry Andric setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // Exception handling intrinsics 2690b57cec5SDimitry Andric setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); 270*e8d8bef9SDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 2710b57cec5SDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric setMaxAtomicSizeInBitsSupported(64); 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is 2760b57cec5SDimitry Andric // consistent with the f64 and f128 names. 2770b57cec5SDimitry Andric setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2"); 2780b57cec5SDimitry Andric setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2"); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Define the emscripten name for return address helper. 281*e8d8bef9SDimitry Andric // TODO: when implementing other Wasm backends, make this generic or only do 2820b57cec5SDimitry Andric // this on emscripten depending on what they end up doing. 2830b57cec5SDimitry Andric setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address"); 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric // Always convert switches to br_tables unless there is only one case, which 2860b57cec5SDimitry Andric // is equivalent to a simple branch. This reduces code size for wasm, and we 2870b57cec5SDimitry Andric // defer possible jump table optimizations to the VM. 2880b57cec5SDimitry Andric setMinimumJumpTableEntries(2); 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric TargetLowering::AtomicExpansionKind 2920b57cec5SDimitry Andric WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { 2930b57cec5SDimitry Andric // We have wasm instructions for these 2940b57cec5SDimitry Andric switch (AI->getOperation()) { 2950b57cec5SDimitry Andric case AtomicRMWInst::Add: 2960b57cec5SDimitry Andric case AtomicRMWInst::Sub: 2970b57cec5SDimitry Andric case AtomicRMWInst::And: 2980b57cec5SDimitry Andric case AtomicRMWInst::Or: 2990b57cec5SDimitry Andric case AtomicRMWInst::Xor: 3000b57cec5SDimitry Andric case AtomicRMWInst::Xchg: 3010b57cec5SDimitry Andric return AtomicExpansionKind::None; 3020b57cec5SDimitry Andric default: 3030b57cec5SDimitry Andric break; 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric return AtomicExpansionKind::CmpXChg; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric FastISel *WebAssemblyTargetLowering::createFastISel( 3090b57cec5SDimitry Andric FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const { 3100b57cec5SDimitry Andric return WebAssembly::createFastISel(FuncInfo, LibInfo); 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, 3140b57cec5SDimitry Andric EVT VT) const { 3150b57cec5SDimitry Andric unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1); 3160b57cec5SDimitry Andric if (BitWidth > 1 && BitWidth < 8) 3170b57cec5SDimitry Andric BitWidth = 8; 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric if (BitWidth > 64) { 3200b57cec5SDimitry Andric // The shift will be lowered to a libcall, and compiler-rt libcalls expect 3210b57cec5SDimitry Andric // the count to be an i32. 3220b57cec5SDimitry Andric BitWidth = 32; 3230b57cec5SDimitry Andric assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) && 3240b57cec5SDimitry Andric "32-bit shift counts ought to be enough for anyone"); 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric MVT Result = MVT::getIntegerVT(BitWidth); 3280b57cec5SDimitry Andric assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE && 3290b57cec5SDimitry Andric "Unable to represent scalar shift amount type"); 3300b57cec5SDimitry Andric return Result; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric // Lower an fp-to-int conversion operator from the LLVM opcode, which has an 3340b57cec5SDimitry Andric // undefined result on invalid/overflow, to the WebAssembly opcode, which 3350b57cec5SDimitry Andric // traps on invalid/overflow. 3360b57cec5SDimitry Andric static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL, 3370b57cec5SDimitry Andric MachineBasicBlock *BB, 3380b57cec5SDimitry Andric const TargetInstrInfo &TII, 3390b57cec5SDimitry Andric bool IsUnsigned, bool Int64, 3400b57cec5SDimitry Andric bool Float64, unsigned LoweredOpcode) { 3410b57cec5SDimitry Andric MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); 3420b57cec5SDimitry Andric 3438bcb0991SDimitry Andric Register OutReg = MI.getOperand(0).getReg(); 3448bcb0991SDimitry Andric Register InReg = MI.getOperand(1).getReg(); 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32; 3470b57cec5SDimitry Andric unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32; 3480b57cec5SDimitry Andric unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32; 3490b57cec5SDimitry Andric unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32; 3500b57cec5SDimitry Andric unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; 3510b57cec5SDimitry Andric unsigned Eqz = WebAssembly::EQZ_I32; 3520b57cec5SDimitry Andric unsigned And = WebAssembly::AND_I32; 3530b57cec5SDimitry Andric int64_t Limit = Int64 ? INT64_MIN : INT32_MIN; 3540b57cec5SDimitry Andric int64_t Substitute = IsUnsigned ? 0 : Limit; 3550b57cec5SDimitry Andric double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit; 3560b57cec5SDimitry Andric auto &Context = BB->getParent()->getFunction().getContext(); 3570b57cec5SDimitry Andric Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context); 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric const BasicBlock *LLVMBB = BB->getBasicBlock(); 3600b57cec5SDimitry Andric MachineFunction *F = BB->getParent(); 3610b57cec5SDimitry Andric MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB); 3620b57cec5SDimitry Andric MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB); 3630b57cec5SDimitry Andric MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB); 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric MachineFunction::iterator It = ++BB->getIterator(); 3660b57cec5SDimitry Andric F->insert(It, FalseMBB); 3670b57cec5SDimitry Andric F->insert(It, TrueMBB); 3680b57cec5SDimitry Andric F->insert(It, DoneMBB); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric // Transfer the remainder of BB and its successor edges to DoneMBB. 3710b57cec5SDimitry Andric DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end()); 3720b57cec5SDimitry Andric DoneMBB->transferSuccessorsAndUpdatePHIs(BB); 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric BB->addSuccessor(TrueMBB); 3750b57cec5SDimitry Andric BB->addSuccessor(FalseMBB); 3760b57cec5SDimitry Andric TrueMBB->addSuccessor(DoneMBB); 3770b57cec5SDimitry Andric FalseMBB->addSuccessor(DoneMBB); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg; 3800b57cec5SDimitry Andric Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 3810b57cec5SDimitry Andric Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 3820b57cec5SDimitry Andric CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 3830b57cec5SDimitry Andric EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 3840b57cec5SDimitry Andric FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 3850b57cec5SDimitry Andric TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric MI.eraseFromParent(); 3880b57cec5SDimitry Andric // For signed numbers, we can do a single comparison to determine whether 3890b57cec5SDimitry Andric // fabs(x) is within range. 3900b57cec5SDimitry Andric if (IsUnsigned) { 3910b57cec5SDimitry Andric Tmp0 = InReg; 3920b57cec5SDimitry Andric } else { 3930b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg); 3940b57cec5SDimitry Andric } 3950b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(FConst), Tmp1) 3960b57cec5SDimitry Andric .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal))); 3970b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1); 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric // For unsigned numbers, we have to do a separate comparison with zero. 4000b57cec5SDimitry Andric if (IsUnsigned) { 4010b57cec5SDimitry Andric Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 4028bcb0991SDimitry Andric Register SecondCmpReg = 4030b57cec5SDimitry Andric MRI.createVirtualRegister(&WebAssembly::I32RegClass); 4048bcb0991SDimitry Andric Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 4050b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(FConst), Tmp1) 4060b57cec5SDimitry Andric .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0))); 4070b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1); 4080b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg); 4090b57cec5SDimitry Andric CmpReg = AndReg; 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg); 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric // Create the CFG diamond to select between doing the conversion or using 4150b57cec5SDimitry Andric // the substitute value. 4160b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg); 4170b57cec5SDimitry Andric BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg); 4180b57cec5SDimitry Andric BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB); 4190b57cec5SDimitry Andric BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute); 4200b57cec5SDimitry Andric BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg) 4210b57cec5SDimitry Andric .addReg(FalseReg) 4220b57cec5SDimitry Andric .addMBB(FalseMBB) 4230b57cec5SDimitry Andric .addReg(TrueReg) 4240b57cec5SDimitry Andric .addMBB(TrueMBB); 4250b57cec5SDimitry Andric 4260b57cec5SDimitry Andric return DoneMBB; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric 4295ffd83dbSDimitry Andric static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults, 4305ffd83dbSDimitry Andric DebugLoc DL, MachineBasicBlock *BB, 4315ffd83dbSDimitry Andric const TargetInstrInfo &TII) { 4325ffd83dbSDimitry Andric MachineInstr &CallParams = *CallResults.getPrevNode(); 4335ffd83dbSDimitry Andric assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS); 4345ffd83dbSDimitry Andric assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS || 4355ffd83dbSDimitry Andric CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS); 4365ffd83dbSDimitry Andric 4375ffd83dbSDimitry Andric bool IsIndirect = CallParams.getOperand(0).isReg(); 4385ffd83dbSDimitry Andric bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS; 4395ffd83dbSDimitry Andric 4405ffd83dbSDimitry Andric unsigned CallOp; 4415ffd83dbSDimitry Andric if (IsIndirect && IsRetCall) { 4425ffd83dbSDimitry Andric CallOp = WebAssembly::RET_CALL_INDIRECT; 4435ffd83dbSDimitry Andric } else if (IsIndirect) { 4445ffd83dbSDimitry Andric CallOp = WebAssembly::CALL_INDIRECT; 4455ffd83dbSDimitry Andric } else if (IsRetCall) { 4465ffd83dbSDimitry Andric CallOp = WebAssembly::RET_CALL; 4475ffd83dbSDimitry Andric } else { 4485ffd83dbSDimitry Andric CallOp = WebAssembly::CALL; 4495ffd83dbSDimitry Andric } 4505ffd83dbSDimitry Andric 4515ffd83dbSDimitry Andric MachineFunction &MF = *BB->getParent(); 4525ffd83dbSDimitry Andric const MCInstrDesc &MCID = TII.get(CallOp); 4535ffd83dbSDimitry Andric MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL)); 4545ffd83dbSDimitry Andric 455*e8d8bef9SDimitry Andric // See if we must truncate the function pointer. 456*e8d8bef9SDimitry Andric // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers 457*e8d8bef9SDimitry Andric // as 64-bit for uniformity with other pointer types. 458*e8d8bef9SDimitry Andric if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) { 459*e8d8bef9SDimitry Andric Register Reg32 = 460*e8d8bef9SDimitry Andric MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); 461*e8d8bef9SDimitry Andric auto &FnPtr = CallParams.getOperand(0); 462*e8d8bef9SDimitry Andric BuildMI(*BB, CallResults.getIterator(), DL, 463*e8d8bef9SDimitry Andric TII.get(WebAssembly::I32_WRAP_I64), Reg32) 464*e8d8bef9SDimitry Andric .addReg(FnPtr.getReg()); 465*e8d8bef9SDimitry Andric FnPtr.setReg(Reg32); 466*e8d8bef9SDimitry Andric } 467*e8d8bef9SDimitry Andric 4685ffd83dbSDimitry Andric // Move the function pointer to the end of the arguments for indirect calls 4695ffd83dbSDimitry Andric if (IsIndirect) { 4705ffd83dbSDimitry Andric auto FnPtr = CallParams.getOperand(0); 4715ffd83dbSDimitry Andric CallParams.RemoveOperand(0); 4725ffd83dbSDimitry Andric CallParams.addOperand(FnPtr); 4735ffd83dbSDimitry Andric } 4745ffd83dbSDimitry Andric 4755ffd83dbSDimitry Andric for (auto Def : CallResults.defs()) 4765ffd83dbSDimitry Andric MIB.add(Def); 4775ffd83dbSDimitry Andric 4785ffd83dbSDimitry Andric // Add placeholders for the type index and immediate flags 4795ffd83dbSDimitry Andric if (IsIndirect) { 4805ffd83dbSDimitry Andric MIB.addImm(0); 4815ffd83dbSDimitry Andric MIB.addImm(0); 482*e8d8bef9SDimitry Andric 483*e8d8bef9SDimitry Andric // Ensure that the object file has a __indirect_function_table import, as we 484*e8d8bef9SDimitry Andric // call_indirect against it. 485*e8d8bef9SDimitry Andric MCSymbolWasm *Sym = WebAssembly::getOrCreateFunctionTableSymbol( 486*e8d8bef9SDimitry Andric MF.getContext(), "__indirect_function_table"); 487*e8d8bef9SDimitry Andric // Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark 488*e8d8bef9SDimitry Andric // it as NO_STRIP so as to ensure that the indirect function table makes it 489*e8d8bef9SDimitry Andric // to linked output. 490*e8d8bef9SDimitry Andric Sym->setNoStrip(); 4915ffd83dbSDimitry Andric } 4925ffd83dbSDimitry Andric 4935ffd83dbSDimitry Andric for (auto Use : CallParams.uses()) 4945ffd83dbSDimitry Andric MIB.add(Use); 4955ffd83dbSDimitry Andric 4965ffd83dbSDimitry Andric BB->insert(CallResults.getIterator(), MIB); 4975ffd83dbSDimitry Andric CallParams.eraseFromParent(); 4985ffd83dbSDimitry Andric CallResults.eraseFromParent(); 4995ffd83dbSDimitry Andric 5005ffd83dbSDimitry Andric return BB; 5015ffd83dbSDimitry Andric } 5025ffd83dbSDimitry Andric 5030b57cec5SDimitry Andric MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter( 5040b57cec5SDimitry Andric MachineInstr &MI, MachineBasicBlock *BB) const { 5050b57cec5SDimitry Andric const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 5060b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric switch (MI.getOpcode()) { 5090b57cec5SDimitry Andric default: 5100b57cec5SDimitry Andric llvm_unreachable("Unexpected instr type to insert"); 5110b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I32_F32: 5120b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, false, false, 5130b57cec5SDimitry Andric WebAssembly::I32_TRUNC_S_F32); 5140b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I32_F32: 5150b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, false, false, 5160b57cec5SDimitry Andric WebAssembly::I32_TRUNC_U_F32); 5170b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I64_F32: 5180b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, true, false, 5190b57cec5SDimitry Andric WebAssembly::I64_TRUNC_S_F32); 5200b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I64_F32: 5210b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, true, false, 5220b57cec5SDimitry Andric WebAssembly::I64_TRUNC_U_F32); 5230b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I32_F64: 5240b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, false, true, 5250b57cec5SDimitry Andric WebAssembly::I32_TRUNC_S_F64); 5260b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I32_F64: 5270b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, false, true, 5280b57cec5SDimitry Andric WebAssembly::I32_TRUNC_U_F64); 5290b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I64_F64: 5300b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, true, true, 5310b57cec5SDimitry Andric WebAssembly::I64_TRUNC_S_F64); 5320b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I64_F64: 5330b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, true, true, 5340b57cec5SDimitry Andric WebAssembly::I64_TRUNC_U_F64); 5355ffd83dbSDimitry Andric case WebAssembly::CALL_RESULTS: 5365ffd83dbSDimitry Andric case WebAssembly::RET_CALL_RESULTS: 5375ffd83dbSDimitry Andric return LowerCallResults(MI, DL, BB, TII); 5380b57cec5SDimitry Andric } 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric const char * 5420b57cec5SDimitry Andric WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const { 5430b57cec5SDimitry Andric switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { 5440b57cec5SDimitry Andric case WebAssemblyISD::FIRST_NUMBER: 545480093f4SDimitry Andric case WebAssemblyISD::FIRST_MEM_OPCODE: 5460b57cec5SDimitry Andric break; 5470b57cec5SDimitry Andric #define HANDLE_NODETYPE(NODE) \ 5480b57cec5SDimitry Andric case WebAssemblyISD::NODE: \ 5490b57cec5SDimitry Andric return "WebAssemblyISD::" #NODE; 550480093f4SDimitry Andric #define HANDLE_MEM_NODETYPE(NODE) HANDLE_NODETYPE(NODE) 5510b57cec5SDimitry Andric #include "WebAssemblyISD.def" 552480093f4SDimitry Andric #undef HANDLE_MEM_NODETYPE 5530b57cec5SDimitry Andric #undef HANDLE_NODETYPE 5540b57cec5SDimitry Andric } 5550b57cec5SDimitry Andric return nullptr; 5560b57cec5SDimitry Andric } 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric std::pair<unsigned, const TargetRegisterClass *> 5590b57cec5SDimitry Andric WebAssemblyTargetLowering::getRegForInlineAsmConstraint( 5600b57cec5SDimitry Andric const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 5610b57cec5SDimitry Andric // First, see if this is a constraint that directly corresponds to a 5620b57cec5SDimitry Andric // WebAssembly register class. 5630b57cec5SDimitry Andric if (Constraint.size() == 1) { 5640b57cec5SDimitry Andric switch (Constraint[0]) { 5650b57cec5SDimitry Andric case 'r': 5660b57cec5SDimitry Andric assert(VT != MVT::iPTR && "Pointer MVT not expected here"); 5670b57cec5SDimitry Andric if (Subtarget->hasSIMD128() && VT.isVector()) { 5680b57cec5SDimitry Andric if (VT.getSizeInBits() == 128) 5690b57cec5SDimitry Andric return std::make_pair(0U, &WebAssembly::V128RegClass); 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric if (VT.isInteger() && !VT.isVector()) { 5720b57cec5SDimitry Andric if (VT.getSizeInBits() <= 32) 5730b57cec5SDimitry Andric return std::make_pair(0U, &WebAssembly::I32RegClass); 5740b57cec5SDimitry Andric if (VT.getSizeInBits() <= 64) 5750b57cec5SDimitry Andric return std::make_pair(0U, &WebAssembly::I64RegClass); 5760b57cec5SDimitry Andric } 577*e8d8bef9SDimitry Andric if (VT.isFloatingPoint() && !VT.isVector()) { 578*e8d8bef9SDimitry Andric switch (VT.getSizeInBits()) { 579*e8d8bef9SDimitry Andric case 32: 580*e8d8bef9SDimitry Andric return std::make_pair(0U, &WebAssembly::F32RegClass); 581*e8d8bef9SDimitry Andric case 64: 582*e8d8bef9SDimitry Andric return std::make_pair(0U, &WebAssembly::F64RegClass); 583*e8d8bef9SDimitry Andric default: 584*e8d8bef9SDimitry Andric break; 585*e8d8bef9SDimitry Andric } 586*e8d8bef9SDimitry Andric } 5870b57cec5SDimitry Andric break; 5880b57cec5SDimitry Andric default: 5890b57cec5SDimitry Andric break; 5900b57cec5SDimitry Andric } 5910b57cec5SDimitry Andric } 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const { 5970b57cec5SDimitry Andric // Assume ctz is a relatively cheap operation. 5980b57cec5SDimitry Andric return true; 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const { 6020b57cec5SDimitry Andric // Assume clz is a relatively cheap operation. 6030b57cec5SDimitry Andric return true; 6040b57cec5SDimitry Andric } 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, 6070b57cec5SDimitry Andric const AddrMode &AM, 6080b57cec5SDimitry Andric Type *Ty, unsigned AS, 6090b57cec5SDimitry Andric Instruction *I) const { 6100b57cec5SDimitry Andric // WebAssembly offsets are added as unsigned without wrapping. The 6110b57cec5SDimitry Andric // isLegalAddressingMode gives us no way to determine if wrapping could be 6120b57cec5SDimitry Andric // happening, so we approximate this by accepting only non-negative offsets. 6130b57cec5SDimitry Andric if (AM.BaseOffs < 0) 6140b57cec5SDimitry Andric return false; 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric // WebAssembly has no scale register operands. 6170b57cec5SDimitry Andric if (AM.Scale != 0) 6180b57cec5SDimitry Andric return false; 6190b57cec5SDimitry Andric 6200b57cec5SDimitry Andric // Everything else is legal. 6210b57cec5SDimitry Andric return true; 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( 6250b57cec5SDimitry Andric EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, 6260b57cec5SDimitry Andric MachineMemOperand::Flags /*Flags*/, bool *Fast) const { 6270b57cec5SDimitry Andric // WebAssembly supports unaligned accesses, though it should be declared 6280b57cec5SDimitry Andric // with the p2align attribute on loads and stores which do so, and there 6290b57cec5SDimitry Andric // may be a performance impact. We tell LLVM they're "fast" because 6300b57cec5SDimitry Andric // for the kinds of things that LLVM uses this for (merging adjacent stores 6310b57cec5SDimitry Andric // of constants, etc.), WebAssembly implementations will either want the 6320b57cec5SDimitry Andric // unaligned access or they'll split anyway. 6330b57cec5SDimitry Andric if (Fast) 6340b57cec5SDimitry Andric *Fast = true; 6350b57cec5SDimitry Andric return true; 6360b57cec5SDimitry Andric } 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, 6390b57cec5SDimitry Andric AttributeList Attr) const { 6400b57cec5SDimitry Andric // The current thinking is that wasm engines will perform this optimization, 6410b57cec5SDimitry Andric // so we can save on code size. 6420b57cec5SDimitry Andric return true; 6430b57cec5SDimitry Andric } 6440b57cec5SDimitry Andric 6458bcb0991SDimitry Andric bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { 64616d6b3b3SDimitry Andric EVT ExtT = ExtVal.getValueType(); 64716d6b3b3SDimitry Andric EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0); 6488bcb0991SDimitry Andric return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) || 6498bcb0991SDimitry Andric (ExtT == MVT::v4i32 && MemT == MVT::v4i16) || 6508bcb0991SDimitry Andric (ExtT == MVT::v2i64 && MemT == MVT::v2i32); 6518bcb0991SDimitry Andric } 6528bcb0991SDimitry Andric 6530b57cec5SDimitry Andric EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL, 6540b57cec5SDimitry Andric LLVMContext &C, 6550b57cec5SDimitry Andric EVT VT) const { 6560b57cec5SDimitry Andric if (VT.isVector()) 6570b57cec5SDimitry Andric return VT.changeVectorElementTypeToInteger(); 6580b57cec5SDimitry Andric 6595ffd83dbSDimitry Andric // So far, all branch instructions in Wasm take an I32 condition. 6605ffd83dbSDimitry Andric // The default TargetLowering::getSetCCResultType returns the pointer size, 6615ffd83dbSDimitry Andric // which would be useful to reduce instruction counts when testing 6625ffd83dbSDimitry Andric // against 64-bit pointers/values if at some point Wasm supports that. 6635ffd83dbSDimitry Andric return EVT::getIntegerVT(C, 32); 6640b57cec5SDimitry Andric } 6650b57cec5SDimitry Andric 6660b57cec5SDimitry Andric bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, 6670b57cec5SDimitry Andric const CallInst &I, 6680b57cec5SDimitry Andric MachineFunction &MF, 6690b57cec5SDimitry Andric unsigned Intrinsic) const { 6700b57cec5SDimitry Andric switch (Intrinsic) { 671*e8d8bef9SDimitry Andric case Intrinsic::wasm_memory_atomic_notify: 6720b57cec5SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 6730b57cec5SDimitry Andric Info.memVT = MVT::i32; 6740b57cec5SDimitry Andric Info.ptrVal = I.getArgOperand(0); 6750b57cec5SDimitry Andric Info.offset = 0; 6768bcb0991SDimitry Andric Info.align = Align(4); 6770b57cec5SDimitry Andric // atomic.notify instruction does not really load the memory specified with 6780b57cec5SDimitry Andric // this argument, but MachineMemOperand should either be load or store, so 6790b57cec5SDimitry Andric // we set this to a load. 6800b57cec5SDimitry Andric // FIXME Volatile isn't really correct, but currently all LLVM atomic 6810b57cec5SDimitry Andric // instructions are treated as volatiles in the backend, so we should be 6820b57cec5SDimitry Andric // consistent. The same applies for wasm_atomic_wait intrinsics too. 6830b57cec5SDimitry Andric Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 6840b57cec5SDimitry Andric return true; 685*e8d8bef9SDimitry Andric case Intrinsic::wasm_memory_atomic_wait32: 6860b57cec5SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 6870b57cec5SDimitry Andric Info.memVT = MVT::i32; 6880b57cec5SDimitry Andric Info.ptrVal = I.getArgOperand(0); 6890b57cec5SDimitry Andric Info.offset = 0; 6908bcb0991SDimitry Andric Info.align = Align(4); 6910b57cec5SDimitry Andric Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 6920b57cec5SDimitry Andric return true; 693*e8d8bef9SDimitry Andric case Intrinsic::wasm_memory_atomic_wait64: 6940b57cec5SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 6950b57cec5SDimitry Andric Info.memVT = MVT::i64; 6960b57cec5SDimitry Andric Info.ptrVal = I.getArgOperand(0); 6970b57cec5SDimitry Andric Info.offset = 0; 6988bcb0991SDimitry Andric Info.align = Align(8); 6990b57cec5SDimitry Andric Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 7000b57cec5SDimitry Andric return true; 701*e8d8bef9SDimitry Andric case Intrinsic::wasm_load32_zero: 702*e8d8bef9SDimitry Andric case Intrinsic::wasm_load64_zero: 703*e8d8bef9SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 704*e8d8bef9SDimitry Andric Info.memVT = Intrinsic == Intrinsic::wasm_load32_zero ? MVT::i32 : MVT::i64; 705*e8d8bef9SDimitry Andric Info.ptrVal = I.getArgOperand(0); 706*e8d8bef9SDimitry Andric Info.offset = 0; 707*e8d8bef9SDimitry Andric Info.align = Info.memVT == MVT::i32 ? Align(4) : Align(8); 708*e8d8bef9SDimitry Andric Info.flags = MachineMemOperand::MOLoad; 709*e8d8bef9SDimitry Andric return true; 710*e8d8bef9SDimitry Andric case Intrinsic::wasm_load8_lane: 711*e8d8bef9SDimitry Andric case Intrinsic::wasm_load16_lane: 712*e8d8bef9SDimitry Andric case Intrinsic::wasm_load32_lane: 713*e8d8bef9SDimitry Andric case Intrinsic::wasm_load64_lane: 714*e8d8bef9SDimitry Andric case Intrinsic::wasm_store8_lane: 715*e8d8bef9SDimitry Andric case Intrinsic::wasm_store16_lane: 716*e8d8bef9SDimitry Andric case Intrinsic::wasm_store32_lane: 717*e8d8bef9SDimitry Andric case Intrinsic::wasm_store64_lane: { 718*e8d8bef9SDimitry Andric MVT MemVT; 719*e8d8bef9SDimitry Andric Align MemAlign; 720*e8d8bef9SDimitry Andric switch (Intrinsic) { 721*e8d8bef9SDimitry Andric case Intrinsic::wasm_load8_lane: 722*e8d8bef9SDimitry Andric case Intrinsic::wasm_store8_lane: 723*e8d8bef9SDimitry Andric MemVT = MVT::i8; 724*e8d8bef9SDimitry Andric MemAlign = Align(1); 725*e8d8bef9SDimitry Andric break; 726*e8d8bef9SDimitry Andric case Intrinsic::wasm_load16_lane: 727*e8d8bef9SDimitry Andric case Intrinsic::wasm_store16_lane: 728*e8d8bef9SDimitry Andric MemVT = MVT::i16; 729*e8d8bef9SDimitry Andric MemAlign = Align(2); 730*e8d8bef9SDimitry Andric break; 731*e8d8bef9SDimitry Andric case Intrinsic::wasm_load32_lane: 732*e8d8bef9SDimitry Andric case Intrinsic::wasm_store32_lane: 733*e8d8bef9SDimitry Andric MemVT = MVT::i32; 734*e8d8bef9SDimitry Andric MemAlign = Align(4); 735*e8d8bef9SDimitry Andric break; 736*e8d8bef9SDimitry Andric case Intrinsic::wasm_load64_lane: 737*e8d8bef9SDimitry Andric case Intrinsic::wasm_store64_lane: 738*e8d8bef9SDimitry Andric MemVT = MVT::i64; 739*e8d8bef9SDimitry Andric MemAlign = Align(8); 740*e8d8bef9SDimitry Andric break; 741*e8d8bef9SDimitry Andric default: 742*e8d8bef9SDimitry Andric llvm_unreachable("unexpected intrinsic"); 743*e8d8bef9SDimitry Andric } 744*e8d8bef9SDimitry Andric if (Intrinsic == Intrinsic::wasm_load8_lane || 745*e8d8bef9SDimitry Andric Intrinsic == Intrinsic::wasm_load16_lane || 746*e8d8bef9SDimitry Andric Intrinsic == Intrinsic::wasm_load32_lane || 747*e8d8bef9SDimitry Andric Intrinsic == Intrinsic::wasm_load64_lane) { 748*e8d8bef9SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 749*e8d8bef9SDimitry Andric Info.flags = MachineMemOperand::MOLoad; 750*e8d8bef9SDimitry Andric } else { 751*e8d8bef9SDimitry Andric Info.opc = ISD::INTRINSIC_VOID; 752*e8d8bef9SDimitry Andric Info.flags = MachineMemOperand::MOStore; 753*e8d8bef9SDimitry Andric } 754*e8d8bef9SDimitry Andric Info.ptrVal = I.getArgOperand(0); 755*e8d8bef9SDimitry Andric Info.memVT = MemVT; 756*e8d8bef9SDimitry Andric Info.offset = 0; 757*e8d8bef9SDimitry Andric Info.align = MemAlign; 758*e8d8bef9SDimitry Andric return true; 759*e8d8bef9SDimitry Andric } 760*e8d8bef9SDimitry Andric case Intrinsic::wasm_prefetch_t: 761*e8d8bef9SDimitry Andric case Intrinsic::wasm_prefetch_nt: { 762*e8d8bef9SDimitry Andric Info.opc = ISD::INTRINSIC_VOID; 763*e8d8bef9SDimitry Andric Info.memVT = MVT::i8; 764*e8d8bef9SDimitry Andric Info.ptrVal = I.getArgOperand(0); 765*e8d8bef9SDimitry Andric Info.offset = 0; 766*e8d8bef9SDimitry Andric Info.align = Align(1); 767*e8d8bef9SDimitry Andric Info.flags = MachineMemOperand::MOLoad; 768*e8d8bef9SDimitry Andric return true; 769*e8d8bef9SDimitry Andric } 7700b57cec5SDimitry Andric default: 7710b57cec5SDimitry Andric return false; 7720b57cec5SDimitry Andric } 7730b57cec5SDimitry Andric } 7740b57cec5SDimitry Andric 7750b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7760b57cec5SDimitry Andric // WebAssembly Lowering private implementation. 7770b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7800b57cec5SDimitry Andric // Lowering Code 7810b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) { 7840b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 7850b57cec5SDimitry Andric DAG.getContext()->diagnose( 7860b57cec5SDimitry Andric DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc())); 7870b57cec5SDimitry Andric } 7880b57cec5SDimitry Andric 7890b57cec5SDimitry Andric // Test whether the given calling convention is supported. 7900b57cec5SDimitry Andric static bool callingConvSupported(CallingConv::ID CallConv) { 7910b57cec5SDimitry Andric // We currently support the language-independent target-independent 7920b57cec5SDimitry Andric // conventions. We don't yet have a way to annotate calls with properties like 7930b57cec5SDimitry Andric // "cold", and we don't have any call-clobbered registers, so these are mostly 7940b57cec5SDimitry Andric // all handled the same. 7950b57cec5SDimitry Andric return CallConv == CallingConv::C || CallConv == CallingConv::Fast || 7960b57cec5SDimitry Andric CallConv == CallingConv::Cold || 7970b57cec5SDimitry Andric CallConv == CallingConv::PreserveMost || 7980b57cec5SDimitry Andric CallConv == CallingConv::PreserveAll || 7998bcb0991SDimitry Andric CallConv == CallingConv::CXX_FAST_TLS || 8005ffd83dbSDimitry Andric CallConv == CallingConv::WASM_EmscriptenInvoke || 8015ffd83dbSDimitry Andric CallConv == CallingConv::Swift; 8020b57cec5SDimitry Andric } 8030b57cec5SDimitry Andric 8040b57cec5SDimitry Andric SDValue 8050b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, 8060b57cec5SDimitry Andric SmallVectorImpl<SDValue> &InVals) const { 8070b57cec5SDimitry Andric SelectionDAG &DAG = CLI.DAG; 8080b57cec5SDimitry Andric SDLoc DL = CLI.DL; 8090b57cec5SDimitry Andric SDValue Chain = CLI.Chain; 8100b57cec5SDimitry Andric SDValue Callee = CLI.Callee; 8110b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 8120b57cec5SDimitry Andric auto Layout = MF.getDataLayout(); 8130b57cec5SDimitry Andric 8140b57cec5SDimitry Andric CallingConv::ID CallConv = CLI.CallConv; 8150b57cec5SDimitry Andric if (!callingConvSupported(CallConv)) 8160b57cec5SDimitry Andric fail(DL, DAG, 8170b57cec5SDimitry Andric "WebAssembly doesn't support language-specific or target-specific " 8180b57cec5SDimitry Andric "calling conventions yet"); 8190b57cec5SDimitry Andric if (CLI.IsPatchPoint) 8200b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly doesn't support patch point yet"); 8210b57cec5SDimitry Andric 8228bcb0991SDimitry Andric if (CLI.IsTailCall) { 8235ffd83dbSDimitry Andric auto NoTail = [&](const char *Msg) { 8245ffd83dbSDimitry Andric if (CLI.CB && CLI.CB->isMustTailCall()) 8255ffd83dbSDimitry Andric fail(DL, DAG, Msg); 8265ffd83dbSDimitry Andric CLI.IsTailCall = false; 8275ffd83dbSDimitry Andric }; 8285ffd83dbSDimitry Andric 8295ffd83dbSDimitry Andric if (!Subtarget->hasTailCall()) 8305ffd83dbSDimitry Andric NoTail("WebAssembly 'tail-call' feature not enabled"); 8315ffd83dbSDimitry Andric 8325ffd83dbSDimitry Andric // Varargs calls cannot be tail calls because the buffer is on the stack 8335ffd83dbSDimitry Andric if (CLI.IsVarArg) 8345ffd83dbSDimitry Andric NoTail("WebAssembly does not support varargs tail calls"); 8355ffd83dbSDimitry Andric 8368bcb0991SDimitry Andric // Do not tail call unless caller and callee return types match 8378bcb0991SDimitry Andric const Function &F = MF.getFunction(); 8388bcb0991SDimitry Andric const TargetMachine &TM = getTargetMachine(); 8398bcb0991SDimitry Andric Type *RetTy = F.getReturnType(); 8408bcb0991SDimitry Andric SmallVector<MVT, 4> CallerRetTys; 8418bcb0991SDimitry Andric SmallVector<MVT, 4> CalleeRetTys; 8428bcb0991SDimitry Andric computeLegalValueVTs(F, TM, RetTy, CallerRetTys); 8438bcb0991SDimitry Andric computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys); 8448bcb0991SDimitry Andric bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() && 8458bcb0991SDimitry Andric std::equal(CallerRetTys.begin(), CallerRetTys.end(), 8468bcb0991SDimitry Andric CalleeRetTys.begin()); 8475ffd83dbSDimitry Andric if (!TypesMatch) 8485ffd83dbSDimitry Andric NoTail("WebAssembly tail call requires caller and callee return types to " 8495ffd83dbSDimitry Andric "match"); 8505ffd83dbSDimitry Andric 8515ffd83dbSDimitry Andric // If pointers to local stack values are passed, we cannot tail call 8525ffd83dbSDimitry Andric if (CLI.CB) { 8535ffd83dbSDimitry Andric for (auto &Arg : CLI.CB->args()) { 8545ffd83dbSDimitry Andric Value *Val = Arg.get(); 8555ffd83dbSDimitry Andric // Trace the value back through pointer operations 8565ffd83dbSDimitry Andric while (true) { 8575ffd83dbSDimitry Andric Value *Src = Val->stripPointerCastsAndAliases(); 8585ffd83dbSDimitry Andric if (auto *GEP = dyn_cast<GetElementPtrInst>(Src)) 8595ffd83dbSDimitry Andric Src = GEP->getPointerOperand(); 8605ffd83dbSDimitry Andric if (Val == Src) 8615ffd83dbSDimitry Andric break; 8625ffd83dbSDimitry Andric Val = Src; 8630b57cec5SDimitry Andric } 8645ffd83dbSDimitry Andric if (isa<AllocaInst>(Val)) { 8655ffd83dbSDimitry Andric NoTail( 8665ffd83dbSDimitry Andric "WebAssembly does not support tail calling with stack arguments"); 8675ffd83dbSDimitry Andric break; 8688bcb0991SDimitry Andric } 8698bcb0991SDimitry Andric } 8708bcb0991SDimitry Andric } 8718bcb0991SDimitry Andric } 8720b57cec5SDimitry Andric 8730b57cec5SDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 8740b57cec5SDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 8750b57cec5SDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 8768bcb0991SDimitry Andric 8778bcb0991SDimitry Andric // The generic code may have added an sret argument. If we're lowering an 8788bcb0991SDimitry Andric // invoke function, the ABI requires that the function pointer be the first 8798bcb0991SDimitry Andric // argument, so we may have to swap the arguments. 8808bcb0991SDimitry Andric if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 && 8818bcb0991SDimitry Andric Outs[0].Flags.isSRet()) { 8828bcb0991SDimitry Andric std::swap(Outs[0], Outs[1]); 8838bcb0991SDimitry Andric std::swap(OutVals[0], OutVals[1]); 8848bcb0991SDimitry Andric } 8858bcb0991SDimitry Andric 8865ffd83dbSDimitry Andric bool HasSwiftSelfArg = false; 8875ffd83dbSDimitry Andric bool HasSwiftErrorArg = false; 8880b57cec5SDimitry Andric unsigned NumFixedArgs = 0; 8890b57cec5SDimitry Andric for (unsigned I = 0; I < Outs.size(); ++I) { 8900b57cec5SDimitry Andric const ISD::OutputArg &Out = Outs[I]; 8910b57cec5SDimitry Andric SDValue &OutVal = OutVals[I]; 8925ffd83dbSDimitry Andric HasSwiftSelfArg |= Out.Flags.isSwiftSelf(); 8935ffd83dbSDimitry Andric HasSwiftErrorArg |= Out.Flags.isSwiftError(); 8940b57cec5SDimitry Andric if (Out.Flags.isNest()) 8950b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 8960b57cec5SDimitry Andric if (Out.Flags.isInAlloca()) 8970b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 8980b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegs()) 8990b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 9000b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegsLast()) 9010b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 9020b57cec5SDimitry Andric if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) { 9030b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 9040b57cec5SDimitry Andric int FI = MFI.CreateStackObject(Out.Flags.getByValSize(), 9055ffd83dbSDimitry Andric Out.Flags.getNonZeroByValAlign(), 9060b57cec5SDimitry Andric /*isSS=*/false); 9070b57cec5SDimitry Andric SDValue SizeNode = 9080b57cec5SDimitry Andric DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32); 9090b57cec5SDimitry Andric SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 9100b57cec5SDimitry Andric Chain = DAG.getMemcpy( 9115ffd83dbSDimitry Andric Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getNonZeroByValAlign(), 9120b57cec5SDimitry Andric /*isVolatile*/ false, /*AlwaysInline=*/false, 9130b57cec5SDimitry Andric /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); 9140b57cec5SDimitry Andric OutVal = FINode; 9150b57cec5SDimitry Andric } 9160b57cec5SDimitry Andric // Count the number of fixed args *after* legalization. 9170b57cec5SDimitry Andric NumFixedArgs += Out.IsFixed; 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric bool IsVarArg = CLI.IsVarArg; 9210b57cec5SDimitry Andric auto PtrVT = getPointerTy(Layout); 9220b57cec5SDimitry Andric 9235ffd83dbSDimitry Andric // For swiftcc, emit additional swiftself and swifterror arguments 9245ffd83dbSDimitry Andric // if there aren't. These additional arguments are also added for callee 9255ffd83dbSDimitry Andric // signature They are necessary to match callee and caller signature for 9265ffd83dbSDimitry Andric // indirect call. 9275ffd83dbSDimitry Andric if (CallConv == CallingConv::Swift) { 9285ffd83dbSDimitry Andric if (!HasSwiftSelfArg) { 9295ffd83dbSDimitry Andric NumFixedArgs++; 9305ffd83dbSDimitry Andric ISD::OutputArg Arg; 9315ffd83dbSDimitry Andric Arg.Flags.setSwiftSelf(); 9325ffd83dbSDimitry Andric CLI.Outs.push_back(Arg); 9335ffd83dbSDimitry Andric SDValue ArgVal = DAG.getUNDEF(PtrVT); 9345ffd83dbSDimitry Andric CLI.OutVals.push_back(ArgVal); 9355ffd83dbSDimitry Andric } 9365ffd83dbSDimitry Andric if (!HasSwiftErrorArg) { 9375ffd83dbSDimitry Andric NumFixedArgs++; 9385ffd83dbSDimitry Andric ISD::OutputArg Arg; 9395ffd83dbSDimitry Andric Arg.Flags.setSwiftError(); 9405ffd83dbSDimitry Andric CLI.Outs.push_back(Arg); 9415ffd83dbSDimitry Andric SDValue ArgVal = DAG.getUNDEF(PtrVT); 9425ffd83dbSDimitry Andric CLI.OutVals.push_back(ArgVal); 9435ffd83dbSDimitry Andric } 9445ffd83dbSDimitry Andric } 9455ffd83dbSDimitry Andric 9460b57cec5SDimitry Andric // Analyze operands of the call, assigning locations to each operand. 9470b57cec5SDimitry Andric SmallVector<CCValAssign, 16> ArgLocs; 9480b57cec5SDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 9490b57cec5SDimitry Andric 9500b57cec5SDimitry Andric if (IsVarArg) { 9510b57cec5SDimitry Andric // Outgoing non-fixed arguments are placed in a buffer. First 9520b57cec5SDimitry Andric // compute their offsets and the total amount of buffer space needed. 9530b57cec5SDimitry Andric for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) { 9540b57cec5SDimitry Andric const ISD::OutputArg &Out = Outs[I]; 9550b57cec5SDimitry Andric SDValue &Arg = OutVals[I]; 9560b57cec5SDimitry Andric EVT VT = Arg.getValueType(); 9570b57cec5SDimitry Andric assert(VT != MVT::iPTR && "Legalized args should be concrete"); 9580b57cec5SDimitry Andric Type *Ty = VT.getTypeForEVT(*DAG.getContext()); 9595ffd83dbSDimitry Andric Align Alignment = 9605ffd83dbSDimitry Andric std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty)); 9615ffd83dbSDimitry Andric unsigned Offset = 9625ffd83dbSDimitry Andric CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment); 9630b57cec5SDimitry Andric CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), 9640b57cec5SDimitry Andric Offset, VT.getSimpleVT(), 9650b57cec5SDimitry Andric CCValAssign::Full)); 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric } 9680b57cec5SDimitry Andric 9690b57cec5SDimitry Andric unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); 9700b57cec5SDimitry Andric 9710b57cec5SDimitry Andric SDValue FINode; 9720b57cec5SDimitry Andric if (IsVarArg && NumBytes) { 9730b57cec5SDimitry Andric // For non-fixed arguments, next emit stores to store the argument values 9740b57cec5SDimitry Andric // to the stack buffer at the offsets computed above. 9750b57cec5SDimitry Andric int FI = MF.getFrameInfo().CreateStackObject(NumBytes, 9760b57cec5SDimitry Andric Layout.getStackAlignment(), 9770b57cec5SDimitry Andric /*isSS=*/false); 9780b57cec5SDimitry Andric unsigned ValNo = 0; 9790b57cec5SDimitry Andric SmallVector<SDValue, 8> Chains; 980*e8d8bef9SDimitry Andric for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) { 9810b57cec5SDimitry Andric assert(ArgLocs[ValNo].getValNo() == ValNo && 9820b57cec5SDimitry Andric "ArgLocs should remain in order and only hold varargs args"); 9830b57cec5SDimitry Andric unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); 9840b57cec5SDimitry Andric FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 9850b57cec5SDimitry Andric SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode, 9860b57cec5SDimitry Andric DAG.getConstant(Offset, DL, PtrVT)); 9870b57cec5SDimitry Andric Chains.push_back( 9880b57cec5SDimitry Andric DAG.getStore(Chain, DL, Arg, Add, 989*e8d8bef9SDimitry Andric MachinePointerInfo::getFixedStack(MF, FI, Offset))); 9900b57cec5SDimitry Andric } 9910b57cec5SDimitry Andric if (!Chains.empty()) 9920b57cec5SDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); 9930b57cec5SDimitry Andric } else if (IsVarArg) { 9940b57cec5SDimitry Andric FINode = DAG.getIntPtrConstant(0, DL); 9950b57cec5SDimitry Andric } 9960b57cec5SDimitry Andric 9970b57cec5SDimitry Andric if (Callee->getOpcode() == ISD::GlobalAddress) { 9980b57cec5SDimitry Andric // If the callee is a GlobalAddress node (quite common, every direct call 9990b57cec5SDimitry Andric // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress 10000b57cec5SDimitry Andric // doesn't at MO_GOT which is not needed for direct calls. 10010b57cec5SDimitry Andric GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee); 10020b57cec5SDimitry Andric Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL, 10030b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout()), 10040b57cec5SDimitry Andric GA->getOffset()); 10050b57cec5SDimitry Andric Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL, 10060b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout()), Callee); 10070b57cec5SDimitry Andric } 10080b57cec5SDimitry Andric 10090b57cec5SDimitry Andric // Compute the operands for the CALLn node. 10100b57cec5SDimitry Andric SmallVector<SDValue, 16> Ops; 10110b57cec5SDimitry Andric Ops.push_back(Chain); 10120b57cec5SDimitry Andric Ops.push_back(Callee); 10130b57cec5SDimitry Andric 10140b57cec5SDimitry Andric // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs 10150b57cec5SDimitry Andric // isn't reliable. 10160b57cec5SDimitry Andric Ops.append(OutVals.begin(), 10170b57cec5SDimitry Andric IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); 10180b57cec5SDimitry Andric // Add a pointer to the vararg buffer. 10190b57cec5SDimitry Andric if (IsVarArg) 10200b57cec5SDimitry Andric Ops.push_back(FINode); 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric SmallVector<EVT, 8> InTys; 10230b57cec5SDimitry Andric for (const auto &In : Ins) { 10240b57cec5SDimitry Andric assert(!In.Flags.isByVal() && "byval is not valid for return values"); 10250b57cec5SDimitry Andric assert(!In.Flags.isNest() && "nest is not valid for return values"); 10260b57cec5SDimitry Andric if (In.Flags.isInAlloca()) 10270b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values"); 10280b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegs()) 10290b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values"); 10300b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegsLast()) 10310b57cec5SDimitry Andric fail(DL, DAG, 10320b57cec5SDimitry Andric "WebAssembly hasn't implemented cons regs last return values"); 10335ffd83dbSDimitry Andric // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in 10340b57cec5SDimitry Andric // registers. 10350b57cec5SDimitry Andric InTys.push_back(In.VT); 10360b57cec5SDimitry Andric } 10370b57cec5SDimitry Andric 10380b57cec5SDimitry Andric if (CLI.IsTailCall) { 10390b57cec5SDimitry Andric // ret_calls do not return values to the current frame 10400b57cec5SDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 10410b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops); 10420b57cec5SDimitry Andric } 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric InTys.push_back(MVT::Other); 10450b57cec5SDimitry Andric SDVTList InTyList = DAG.getVTList(InTys); 10465ffd83dbSDimitry Andric SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops); 10470b57cec5SDimitry Andric 10485ffd83dbSDimitry Andric for (size_t I = 0; I < Ins.size(); ++I) 10495ffd83dbSDimitry Andric InVals.push_back(Res.getValue(I)); 10505ffd83dbSDimitry Andric 10515ffd83dbSDimitry Andric // Return the chain 10525ffd83dbSDimitry Andric return Res.getValue(Ins.size()); 10530b57cec5SDimitry Andric } 10540b57cec5SDimitry Andric 10550b57cec5SDimitry Andric bool WebAssemblyTargetLowering::CanLowerReturn( 10560b57cec5SDimitry Andric CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/, 10570b57cec5SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 10580b57cec5SDimitry Andric LLVMContext & /*Context*/) const { 10598bcb0991SDimitry Andric // WebAssembly can only handle returning tuples with multivalue enabled 10608bcb0991SDimitry Andric return Subtarget->hasMultivalue() || Outs.size() <= 1; 10610b57cec5SDimitry Andric } 10620b57cec5SDimitry Andric 10630b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerReturn( 10640b57cec5SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, 10650b57cec5SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 10660b57cec5SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 10670b57cec5SDimitry Andric SelectionDAG &DAG) const { 10688bcb0991SDimitry Andric assert((Subtarget->hasMultivalue() || Outs.size() <= 1) && 10698bcb0991SDimitry Andric "MVP WebAssembly can only return up to one value"); 10700b57cec5SDimitry Andric if (!callingConvSupported(CallConv)) 10710b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 10720b57cec5SDimitry Andric 10730b57cec5SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 10740b57cec5SDimitry Andric RetOps.append(OutVals.begin(), OutVals.end()); 10750b57cec5SDimitry Andric Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric // Record the number and types of the return values. 10780b57cec5SDimitry Andric for (const ISD::OutputArg &Out : Outs) { 10790b57cec5SDimitry Andric assert(!Out.Flags.isByVal() && "byval is not valid for return values"); 10800b57cec5SDimitry Andric assert(!Out.Flags.isNest() && "nest is not valid for return values"); 10810b57cec5SDimitry Andric assert(Out.IsFixed && "non-fixed return value is not valid"); 10820b57cec5SDimitry Andric if (Out.Flags.isInAlloca()) 10830b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca results"); 10840b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegs()) 10850b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs results"); 10860b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegsLast()) 10870b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results"); 10880b57cec5SDimitry Andric } 10890b57cec5SDimitry Andric 10900b57cec5SDimitry Andric return Chain; 10910b57cec5SDimitry Andric } 10920b57cec5SDimitry Andric 10930b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFormalArguments( 10940b57cec5SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 10950b57cec5SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 10960b57cec5SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 10970b57cec5SDimitry Andric if (!callingConvSupported(CallConv)) 10980b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 10990b57cec5SDimitry Andric 11000b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 11010b57cec5SDimitry Andric auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric // Set up the incoming ARGUMENTS value, which serves to represent the liveness 11040b57cec5SDimitry Andric // of the incoming values before they're represented by virtual registers. 11050b57cec5SDimitry Andric MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); 11060b57cec5SDimitry Andric 11075ffd83dbSDimitry Andric bool HasSwiftErrorArg = false; 11085ffd83dbSDimitry Andric bool HasSwiftSelfArg = false; 11090b57cec5SDimitry Andric for (const ISD::InputArg &In : Ins) { 11105ffd83dbSDimitry Andric HasSwiftSelfArg |= In.Flags.isSwiftSelf(); 11115ffd83dbSDimitry Andric HasSwiftErrorArg |= In.Flags.isSwiftError(); 11120b57cec5SDimitry Andric if (In.Flags.isInAlloca()) 11130b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 11140b57cec5SDimitry Andric if (In.Flags.isNest()) 11150b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 11160b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegs()) 11170b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 11180b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegsLast()) 11190b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 11205ffd83dbSDimitry Andric // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in 11210b57cec5SDimitry Andric // registers. 11220b57cec5SDimitry Andric InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, 11230b57cec5SDimitry Andric DAG.getTargetConstant(InVals.size(), 11240b57cec5SDimitry Andric DL, MVT::i32)) 11250b57cec5SDimitry Andric : DAG.getUNDEF(In.VT)); 11260b57cec5SDimitry Andric 11270b57cec5SDimitry Andric // Record the number and types of arguments. 11280b57cec5SDimitry Andric MFI->addParam(In.VT); 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric 11315ffd83dbSDimitry Andric // For swiftcc, emit additional swiftself and swifterror arguments 11325ffd83dbSDimitry Andric // if there aren't. These additional arguments are also added for callee 11335ffd83dbSDimitry Andric // signature They are necessary to match callee and caller signature for 11345ffd83dbSDimitry Andric // indirect call. 11355ffd83dbSDimitry Andric auto PtrVT = getPointerTy(MF.getDataLayout()); 11365ffd83dbSDimitry Andric if (CallConv == CallingConv::Swift) { 11375ffd83dbSDimitry Andric if (!HasSwiftSelfArg) { 11385ffd83dbSDimitry Andric MFI->addParam(PtrVT); 11395ffd83dbSDimitry Andric } 11405ffd83dbSDimitry Andric if (!HasSwiftErrorArg) { 11415ffd83dbSDimitry Andric MFI->addParam(PtrVT); 11425ffd83dbSDimitry Andric } 11435ffd83dbSDimitry Andric } 11440b57cec5SDimitry Andric // Varargs are copied into a buffer allocated by the caller, and a pointer to 11450b57cec5SDimitry Andric // the buffer is passed as an argument. 11460b57cec5SDimitry Andric if (IsVarArg) { 11470b57cec5SDimitry Andric MVT PtrVT = getPointerTy(MF.getDataLayout()); 11488bcb0991SDimitry Andric Register VarargVreg = 11490b57cec5SDimitry Andric MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT)); 11500b57cec5SDimitry Andric MFI->setVarargBufferVreg(VarargVreg); 11510b57cec5SDimitry Andric Chain = DAG.getCopyToReg( 11520b57cec5SDimitry Andric Chain, DL, VarargVreg, 11530b57cec5SDimitry Andric DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT, 11540b57cec5SDimitry Andric DAG.getTargetConstant(Ins.size(), DL, MVT::i32))); 11550b57cec5SDimitry Andric MFI->addParam(PtrVT); 11560b57cec5SDimitry Andric } 11570b57cec5SDimitry Andric 11580b57cec5SDimitry Andric // Record the number and types of arguments and results. 11590b57cec5SDimitry Andric SmallVector<MVT, 4> Params; 11600b57cec5SDimitry Andric SmallVector<MVT, 4> Results; 11615ffd83dbSDimitry Andric computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(), 11625ffd83dbSDimitry Andric MF.getFunction(), DAG.getTarget(), Params, Results); 11630b57cec5SDimitry Andric for (MVT VT : Results) 11640b57cec5SDimitry Andric MFI->addResult(VT); 11650b57cec5SDimitry Andric // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify 11660b57cec5SDimitry Andric // the param logic here with ComputeSignatureVTs 11670b57cec5SDimitry Andric assert(MFI->getParams().size() == Params.size() && 11680b57cec5SDimitry Andric std::equal(MFI->getParams().begin(), MFI->getParams().end(), 11690b57cec5SDimitry Andric Params.begin())); 11700b57cec5SDimitry Andric 11710b57cec5SDimitry Andric return Chain; 11720b57cec5SDimitry Andric } 11730b57cec5SDimitry Andric 11740b57cec5SDimitry Andric void WebAssemblyTargetLowering::ReplaceNodeResults( 11750b57cec5SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 11760b57cec5SDimitry Andric switch (N->getOpcode()) { 11770b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 11780b57cec5SDimitry Andric // Do not add any results, signifying that N should not be custom lowered 11790b57cec5SDimitry Andric // after all. This happens because simd128 turns on custom lowering for 11800b57cec5SDimitry Andric // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an 11810b57cec5SDimitry Andric // illegal type. 11820b57cec5SDimitry Andric break; 11830b57cec5SDimitry Andric default: 11840b57cec5SDimitry Andric llvm_unreachable( 11850b57cec5SDimitry Andric "ReplaceNodeResults not implemented for this op for WebAssembly!"); 11860b57cec5SDimitry Andric } 11870b57cec5SDimitry Andric } 11880b57cec5SDimitry Andric 11890b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11900b57cec5SDimitry Andric // Custom lowering hooks. 11910b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11920b57cec5SDimitry Andric 11930b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, 11940b57cec5SDimitry Andric SelectionDAG &DAG) const { 11950b57cec5SDimitry Andric SDLoc DL(Op); 11960b57cec5SDimitry Andric switch (Op.getOpcode()) { 11970b57cec5SDimitry Andric default: 11980b57cec5SDimitry Andric llvm_unreachable("unimplemented operation lowering"); 11990b57cec5SDimitry Andric return SDValue(); 12000b57cec5SDimitry Andric case ISD::FrameIndex: 12010b57cec5SDimitry Andric return LowerFrameIndex(Op, DAG); 12020b57cec5SDimitry Andric case ISD::GlobalAddress: 12030b57cec5SDimitry Andric return LowerGlobalAddress(Op, DAG); 1204*e8d8bef9SDimitry Andric case ISD::GlobalTLSAddress: 1205*e8d8bef9SDimitry Andric return LowerGlobalTLSAddress(Op, DAG); 12060b57cec5SDimitry Andric case ISD::ExternalSymbol: 12070b57cec5SDimitry Andric return LowerExternalSymbol(Op, DAG); 12080b57cec5SDimitry Andric case ISD::JumpTable: 12090b57cec5SDimitry Andric return LowerJumpTable(Op, DAG); 12100b57cec5SDimitry Andric case ISD::BR_JT: 12110b57cec5SDimitry Andric return LowerBR_JT(Op, DAG); 12120b57cec5SDimitry Andric case ISD::VASTART: 12130b57cec5SDimitry Andric return LowerVASTART(Op, DAG); 12140b57cec5SDimitry Andric case ISD::BlockAddress: 12150b57cec5SDimitry Andric case ISD::BRIND: 12160b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented computed gotos"); 12170b57cec5SDimitry Andric return SDValue(); 12180b57cec5SDimitry Andric case ISD::RETURNADDR: 12190b57cec5SDimitry Andric return LowerRETURNADDR(Op, DAG); 12200b57cec5SDimitry Andric case ISD::FRAMEADDR: 12210b57cec5SDimitry Andric return LowerFRAMEADDR(Op, DAG); 12220b57cec5SDimitry Andric case ISD::CopyToReg: 12230b57cec5SDimitry Andric return LowerCopyToReg(Op, DAG); 12240b57cec5SDimitry Andric case ISD::EXTRACT_VECTOR_ELT: 12250b57cec5SDimitry Andric case ISD::INSERT_VECTOR_ELT: 12260b57cec5SDimitry Andric return LowerAccessVectorElement(Op, DAG); 12270b57cec5SDimitry Andric case ISD::INTRINSIC_VOID: 12280b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 12290b57cec5SDimitry Andric case ISD::INTRINSIC_W_CHAIN: 12300b57cec5SDimitry Andric return LowerIntrinsic(Op, DAG); 12310b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 12320b57cec5SDimitry Andric return LowerSIGN_EXTEND_INREG(Op, DAG); 12330b57cec5SDimitry Andric case ISD::BUILD_VECTOR: 12340b57cec5SDimitry Andric return LowerBUILD_VECTOR(Op, DAG); 12350b57cec5SDimitry Andric case ISD::VECTOR_SHUFFLE: 12360b57cec5SDimitry Andric return LowerVECTOR_SHUFFLE(Op, DAG); 1237480093f4SDimitry Andric case ISD::SETCC: 1238480093f4SDimitry Andric return LowerSETCC(Op, DAG); 12390b57cec5SDimitry Andric case ISD::SHL: 12400b57cec5SDimitry Andric case ISD::SRA: 12410b57cec5SDimitry Andric case ISD::SRL: 12420b57cec5SDimitry Andric return LowerShift(Op, DAG); 12430b57cec5SDimitry Andric } 12440b57cec5SDimitry Andric } 12450b57cec5SDimitry Andric 12460b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op, 12470b57cec5SDimitry Andric SelectionDAG &DAG) const { 12480b57cec5SDimitry Andric SDValue Src = Op.getOperand(2); 12490b57cec5SDimitry Andric if (isa<FrameIndexSDNode>(Src.getNode())) { 12500b57cec5SDimitry Andric // CopyToReg nodes don't support FrameIndex operands. Other targets select 12510b57cec5SDimitry Andric // the FI to some LEA-like instruction, but since we don't have that, we 12520b57cec5SDimitry Andric // need to insert some kind of instruction that can take an FI operand and 12530b57cec5SDimitry Andric // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy 12540b57cec5SDimitry Andric // local.copy between Op and its FI operand. 12550b57cec5SDimitry Andric SDValue Chain = Op.getOperand(0); 12560b57cec5SDimitry Andric SDLoc DL(Op); 12570b57cec5SDimitry Andric unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg(); 12580b57cec5SDimitry Andric EVT VT = Src.getValueType(); 12590b57cec5SDimitry Andric SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32 12600b57cec5SDimitry Andric : WebAssembly::COPY_I64, 12610b57cec5SDimitry Andric DL, VT, Src), 12620b57cec5SDimitry Andric 0); 12630b57cec5SDimitry Andric return Op.getNode()->getNumValues() == 1 12640b57cec5SDimitry Andric ? DAG.getCopyToReg(Chain, DL, Reg, Copy) 12650b57cec5SDimitry Andric : DAG.getCopyToReg(Chain, DL, Reg, Copy, 12660b57cec5SDimitry Andric Op.getNumOperands() == 4 ? Op.getOperand(3) 12670b57cec5SDimitry Andric : SDValue()); 12680b57cec5SDimitry Andric } 12690b57cec5SDimitry Andric return SDValue(); 12700b57cec5SDimitry Andric } 12710b57cec5SDimitry Andric 12720b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, 12730b57cec5SDimitry Andric SelectionDAG &DAG) const { 12740b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Op)->getIndex(); 12750b57cec5SDimitry Andric return DAG.getTargetFrameIndex(FI, Op.getValueType()); 12760b57cec5SDimitry Andric } 12770b57cec5SDimitry Andric 12780b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op, 12790b57cec5SDimitry Andric SelectionDAG &DAG) const { 12800b57cec5SDimitry Andric SDLoc DL(Op); 12810b57cec5SDimitry Andric 12820b57cec5SDimitry Andric if (!Subtarget->getTargetTriple().isOSEmscripten()) { 12830b57cec5SDimitry Andric fail(DL, DAG, 12840b57cec5SDimitry Andric "Non-Emscripten WebAssembly hasn't implemented " 12850b57cec5SDimitry Andric "__builtin_return_address"); 12860b57cec5SDimitry Andric return SDValue(); 12870b57cec5SDimitry Andric } 12880b57cec5SDimitry Andric 12890b57cec5SDimitry Andric if (verifyReturnAddressArgumentIsConstant(Op, DAG)) 12900b57cec5SDimitry Andric return SDValue(); 12910b57cec5SDimitry Andric 12920b57cec5SDimitry Andric unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 12938bcb0991SDimitry Andric MakeLibCallOptions CallOptions; 12940b57cec5SDimitry Andric return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(), 12958bcb0991SDimitry Andric {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL) 12960b57cec5SDimitry Andric .first; 12970b57cec5SDimitry Andric } 12980b57cec5SDimitry Andric 12990b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op, 13000b57cec5SDimitry Andric SelectionDAG &DAG) const { 13010b57cec5SDimitry Andric // Non-zero depths are not supported by WebAssembly currently. Use the 13020b57cec5SDimitry Andric // legalizer's default expansion, which is to return 0 (what this function is 13030b57cec5SDimitry Andric // documented to do). 13040b57cec5SDimitry Andric if (Op.getConstantOperandVal(0) > 0) 13050b57cec5SDimitry Andric return SDValue(); 13060b57cec5SDimitry Andric 13070b57cec5SDimitry Andric DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true); 13080b57cec5SDimitry Andric EVT VT = Op.getValueType(); 13098bcb0991SDimitry Andric Register FP = 13100b57cec5SDimitry Andric Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); 13110b57cec5SDimitry Andric return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT); 13120b57cec5SDimitry Andric } 13130b57cec5SDimitry Andric 1314*e8d8bef9SDimitry Andric SDValue 1315*e8d8bef9SDimitry Andric WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, 1316*e8d8bef9SDimitry Andric SelectionDAG &DAG) const { 1317*e8d8bef9SDimitry Andric SDLoc DL(Op); 1318*e8d8bef9SDimitry Andric const auto *GA = cast<GlobalAddressSDNode>(Op); 1319*e8d8bef9SDimitry Andric MVT PtrVT = getPointerTy(DAG.getDataLayout()); 1320*e8d8bef9SDimitry Andric 1321*e8d8bef9SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 1322*e8d8bef9SDimitry Andric if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory()) 1323*e8d8bef9SDimitry Andric report_fatal_error("cannot use thread-local storage without bulk memory", 1324*e8d8bef9SDimitry Andric false); 1325*e8d8bef9SDimitry Andric 1326*e8d8bef9SDimitry Andric const GlobalValue *GV = GA->getGlobal(); 1327*e8d8bef9SDimitry Andric 1328*e8d8bef9SDimitry Andric // Currently Emscripten does not support dynamic linking with threads. 1329*e8d8bef9SDimitry Andric // Therefore, if we have thread-local storage, only the local-exec model 1330*e8d8bef9SDimitry Andric // is possible. 1331*e8d8bef9SDimitry Andric // TODO: remove this and implement proper TLS models once Emscripten 1332*e8d8bef9SDimitry Andric // supports dynamic linking with threads. 1333*e8d8bef9SDimitry Andric if (GV->getThreadLocalMode() != GlobalValue::LocalExecTLSModel && 1334*e8d8bef9SDimitry Andric !Subtarget->getTargetTriple().isOSEmscripten()) { 1335*e8d8bef9SDimitry Andric report_fatal_error("only -ftls-model=local-exec is supported for now on " 1336*e8d8bef9SDimitry Andric "non-Emscripten OSes: variable " + 1337*e8d8bef9SDimitry Andric GV->getName(), 1338*e8d8bef9SDimitry Andric false); 1339*e8d8bef9SDimitry Andric } 1340*e8d8bef9SDimitry Andric 1341*e8d8bef9SDimitry Andric auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 1342*e8d8bef9SDimitry Andric : WebAssembly::GLOBAL_GET_I32; 1343*e8d8bef9SDimitry Andric const char *BaseName = MF.createExternalSymbolName("__tls_base"); 1344*e8d8bef9SDimitry Andric 1345*e8d8bef9SDimitry Andric SDValue BaseAddr( 1346*e8d8bef9SDimitry Andric DAG.getMachineNode(GlobalGet, DL, PtrVT, 1347*e8d8bef9SDimitry Andric DAG.getTargetExternalSymbol(BaseName, PtrVT)), 1348*e8d8bef9SDimitry Andric 0); 1349*e8d8bef9SDimitry Andric 1350*e8d8bef9SDimitry Andric SDValue TLSOffset = DAG.getTargetGlobalAddress( 1351*e8d8bef9SDimitry Andric GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL); 1352*e8d8bef9SDimitry Andric SDValue SymAddr = DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, TLSOffset); 1353*e8d8bef9SDimitry Andric 1354*e8d8bef9SDimitry Andric return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr); 1355*e8d8bef9SDimitry Andric } 1356*e8d8bef9SDimitry Andric 13570b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, 13580b57cec5SDimitry Andric SelectionDAG &DAG) const { 13590b57cec5SDimitry Andric SDLoc DL(Op); 13600b57cec5SDimitry Andric const auto *GA = cast<GlobalAddressSDNode>(Op); 13610b57cec5SDimitry Andric EVT VT = Op.getValueType(); 13620b57cec5SDimitry Andric assert(GA->getTargetFlags() == 0 && 13630b57cec5SDimitry Andric "Unexpected target flags on generic GlobalAddressSDNode"); 13640b57cec5SDimitry Andric if (GA->getAddressSpace() != 0) 13650b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly only expects the 0 address space"); 13660b57cec5SDimitry Andric 13670b57cec5SDimitry Andric unsigned OperandFlags = 0; 13680b57cec5SDimitry Andric if (isPositionIndependent()) { 13690b57cec5SDimitry Andric const GlobalValue *GV = GA->getGlobal(); 13700b57cec5SDimitry Andric if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) { 13710b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 13720b57cec5SDimitry Andric MVT PtrVT = getPointerTy(MF.getDataLayout()); 13730b57cec5SDimitry Andric const char *BaseName; 13740b57cec5SDimitry Andric if (GV->getValueType()->isFunctionTy()) { 13750b57cec5SDimitry Andric BaseName = MF.createExternalSymbolName("__table_base"); 13760b57cec5SDimitry Andric OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL; 13770b57cec5SDimitry Andric } 13780b57cec5SDimitry Andric else { 13790b57cec5SDimitry Andric BaseName = MF.createExternalSymbolName("__memory_base"); 13800b57cec5SDimitry Andric OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL; 13810b57cec5SDimitry Andric } 13820b57cec5SDimitry Andric SDValue BaseAddr = 13830b57cec5SDimitry Andric DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, 13840b57cec5SDimitry Andric DAG.getTargetExternalSymbol(BaseName, PtrVT)); 13850b57cec5SDimitry Andric 13860b57cec5SDimitry Andric SDValue SymAddr = DAG.getNode( 13870b57cec5SDimitry Andric WebAssemblyISD::WrapperPIC, DL, VT, 13880b57cec5SDimitry Andric DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(), 13890b57cec5SDimitry Andric OperandFlags)); 13900b57cec5SDimitry Andric 13910b57cec5SDimitry Andric return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr); 13920b57cec5SDimitry Andric } else { 13930b57cec5SDimitry Andric OperandFlags = WebAssemblyII::MO_GOT; 13940b57cec5SDimitry Andric } 13950b57cec5SDimitry Andric } 13960b57cec5SDimitry Andric 13970b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 13980b57cec5SDimitry Andric DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, 13990b57cec5SDimitry Andric GA->getOffset(), OperandFlags)); 14000b57cec5SDimitry Andric } 14010b57cec5SDimitry Andric 14020b57cec5SDimitry Andric SDValue 14030b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op, 14040b57cec5SDimitry Andric SelectionDAG &DAG) const { 14050b57cec5SDimitry Andric SDLoc DL(Op); 14060b57cec5SDimitry Andric const auto *ES = cast<ExternalSymbolSDNode>(Op); 14070b57cec5SDimitry Andric EVT VT = Op.getValueType(); 14080b57cec5SDimitry Andric assert(ES->getTargetFlags() == 0 && 14090b57cec5SDimitry Andric "Unexpected target flags on generic ExternalSymbolSDNode"); 14100b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 14110b57cec5SDimitry Andric DAG.getTargetExternalSymbol(ES->getSymbol(), VT)); 14120b57cec5SDimitry Andric } 14130b57cec5SDimitry Andric 14140b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op, 14150b57cec5SDimitry Andric SelectionDAG &DAG) const { 14160b57cec5SDimitry Andric // There's no need for a Wrapper node because we always incorporate a jump 14170b57cec5SDimitry Andric // table operand into a BR_TABLE instruction, rather than ever 14180b57cec5SDimitry Andric // materializing it in a register. 14190b57cec5SDimitry Andric const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); 14200b57cec5SDimitry Andric return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(), 14210b57cec5SDimitry Andric JT->getTargetFlags()); 14220b57cec5SDimitry Andric } 14230b57cec5SDimitry Andric 14240b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, 14250b57cec5SDimitry Andric SelectionDAG &DAG) const { 14260b57cec5SDimitry Andric SDLoc DL(Op); 14270b57cec5SDimitry Andric SDValue Chain = Op.getOperand(0); 14280b57cec5SDimitry Andric const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1)); 14290b57cec5SDimitry Andric SDValue Index = Op.getOperand(2); 14300b57cec5SDimitry Andric assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags"); 14310b57cec5SDimitry Andric 14320b57cec5SDimitry Andric SmallVector<SDValue, 8> Ops; 14330b57cec5SDimitry Andric Ops.push_back(Chain); 14340b57cec5SDimitry Andric Ops.push_back(Index); 14350b57cec5SDimitry Andric 14360b57cec5SDimitry Andric MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo(); 14370b57cec5SDimitry Andric const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; 14380b57cec5SDimitry Andric 14390b57cec5SDimitry Andric // Add an operand for each case. 14400b57cec5SDimitry Andric for (auto MBB : MBBs) 14410b57cec5SDimitry Andric Ops.push_back(DAG.getBasicBlock(MBB)); 14420b57cec5SDimitry Andric 14435ffd83dbSDimitry Andric // Add the first MBB as a dummy default target for now. This will be replaced 14445ffd83dbSDimitry Andric // with the proper default target (and the preceding range check eliminated) 14455ffd83dbSDimitry Andric // if possible by WebAssemblyFixBrTableDefaults. 14465ffd83dbSDimitry Andric Ops.push_back(DAG.getBasicBlock(*MBBs.begin())); 14470b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops); 14480b57cec5SDimitry Andric } 14490b57cec5SDimitry Andric 14500b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, 14510b57cec5SDimitry Andric SelectionDAG &DAG) const { 14520b57cec5SDimitry Andric SDLoc DL(Op); 14530b57cec5SDimitry Andric EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); 14540b57cec5SDimitry Andric 14550b57cec5SDimitry Andric auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>(); 14560b57cec5SDimitry Andric const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 14570b57cec5SDimitry Andric 14580b57cec5SDimitry Andric SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL, 14590b57cec5SDimitry Andric MFI->getVarargBufferVreg(), PtrVT); 14600b57cec5SDimitry Andric return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1), 1461*e8d8bef9SDimitry Andric MachinePointerInfo(SV)); 1462*e8d8bef9SDimitry Andric } 1463*e8d8bef9SDimitry Andric 1464*e8d8bef9SDimitry Andric static SDValue getCppExceptionSymNode(SDValue Op, unsigned TagIndex, 1465*e8d8bef9SDimitry Andric SelectionDAG &DAG) { 1466*e8d8bef9SDimitry Andric // We only support C++ exceptions for now 1467*e8d8bef9SDimitry Andric int Tag = 1468*e8d8bef9SDimitry Andric cast<ConstantSDNode>(Op.getOperand(TagIndex).getNode())->getZExtValue(); 1469*e8d8bef9SDimitry Andric if (Tag != WebAssembly::CPP_EXCEPTION) 1470*e8d8bef9SDimitry Andric llvm_unreachable("Invalid tag: We only support C++ exceptions for now"); 1471*e8d8bef9SDimitry Andric auto &MF = DAG.getMachineFunction(); 1472*e8d8bef9SDimitry Andric const auto &TLI = DAG.getTargetLoweringInfo(); 1473*e8d8bef9SDimitry Andric MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); 1474*e8d8bef9SDimitry Andric const char *SymName = MF.createExternalSymbolName("__cpp_exception"); 1475*e8d8bef9SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, SDLoc(Op), PtrVT, 1476*e8d8bef9SDimitry Andric DAG.getTargetExternalSymbol(SymName, PtrVT)); 14770b57cec5SDimitry Andric } 14780b57cec5SDimitry Andric 14790b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, 14800b57cec5SDimitry Andric SelectionDAG &DAG) const { 14810b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 14820b57cec5SDimitry Andric unsigned IntNo; 14830b57cec5SDimitry Andric switch (Op.getOpcode()) { 14840b57cec5SDimitry Andric case ISD::INTRINSIC_VOID: 14850b57cec5SDimitry Andric case ISD::INTRINSIC_W_CHAIN: 14860b57cec5SDimitry Andric IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); 14870b57cec5SDimitry Andric break; 14880b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 14890b57cec5SDimitry Andric IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 14900b57cec5SDimitry Andric break; 14910b57cec5SDimitry Andric default: 14920b57cec5SDimitry Andric llvm_unreachable("Invalid intrinsic"); 14930b57cec5SDimitry Andric } 14940b57cec5SDimitry Andric SDLoc DL(Op); 14950b57cec5SDimitry Andric 14960b57cec5SDimitry Andric switch (IntNo) { 14970b57cec5SDimitry Andric default: 14980b57cec5SDimitry Andric return SDValue(); // Don't custom lower most intrinsics. 14990b57cec5SDimitry Andric 15000b57cec5SDimitry Andric case Intrinsic::wasm_lsda: { 15010b57cec5SDimitry Andric EVT VT = Op.getValueType(); 15020b57cec5SDimitry Andric const TargetLowering &TLI = DAG.getTargetLoweringInfo(); 15030b57cec5SDimitry Andric MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); 15040b57cec5SDimitry Andric auto &Context = MF.getMMI().getContext(); 15050b57cec5SDimitry Andric MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") + 15060b57cec5SDimitry Andric Twine(MF.getFunctionNumber())); 15070b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 15080b57cec5SDimitry Andric DAG.getMCSymbol(S, PtrVT)); 15090b57cec5SDimitry Andric } 15100b57cec5SDimitry Andric 15110b57cec5SDimitry Andric case Intrinsic::wasm_throw: { 1512*e8d8bef9SDimitry Andric SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); 15130b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::THROW, DL, 15140b57cec5SDimitry Andric MVT::Other, // outchain type 15150b57cec5SDimitry Andric { 15160b57cec5SDimitry Andric Op.getOperand(0), // inchain 15170b57cec5SDimitry Andric SymNode, // exception symbol 15180b57cec5SDimitry Andric Op.getOperand(3) // thrown value 15190b57cec5SDimitry Andric }); 15200b57cec5SDimitry Andric } 15215ffd83dbSDimitry Andric 1522*e8d8bef9SDimitry Andric case Intrinsic::wasm_catch: { 1523*e8d8bef9SDimitry Andric SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); 1524*e8d8bef9SDimitry Andric return DAG.getNode(WebAssemblyISD::CATCH, DL, 1525*e8d8bef9SDimitry Andric { 1526*e8d8bef9SDimitry Andric MVT::i32, // outchain type 1527*e8d8bef9SDimitry Andric MVT::Other // return value 1528*e8d8bef9SDimitry Andric }, 1529*e8d8bef9SDimitry Andric { 1530*e8d8bef9SDimitry Andric Op.getOperand(0), // inchain 1531*e8d8bef9SDimitry Andric SymNode // exception symbol 1532*e8d8bef9SDimitry Andric }); 1533*e8d8bef9SDimitry Andric } 1534*e8d8bef9SDimitry Andric 15355ffd83dbSDimitry Andric case Intrinsic::wasm_shuffle: { 15365ffd83dbSDimitry Andric // Drop in-chain and replace undefs, but otherwise pass through unchanged 15375ffd83dbSDimitry Andric SDValue Ops[18]; 15385ffd83dbSDimitry Andric size_t OpIdx = 0; 15395ffd83dbSDimitry Andric Ops[OpIdx++] = Op.getOperand(1); 15405ffd83dbSDimitry Andric Ops[OpIdx++] = Op.getOperand(2); 15415ffd83dbSDimitry Andric while (OpIdx < 18) { 15425ffd83dbSDimitry Andric const SDValue &MaskIdx = Op.getOperand(OpIdx + 1); 15435ffd83dbSDimitry Andric if (MaskIdx.isUndef() || 15445ffd83dbSDimitry Andric cast<ConstantSDNode>(MaskIdx.getNode())->getZExtValue() >= 32) { 15455ffd83dbSDimitry Andric Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32); 15465ffd83dbSDimitry Andric } else { 15475ffd83dbSDimitry Andric Ops[OpIdx++] = MaskIdx; 15485ffd83dbSDimitry Andric } 15495ffd83dbSDimitry Andric } 15505ffd83dbSDimitry Andric return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); 15515ffd83dbSDimitry Andric } 15520b57cec5SDimitry Andric } 15530b57cec5SDimitry Andric } 15540b57cec5SDimitry Andric 15550b57cec5SDimitry Andric SDValue 15560b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op, 15570b57cec5SDimitry Andric SelectionDAG &DAG) const { 15580b57cec5SDimitry Andric SDLoc DL(Op); 15590b57cec5SDimitry Andric // If sign extension operations are disabled, allow sext_inreg only if operand 15605ffd83dbSDimitry Andric // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign 15615ffd83dbSDimitry Andric // extension operations, but allowing sext_inreg in this context lets us have 15625ffd83dbSDimitry Andric // simple patterns to select extract_lane_s instructions. Expanding sext_inreg 15635ffd83dbSDimitry Andric // everywhere would be simpler in this file, but would necessitate large and 15645ffd83dbSDimitry Andric // brittle patterns to undo the expansion and select extract_lane_s 15655ffd83dbSDimitry Andric // instructions. 15660b57cec5SDimitry Andric assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128()); 15675ffd83dbSDimitry Andric if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT) 15685ffd83dbSDimitry Andric return SDValue(); 15695ffd83dbSDimitry Andric 15700b57cec5SDimitry Andric const SDValue &Extract = Op.getOperand(0); 15710b57cec5SDimitry Andric MVT VecT = Extract.getOperand(0).getSimpleValueType(); 15725ffd83dbSDimitry Andric if (VecT.getVectorElementType().getSizeInBits() > 32) 15735ffd83dbSDimitry Andric return SDValue(); 15745ffd83dbSDimitry Andric MVT ExtractedLaneT = 15755ffd83dbSDimitry Andric cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT(); 15760b57cec5SDimitry Andric MVT ExtractedVecT = 15770b57cec5SDimitry Andric MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits()); 15780b57cec5SDimitry Andric if (ExtractedVecT == VecT) 15790b57cec5SDimitry Andric return Op; 15805ffd83dbSDimitry Andric 15810b57cec5SDimitry Andric // Bitcast vector to appropriate type to ensure ISel pattern coverage 15825ffd83dbSDimitry Andric const SDNode *Index = Extract.getOperand(1).getNode(); 15835ffd83dbSDimitry Andric if (!isa<ConstantSDNode>(Index)) 15845ffd83dbSDimitry Andric return SDValue(); 15855ffd83dbSDimitry Andric unsigned IndexVal = cast<ConstantSDNode>(Index)->getZExtValue(); 15860b57cec5SDimitry Andric unsigned Scale = 15870b57cec5SDimitry Andric ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements(); 15880b57cec5SDimitry Andric assert(Scale > 1); 15890b57cec5SDimitry Andric SDValue NewIndex = 15905ffd83dbSDimitry Andric DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0)); 15910b57cec5SDimitry Andric SDValue NewExtract = DAG.getNode( 15920b57cec5SDimitry Andric ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(), 15930b57cec5SDimitry Andric DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex); 15945ffd83dbSDimitry Andric return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract, 15955ffd83dbSDimitry Andric Op.getOperand(1)); 15960b57cec5SDimitry Andric } 15970b57cec5SDimitry Andric 15980b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op, 15990b57cec5SDimitry Andric SelectionDAG &DAG) const { 16000b57cec5SDimitry Andric SDLoc DL(Op); 16010b57cec5SDimitry Andric const EVT VecT = Op.getValueType(); 16020b57cec5SDimitry Andric const EVT LaneT = Op.getOperand(0).getValueType(); 16030b57cec5SDimitry Andric const size_t Lanes = Op.getNumOperands(); 16045ffd83dbSDimitry Andric bool CanSwizzle = VecT == MVT::v16i8; 16058bcb0991SDimitry Andric 16068bcb0991SDimitry Andric // BUILD_VECTORs are lowered to the instruction that initializes the highest 16078bcb0991SDimitry Andric // possible number of lanes at once followed by a sequence of replace_lane 16088bcb0991SDimitry Andric // instructions to individually initialize any remaining lanes. 16098bcb0991SDimitry Andric 16108bcb0991SDimitry Andric // TODO: Tune this. For example, lanewise swizzling is very expensive, so 16118bcb0991SDimitry Andric // swizzled lanes should be given greater weight. 16128bcb0991SDimitry Andric 16138bcb0991SDimitry Andric // TODO: Investigate building vectors by shuffling together vectors built by 16148bcb0991SDimitry Andric // separately specialized means. 16158bcb0991SDimitry Andric 16160b57cec5SDimitry Andric auto IsConstant = [](const SDValue &V) { 16170b57cec5SDimitry Andric return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP; 16180b57cec5SDimitry Andric }; 16190b57cec5SDimitry Andric 16208bcb0991SDimitry Andric // Returns the source vector and index vector pair if they exist. Checks for: 16218bcb0991SDimitry Andric // (extract_vector_elt 16228bcb0991SDimitry Andric // $src, 16238bcb0991SDimitry Andric // (sign_extend_inreg (extract_vector_elt $indices, $i)) 16248bcb0991SDimitry Andric // ) 16258bcb0991SDimitry Andric auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) { 16268bcb0991SDimitry Andric auto Bail = std::make_pair(SDValue(), SDValue()); 16278bcb0991SDimitry Andric if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 16288bcb0991SDimitry Andric return Bail; 16298bcb0991SDimitry Andric const SDValue &SwizzleSrc = Lane->getOperand(0); 16308bcb0991SDimitry Andric const SDValue &IndexExt = Lane->getOperand(1); 16318bcb0991SDimitry Andric if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG) 16328bcb0991SDimitry Andric return Bail; 16338bcb0991SDimitry Andric const SDValue &Index = IndexExt->getOperand(0); 16348bcb0991SDimitry Andric if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 16358bcb0991SDimitry Andric return Bail; 16368bcb0991SDimitry Andric const SDValue &SwizzleIndices = Index->getOperand(0); 16378bcb0991SDimitry Andric if (SwizzleSrc.getValueType() != MVT::v16i8 || 16388bcb0991SDimitry Andric SwizzleIndices.getValueType() != MVT::v16i8 || 16398bcb0991SDimitry Andric Index->getOperand(1)->getOpcode() != ISD::Constant || 16408bcb0991SDimitry Andric Index->getConstantOperandVal(1) != I) 16418bcb0991SDimitry Andric return Bail; 16428bcb0991SDimitry Andric return std::make_pair(SwizzleSrc, SwizzleIndices); 16438bcb0991SDimitry Andric }; 16448bcb0991SDimitry Andric 16458bcb0991SDimitry Andric using ValueEntry = std::pair<SDValue, size_t>; 16468bcb0991SDimitry Andric SmallVector<ValueEntry, 16> SplatValueCounts; 16478bcb0991SDimitry Andric 16488bcb0991SDimitry Andric using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>; 16498bcb0991SDimitry Andric SmallVector<SwizzleEntry, 16> SwizzleCounts; 16508bcb0991SDimitry Andric 16518bcb0991SDimitry Andric auto AddCount = [](auto &Counts, const auto &Val) { 1652*e8d8bef9SDimitry Andric auto CountIt = 1653*e8d8bef9SDimitry Andric llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; }); 16548bcb0991SDimitry Andric if (CountIt == Counts.end()) { 16558bcb0991SDimitry Andric Counts.emplace_back(Val, 1); 16560b57cec5SDimitry Andric } else { 16570b57cec5SDimitry Andric CountIt->second++; 16580b57cec5SDimitry Andric } 16598bcb0991SDimitry Andric }; 16600b57cec5SDimitry Andric 16618bcb0991SDimitry Andric auto GetMostCommon = [](auto &Counts) { 16628bcb0991SDimitry Andric auto CommonIt = 16638bcb0991SDimitry Andric std::max_element(Counts.begin(), Counts.end(), 16648bcb0991SDimitry Andric [](auto A, auto B) { return A.second < B.second; }); 16658bcb0991SDimitry Andric assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector"); 16668bcb0991SDimitry Andric return *CommonIt; 16678bcb0991SDimitry Andric }; 16688bcb0991SDimitry Andric 16698bcb0991SDimitry Andric size_t NumConstantLanes = 0; 16708bcb0991SDimitry Andric 16718bcb0991SDimitry Andric // Count eligible lanes for each type of vector creation op 16728bcb0991SDimitry Andric for (size_t I = 0; I < Lanes; ++I) { 16738bcb0991SDimitry Andric const SDValue &Lane = Op->getOperand(I); 16748bcb0991SDimitry Andric if (Lane.isUndef()) 16758bcb0991SDimitry Andric continue; 16768bcb0991SDimitry Andric 16778bcb0991SDimitry Andric AddCount(SplatValueCounts, Lane); 16788bcb0991SDimitry Andric 16798bcb0991SDimitry Andric if (IsConstant(Lane)) { 16808bcb0991SDimitry Andric NumConstantLanes++; 16818bcb0991SDimitry Andric } else if (CanSwizzle) { 16828bcb0991SDimitry Andric auto SwizzleSrcs = GetSwizzleSrcs(I, Lane); 16838bcb0991SDimitry Andric if (SwizzleSrcs.first) 16848bcb0991SDimitry Andric AddCount(SwizzleCounts, SwizzleSrcs); 16858bcb0991SDimitry Andric } 16868bcb0991SDimitry Andric } 16878bcb0991SDimitry Andric 16888bcb0991SDimitry Andric SDValue SplatValue; 16898bcb0991SDimitry Andric size_t NumSplatLanes; 16908bcb0991SDimitry Andric std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts); 16918bcb0991SDimitry Andric 16928bcb0991SDimitry Andric SDValue SwizzleSrc; 16938bcb0991SDimitry Andric SDValue SwizzleIndices; 16948bcb0991SDimitry Andric size_t NumSwizzleLanes = 0; 16958bcb0991SDimitry Andric if (SwizzleCounts.size()) 16968bcb0991SDimitry Andric std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices), 16978bcb0991SDimitry Andric NumSwizzleLanes) = GetMostCommon(SwizzleCounts); 16988bcb0991SDimitry Andric 16998bcb0991SDimitry Andric // Predicate returning true if the lane is properly initialized by the 17008bcb0991SDimitry Andric // original instruction 17018bcb0991SDimitry Andric std::function<bool(size_t, const SDValue &)> IsLaneConstructed; 17028bcb0991SDimitry Andric SDValue Result; 17038bcb0991SDimitry Andric // Prefer swizzles over vector consts over splats 17048bcb0991SDimitry Andric if (NumSwizzleLanes >= NumSplatLanes && 17055ffd83dbSDimitry Andric (!Subtarget->hasUnimplementedSIMD128() || 17065ffd83dbSDimitry Andric NumSwizzleLanes >= NumConstantLanes)) { 17078bcb0991SDimitry Andric Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc, 17088bcb0991SDimitry Andric SwizzleIndices); 17098bcb0991SDimitry Andric auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices); 17108bcb0991SDimitry Andric IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) { 17118bcb0991SDimitry Andric return Swizzled == GetSwizzleSrcs(I, Lane); 17128bcb0991SDimitry Andric }; 17135ffd83dbSDimitry Andric } else if (NumConstantLanes >= NumSplatLanes && 17145ffd83dbSDimitry Andric Subtarget->hasUnimplementedSIMD128()) { 1715*e8d8bef9SDimitry Andric // If we support v128.const, emit it directly 17160b57cec5SDimitry Andric SmallVector<SDValue, 16> ConstLanes; 17170b57cec5SDimitry Andric for (const SDValue &Lane : Op->op_values()) { 17180b57cec5SDimitry Andric if (IsConstant(Lane)) { 17190b57cec5SDimitry Andric ConstLanes.push_back(Lane); 17200b57cec5SDimitry Andric } else if (LaneT.isFloatingPoint()) { 17210b57cec5SDimitry Andric ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT)); 17220b57cec5SDimitry Andric } else { 17230b57cec5SDimitry Andric ConstLanes.push_back(DAG.getConstant(0, DL, LaneT)); 17240b57cec5SDimitry Andric } 17250b57cec5SDimitry Andric } 17268bcb0991SDimitry Andric Result = DAG.getBuildVector(VecT, DL, ConstLanes); 1727*e8d8bef9SDimitry Andric IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) { 17288bcb0991SDimitry Andric return IsConstant(Lane); 17298bcb0991SDimitry Andric }; 1730*e8d8bef9SDimitry Andric } else if (NumConstantLanes >= NumSplatLanes && VecT.isInteger()) { 1731*e8d8bef9SDimitry Andric // Otherwise, if this is an integer vector, pack the lane values together so 1732*e8d8bef9SDimitry Andric // we can construct the 128-bit constant from a pair of i64s using a splat 1733*e8d8bef9SDimitry Andric // followed by at most one i64x2.replace_lane. Also keep track of the lanes 1734*e8d8bef9SDimitry Andric // that actually matter so we can avoid the replace_lane in more cases. 1735*e8d8bef9SDimitry Andric std::array<uint64_t, 2> I64s{{0, 0}}; 1736*e8d8bef9SDimitry Andric std::array<uint64_t, 2> ConstLaneMasks{{0, 0}}; 1737*e8d8bef9SDimitry Andric size_t LaneBits = 128 / Lanes; 1738*e8d8bef9SDimitry Andric size_t HalfLanes = Lanes / 2; 1739*e8d8bef9SDimitry Andric for (size_t I = 0; I < Lanes; ++I) { 1740*e8d8bef9SDimitry Andric const SDValue &Lane = Op.getOperand(I); 1741*e8d8bef9SDimitry Andric if (IsConstant(Lane)) { 1742*e8d8bef9SDimitry Andric // How much we need to shift Val to position it in an i64 1743*e8d8bef9SDimitry Andric auto Shift = LaneBits * (I % HalfLanes); 1744*e8d8bef9SDimitry Andric auto Mask = maskTrailingOnes<uint64_t>(LaneBits); 1745*e8d8bef9SDimitry Andric auto Val = cast<ConstantSDNode>(Lane.getNode())->getZExtValue() & Mask; 1746*e8d8bef9SDimitry Andric I64s[I / HalfLanes] |= Val << Shift; 1747*e8d8bef9SDimitry Andric ConstLaneMasks[I / HalfLanes] |= Mask << Shift; 17488bcb0991SDimitry Andric } 1749*e8d8bef9SDimitry Andric } 1750*e8d8bef9SDimitry Andric // Check whether all constant lanes in the second half of the vector are 1751*e8d8bef9SDimitry Andric // equivalent in the first half or vice versa to determine whether splatting 1752*e8d8bef9SDimitry Andric // either side will be sufficient to materialize the constant. As a special 1753*e8d8bef9SDimitry Andric // case, if the first and second halves have no constant lanes in common, we 1754*e8d8bef9SDimitry Andric // can just combine them. 1755*e8d8bef9SDimitry Andric bool FirstHalfSufficient = (I64s[0] & ConstLaneMasks[1]) == I64s[1]; 1756*e8d8bef9SDimitry Andric bool SecondHalfSufficient = (I64s[1] & ConstLaneMasks[0]) == I64s[0]; 1757*e8d8bef9SDimitry Andric bool CombinedSufficient = (ConstLaneMasks[0] & ConstLaneMasks[1]) == 0; 1758*e8d8bef9SDimitry Andric 1759*e8d8bef9SDimitry Andric uint64_t Splatted; 1760*e8d8bef9SDimitry Andric if (SecondHalfSufficient) { 1761*e8d8bef9SDimitry Andric Splatted = I64s[1]; 1762*e8d8bef9SDimitry Andric } else if (CombinedSufficient) { 1763*e8d8bef9SDimitry Andric Splatted = I64s[0] | I64s[1]; 1764*e8d8bef9SDimitry Andric } else { 1765*e8d8bef9SDimitry Andric Splatted = I64s[0]; 1766*e8d8bef9SDimitry Andric } 1767*e8d8bef9SDimitry Andric 1768*e8d8bef9SDimitry Andric Result = DAG.getSplatBuildVector(MVT::v2i64, DL, 1769*e8d8bef9SDimitry Andric DAG.getConstant(Splatted, DL, MVT::i64)); 1770*e8d8bef9SDimitry Andric if (!FirstHalfSufficient && !SecondHalfSufficient && !CombinedSufficient) { 1771*e8d8bef9SDimitry Andric Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, MVT::v2i64, Result, 1772*e8d8bef9SDimitry Andric DAG.getConstant(I64s[1], DL, MVT::i64), 1773*e8d8bef9SDimitry Andric DAG.getConstant(1, DL, MVT::i32)); 1774*e8d8bef9SDimitry Andric } 1775*e8d8bef9SDimitry Andric Result = DAG.getBitcast(VecT, Result); 1776*e8d8bef9SDimitry Andric IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) { 1777*e8d8bef9SDimitry Andric return IsConstant(Lane); 1778*e8d8bef9SDimitry Andric }; 1779*e8d8bef9SDimitry Andric } else { 17808bcb0991SDimitry Andric // Use a splat, but possibly a load_splat 17818bcb0991SDimitry Andric LoadSDNode *SplattedLoad; 17825ffd83dbSDimitry Andric if ((SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) && 17838bcb0991SDimitry Andric SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) { 1784480093f4SDimitry Andric Result = DAG.getMemIntrinsicNode( 1785480093f4SDimitry Andric WebAssemblyISD::LOAD_SPLAT, DL, DAG.getVTList(VecT), 1786480093f4SDimitry Andric {SplattedLoad->getChain(), SplattedLoad->getBasePtr(), 1787480093f4SDimitry Andric SplattedLoad->getOffset()}, 1788480093f4SDimitry Andric SplattedLoad->getMemoryVT(), SplattedLoad->getMemOperand()); 17898bcb0991SDimitry Andric } else { 17908bcb0991SDimitry Andric Result = DAG.getSplatBuildVector(VecT, DL, SplatValue); 17918bcb0991SDimitry Andric } 1792*e8d8bef9SDimitry Andric IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) { 17938bcb0991SDimitry Andric return Lane == SplatValue; 17948bcb0991SDimitry Andric }; 17958bcb0991SDimitry Andric } 17968bcb0991SDimitry Andric 1797*e8d8bef9SDimitry Andric assert(Result); 1798*e8d8bef9SDimitry Andric assert(IsLaneConstructed); 1799*e8d8bef9SDimitry Andric 18008bcb0991SDimitry Andric // Add replace_lane instructions for any unhandled values 18010b57cec5SDimitry Andric for (size_t I = 0; I < Lanes; ++I) { 18020b57cec5SDimitry Andric const SDValue &Lane = Op->getOperand(I); 18038bcb0991SDimitry Andric if (!Lane.isUndef() && !IsLaneConstructed(I, Lane)) 18040b57cec5SDimitry Andric Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane, 18050b57cec5SDimitry Andric DAG.getConstant(I, DL, MVT::i32)); 18060b57cec5SDimitry Andric } 18078bcb0991SDimitry Andric 18080b57cec5SDimitry Andric return Result; 18090b57cec5SDimitry Andric } 18100b57cec5SDimitry Andric 18110b57cec5SDimitry Andric SDValue 18120b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, 18130b57cec5SDimitry Andric SelectionDAG &DAG) const { 18140b57cec5SDimitry Andric SDLoc DL(Op); 18150b57cec5SDimitry Andric ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask(); 18160b57cec5SDimitry Andric MVT VecType = Op.getOperand(0).getSimpleValueType(); 18170b57cec5SDimitry Andric assert(VecType.is128BitVector() && "Unexpected shuffle vector type"); 18180b57cec5SDimitry Andric size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8; 18190b57cec5SDimitry Andric 18200b57cec5SDimitry Andric // Space for two vector args and sixteen mask indices 18210b57cec5SDimitry Andric SDValue Ops[18]; 18220b57cec5SDimitry Andric size_t OpIdx = 0; 18230b57cec5SDimitry Andric Ops[OpIdx++] = Op.getOperand(0); 18240b57cec5SDimitry Andric Ops[OpIdx++] = Op.getOperand(1); 18250b57cec5SDimitry Andric 18260b57cec5SDimitry Andric // Expand mask indices to byte indices and materialize them as operands 18270b57cec5SDimitry Andric for (int M : Mask) { 18280b57cec5SDimitry Andric for (size_t J = 0; J < LaneBytes; ++J) { 18290b57cec5SDimitry Andric // Lower undefs (represented by -1 in mask) to zero 18300b57cec5SDimitry Andric uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J; 18310b57cec5SDimitry Andric Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32); 18320b57cec5SDimitry Andric } 18330b57cec5SDimitry Andric } 18340b57cec5SDimitry Andric 18350b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); 18360b57cec5SDimitry Andric } 18370b57cec5SDimitry Andric 1838480093f4SDimitry Andric SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op, 1839480093f4SDimitry Andric SelectionDAG &DAG) const { 1840480093f4SDimitry Andric SDLoc DL(Op); 1841480093f4SDimitry Andric // The legalizer does not know how to expand the comparison modes of i64x2 1842480093f4SDimitry Andric // vectors because no comparison modes are supported. We could solve this by 1843480093f4SDimitry Andric // expanding all i64x2 SETCC nodes, but that seems to expand f64x2 SETCC nodes 1844480093f4SDimitry Andric // (which return i64x2 results) as well. So instead we manually unroll i64x2 1845480093f4SDimitry Andric // comparisons here. 1846480093f4SDimitry Andric assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64); 1847480093f4SDimitry Andric SmallVector<SDValue, 2> LHS, RHS; 1848480093f4SDimitry Andric DAG.ExtractVectorElements(Op->getOperand(0), LHS); 1849480093f4SDimitry Andric DAG.ExtractVectorElements(Op->getOperand(1), RHS); 1850480093f4SDimitry Andric const SDValue &CC = Op->getOperand(2); 1851480093f4SDimitry Andric auto MakeLane = [&](unsigned I) { 1852480093f4SDimitry Andric return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I], 1853480093f4SDimitry Andric DAG.getConstant(uint64_t(-1), DL, MVT::i64), 1854480093f4SDimitry Andric DAG.getConstant(uint64_t(0), DL, MVT::i64), CC); 1855480093f4SDimitry Andric }; 1856480093f4SDimitry Andric return DAG.getBuildVector(Op->getValueType(0), DL, 1857480093f4SDimitry Andric {MakeLane(0), MakeLane(1)}); 1858480093f4SDimitry Andric } 1859480093f4SDimitry Andric 18600b57cec5SDimitry Andric SDValue 18610b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op, 18620b57cec5SDimitry Andric SelectionDAG &DAG) const { 18630b57cec5SDimitry Andric // Allow constant lane indices, expand variable lane indices 18640b57cec5SDimitry Andric SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode(); 18650b57cec5SDimitry Andric if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef()) 18660b57cec5SDimitry Andric return Op; 18670b57cec5SDimitry Andric else 18680b57cec5SDimitry Andric // Perform default expansion 18690b57cec5SDimitry Andric return SDValue(); 18700b57cec5SDimitry Andric } 18710b57cec5SDimitry Andric 18720b57cec5SDimitry Andric static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) { 18730b57cec5SDimitry Andric EVT LaneT = Op.getSimpleValueType().getVectorElementType(); 18740b57cec5SDimitry Andric // 32-bit and 64-bit unrolled shifts will have proper semantics 18750b57cec5SDimitry Andric if (LaneT.bitsGE(MVT::i32)) 18760b57cec5SDimitry Andric return DAG.UnrollVectorOp(Op.getNode()); 18770b57cec5SDimitry Andric // Otherwise mask the shift value to get proper semantics from 32-bit shift 18780b57cec5SDimitry Andric SDLoc DL(Op); 18795ffd83dbSDimitry Andric size_t NumLanes = Op.getSimpleValueType().getVectorNumElements(); 18805ffd83dbSDimitry Andric SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32); 18815ffd83dbSDimitry Andric unsigned ShiftOpcode = Op.getOpcode(); 18825ffd83dbSDimitry Andric SmallVector<SDValue, 16> ShiftedElements; 18835ffd83dbSDimitry Andric DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32); 18845ffd83dbSDimitry Andric SmallVector<SDValue, 16> ShiftElements; 18855ffd83dbSDimitry Andric DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32); 18865ffd83dbSDimitry Andric SmallVector<SDValue, 16> UnrolledOps; 18875ffd83dbSDimitry Andric for (size_t i = 0; i < NumLanes; ++i) { 18885ffd83dbSDimitry Andric SDValue MaskedShiftValue = 18895ffd83dbSDimitry Andric DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask); 18905ffd83dbSDimitry Andric SDValue ShiftedValue = ShiftedElements[i]; 18915ffd83dbSDimitry Andric if (ShiftOpcode == ISD::SRA) 18925ffd83dbSDimitry Andric ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32, 18935ffd83dbSDimitry Andric ShiftedValue, DAG.getValueType(LaneT)); 18945ffd83dbSDimitry Andric UnrolledOps.push_back( 18955ffd83dbSDimitry Andric DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue)); 18965ffd83dbSDimitry Andric } 18975ffd83dbSDimitry Andric return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps); 18980b57cec5SDimitry Andric } 18990b57cec5SDimitry Andric 19000b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, 19010b57cec5SDimitry Andric SelectionDAG &DAG) const { 19020b57cec5SDimitry Andric SDLoc DL(Op); 19030b57cec5SDimitry Andric 19040b57cec5SDimitry Andric // Only manually lower vector shifts 19050b57cec5SDimitry Andric assert(Op.getSimpleValueType().isVector()); 19060b57cec5SDimitry Andric 19075ffd83dbSDimitry Andric auto ShiftVal = DAG.getSplatValue(Op.getOperand(1)); 19085ffd83dbSDimitry Andric if (!ShiftVal) 19090b57cec5SDimitry Andric return unrollVectorShift(Op, DAG); 19100b57cec5SDimitry Andric 19115ffd83dbSDimitry Andric // Use anyext because none of the high bits can affect the shift 19125ffd83dbSDimitry Andric ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32); 19130b57cec5SDimitry Andric 19140b57cec5SDimitry Andric unsigned Opcode; 19150b57cec5SDimitry Andric switch (Op.getOpcode()) { 19160b57cec5SDimitry Andric case ISD::SHL: 19170b57cec5SDimitry Andric Opcode = WebAssemblyISD::VEC_SHL; 19180b57cec5SDimitry Andric break; 19190b57cec5SDimitry Andric case ISD::SRA: 19200b57cec5SDimitry Andric Opcode = WebAssemblyISD::VEC_SHR_S; 19210b57cec5SDimitry Andric break; 19220b57cec5SDimitry Andric case ISD::SRL: 19230b57cec5SDimitry Andric Opcode = WebAssemblyISD::VEC_SHR_U; 19240b57cec5SDimitry Andric break; 19250b57cec5SDimitry Andric default: 19260b57cec5SDimitry Andric llvm_unreachable("unexpected opcode"); 19270b57cec5SDimitry Andric } 19285ffd83dbSDimitry Andric 19295ffd83dbSDimitry Andric return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal); 19300b57cec5SDimitry Andric } 19310b57cec5SDimitry Andric 19320b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 19335ffd83dbSDimitry Andric // Custom DAG combine hooks 19340b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 19355ffd83dbSDimitry Andric static SDValue 19365ffd83dbSDimitry Andric performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { 19375ffd83dbSDimitry Andric auto &DAG = DCI.DAG; 19385ffd83dbSDimitry Andric auto Shuffle = cast<ShuffleVectorSDNode>(N); 19395ffd83dbSDimitry Andric 19405ffd83dbSDimitry Andric // Hoist vector bitcasts that don't change the number of lanes out of unary 19415ffd83dbSDimitry Andric // shuffles, where they are less likely to get in the way of other combines. 19425ffd83dbSDimitry Andric // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) -> 19435ffd83dbSDimitry Andric // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask)))) 19445ffd83dbSDimitry Andric SDValue Bitcast = N->getOperand(0); 19455ffd83dbSDimitry Andric if (Bitcast.getOpcode() != ISD::BITCAST) 19465ffd83dbSDimitry Andric return SDValue(); 19475ffd83dbSDimitry Andric if (!N->getOperand(1).isUndef()) 19485ffd83dbSDimitry Andric return SDValue(); 19495ffd83dbSDimitry Andric SDValue CastOp = Bitcast.getOperand(0); 19505ffd83dbSDimitry Andric MVT SrcType = CastOp.getSimpleValueType(); 19515ffd83dbSDimitry Andric MVT DstType = Bitcast.getSimpleValueType(); 19525ffd83dbSDimitry Andric if (!SrcType.is128BitVector() || 19535ffd83dbSDimitry Andric SrcType.getVectorNumElements() != DstType.getVectorNumElements()) 19545ffd83dbSDimitry Andric return SDValue(); 19555ffd83dbSDimitry Andric SDValue NewShuffle = DAG.getVectorShuffle( 19565ffd83dbSDimitry Andric SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask()); 19575ffd83dbSDimitry Andric return DAG.getBitcast(DstType, NewShuffle); 19585ffd83dbSDimitry Andric } 19595ffd83dbSDimitry Andric 1960*e8d8bef9SDimitry Andric static SDValue performVectorWidenCombine(SDNode *N, 1961*e8d8bef9SDimitry Andric TargetLowering::DAGCombinerInfo &DCI) { 1962*e8d8bef9SDimitry Andric auto &DAG = DCI.DAG; 1963*e8d8bef9SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND || 1964*e8d8bef9SDimitry Andric N->getOpcode() == ISD::ZERO_EXTEND); 1965*e8d8bef9SDimitry Andric 1966*e8d8bef9SDimitry Andric // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if 1967*e8d8bef9SDimitry Andric // possible before the extract_subvector can be expanded. 1968*e8d8bef9SDimitry Andric auto Extract = N->getOperand(0); 1969*e8d8bef9SDimitry Andric if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) 1970*e8d8bef9SDimitry Andric return SDValue(); 1971*e8d8bef9SDimitry Andric auto Source = Extract.getOperand(0); 1972*e8d8bef9SDimitry Andric auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1)); 1973*e8d8bef9SDimitry Andric if (IndexNode == nullptr) 1974*e8d8bef9SDimitry Andric return SDValue(); 1975*e8d8bef9SDimitry Andric auto Index = IndexNode->getZExtValue(); 1976*e8d8bef9SDimitry Andric 1977*e8d8bef9SDimitry Andric // Only v8i8 and v4i16 extracts can be widened, and only if the extracted 1978*e8d8bef9SDimitry Andric // subvector is the low or high half of its source. 1979*e8d8bef9SDimitry Andric EVT ResVT = N->getValueType(0); 1980*e8d8bef9SDimitry Andric if (ResVT == MVT::v8i16) { 1981*e8d8bef9SDimitry Andric if (Extract.getValueType() != MVT::v8i8 || 1982*e8d8bef9SDimitry Andric Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8)) 1983*e8d8bef9SDimitry Andric return SDValue(); 1984*e8d8bef9SDimitry Andric } else if (ResVT == MVT::v4i32) { 1985*e8d8bef9SDimitry Andric if (Extract.getValueType() != MVT::v4i16 || 1986*e8d8bef9SDimitry Andric Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4)) 1987*e8d8bef9SDimitry Andric return SDValue(); 1988*e8d8bef9SDimitry Andric } else { 1989*e8d8bef9SDimitry Andric return SDValue(); 1990*e8d8bef9SDimitry Andric } 1991*e8d8bef9SDimitry Andric 1992*e8d8bef9SDimitry Andric bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND; 1993*e8d8bef9SDimitry Andric bool IsLow = Index == 0; 1994*e8d8bef9SDimitry Andric 1995*e8d8bef9SDimitry Andric unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::WIDEN_LOW_S 1996*e8d8bef9SDimitry Andric : WebAssemblyISD::WIDEN_HIGH_S) 1997*e8d8bef9SDimitry Andric : (IsLow ? WebAssemblyISD::WIDEN_LOW_U 1998*e8d8bef9SDimitry Andric : WebAssemblyISD::WIDEN_HIGH_U); 1999*e8d8bef9SDimitry Andric 2000*e8d8bef9SDimitry Andric return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2001*e8d8bef9SDimitry Andric } 2002*e8d8bef9SDimitry Andric 20035ffd83dbSDimitry Andric SDValue 20045ffd83dbSDimitry Andric WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, 20055ffd83dbSDimitry Andric DAGCombinerInfo &DCI) const { 20065ffd83dbSDimitry Andric switch (N->getOpcode()) { 20075ffd83dbSDimitry Andric default: 20085ffd83dbSDimitry Andric return SDValue(); 20095ffd83dbSDimitry Andric case ISD::VECTOR_SHUFFLE: 20105ffd83dbSDimitry Andric return performVECTOR_SHUFFLECombine(N, DCI); 2011*e8d8bef9SDimitry Andric case ISD::SIGN_EXTEND: 2012*e8d8bef9SDimitry Andric case ISD::ZERO_EXTEND: 2013*e8d8bef9SDimitry Andric return performVectorWidenCombine(N, DCI); 20145ffd83dbSDimitry Andric } 20155ffd83dbSDimitry Andric } 2016