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" 16*fe6060f1SDimitry Andric #include "Utils/WebAssemblyTypeUtilities.h" 17*fe6060f1SDimitry Andric #include "Utils/WebAssemblyUtilities.h" 180b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 190b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 200b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.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" 27*fe6060f1SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h" 290b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 300b57cec5SDimitry Andric #include "llvm/IR/DiagnosticPrinter.h" 310b57cec5SDimitry Andric #include "llvm/IR/Function.h" 320b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 33480093f4SDimitry Andric #include "llvm/IR/IntrinsicsWebAssembly.h" 340b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 350b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 36e8d8bef9SDimitry Andric #include "llvm/Support/MathExtras.h" 370b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 380b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 390b57cec5SDimitry Andric using namespace llvm; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-lower" 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric WebAssemblyTargetLowering::WebAssemblyTargetLowering( 440b57cec5SDimitry Andric const TargetMachine &TM, const WebAssemblySubtarget &STI) 450b57cec5SDimitry Andric : TargetLowering(TM), Subtarget(&STI) { 460b57cec5SDimitry Andric auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric // Booleans always contain 0 or 1. 490b57cec5SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 500b57cec5SDimitry Andric // Except in SIMD vectors 510b57cec5SDimitry Andric setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); 520b57cec5SDimitry Andric // We don't know the microarchitecture here, so just reduce register pressure. 530b57cec5SDimitry Andric setSchedulingPreference(Sched::RegPressure); 540b57cec5SDimitry Andric // Tell ISel that we have a stack pointer. 550b57cec5SDimitry Andric setStackPointerRegisterToSaveRestore( 560b57cec5SDimitry Andric Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); 570b57cec5SDimitry Andric // Set up the register classes. 580b57cec5SDimitry Andric addRegisterClass(MVT::i32, &WebAssembly::I32RegClass); 590b57cec5SDimitry Andric addRegisterClass(MVT::i64, &WebAssembly::I64RegClass); 600b57cec5SDimitry Andric addRegisterClass(MVT::f32, &WebAssembly::F32RegClass); 610b57cec5SDimitry Andric addRegisterClass(MVT::f64, &WebAssembly::F64RegClass); 620b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) { 630b57cec5SDimitry Andric addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass); 640b57cec5SDimitry Andric addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass); 650b57cec5SDimitry Andric addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass); 660b57cec5SDimitry Andric addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass); 670b57cec5SDimitry Andric addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); 680b57cec5SDimitry Andric addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); 690b57cec5SDimitry Andric } 70*fe6060f1SDimitry Andric if (Subtarget->hasReferenceTypes()) { 71*fe6060f1SDimitry Andric addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass); 72*fe6060f1SDimitry Andric addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass); 73*fe6060f1SDimitry Andric } 740b57cec5SDimitry Andric // Compute derived properties from the register classes. 750b57cec5SDimitry Andric computeRegisterProperties(Subtarget->getRegisterInfo()); 760b57cec5SDimitry Andric 77*fe6060f1SDimitry Andric // Transform loads and stores to pointers in address space 1 to loads and 78*fe6060f1SDimitry Andric // stores to WebAssembly global variables, outside linear memory. 79*fe6060f1SDimitry Andric for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) { 80*fe6060f1SDimitry Andric setOperationAction(ISD::LOAD, T, Custom); 81*fe6060f1SDimitry Andric setOperationAction(ISD::STORE, T, Custom); 82*fe6060f1SDimitry Andric } 83*fe6060f1SDimitry Andric if (Subtarget->hasSIMD128()) { 84*fe6060f1SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 85*fe6060f1SDimitry Andric MVT::v2f64}) { 86*fe6060f1SDimitry Andric setOperationAction(ISD::LOAD, T, Custom); 87*fe6060f1SDimitry Andric setOperationAction(ISD::STORE, T, Custom); 88*fe6060f1SDimitry Andric } 89*fe6060f1SDimitry Andric } 90*fe6060f1SDimitry Andric if (Subtarget->hasReferenceTypes()) { 91*fe6060f1SDimitry Andric for (auto T : {MVT::externref, MVT::funcref}) { 92*fe6060f1SDimitry Andric setOperationAction(ISD::LOAD, T, Custom); 93*fe6060f1SDimitry Andric setOperationAction(ISD::STORE, T, Custom); 94*fe6060f1SDimitry Andric } 95*fe6060f1SDimitry Andric } 96*fe6060f1SDimitry Andric 970b57cec5SDimitry Andric setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); 98e8d8bef9SDimitry Andric setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom); 990b57cec5SDimitry Andric setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); 1000b57cec5SDimitry Andric setOperationAction(ISD::JumpTable, MVTPtr, Custom); 1010b57cec5SDimitry Andric setOperationAction(ISD::BlockAddress, MVTPtr, Custom); 1020b57cec5SDimitry Andric setOperationAction(ISD::BRIND, MVT::Other, Custom); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // Take the default expansion for va_arg, va_copy, and va_end. There is no 1050b57cec5SDimitry Andric // default action for va_start, so we do that custom. 1060b57cec5SDimitry Andric setOperationAction(ISD::VASTART, MVT::Other, Custom); 1070b57cec5SDimitry Andric setOperationAction(ISD::VAARG, MVT::Other, Expand); 1080b57cec5SDimitry Andric setOperationAction(ISD::VACOPY, MVT::Other, Expand); 1090b57cec5SDimitry Andric setOperationAction(ISD::VAEND, MVT::Other, Expand); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) { 1120b57cec5SDimitry Andric // Don't expand the floating-point types to constant pools. 1130b57cec5SDimitry Andric setOperationAction(ISD::ConstantFP, T, Legal); 1140b57cec5SDimitry Andric // Expand floating-point comparisons. 1150b57cec5SDimitry Andric for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, 1160b57cec5SDimitry Andric ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) 1170b57cec5SDimitry Andric setCondCodeAction(CC, T, Expand); 1180b57cec5SDimitry Andric // Expand floating-point library function operators. 1190b57cec5SDimitry Andric for (auto Op : 1200b57cec5SDimitry Andric {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA}) 1210b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 1220b57cec5SDimitry Andric // Note supported floating-point library function operators that otherwise 1230b57cec5SDimitry Andric // default to expand. 1240b57cec5SDimitry Andric for (auto Op : 1250b57cec5SDimitry Andric {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT}) 1260b57cec5SDimitry Andric setOperationAction(Op, T, Legal); 1270b57cec5SDimitry Andric // Support minimum and maximum, which otherwise default to expand. 1280b57cec5SDimitry Andric setOperationAction(ISD::FMINIMUM, T, Legal); 1290b57cec5SDimitry Andric setOperationAction(ISD::FMAXIMUM, T, Legal); 1300b57cec5SDimitry Andric // WebAssembly currently has no builtin f16 support. 1310b57cec5SDimitry Andric setOperationAction(ISD::FP16_TO_FP, T, Expand); 1320b57cec5SDimitry Andric setOperationAction(ISD::FP_TO_FP16, T, Expand); 1330b57cec5SDimitry Andric setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand); 1340b57cec5SDimitry Andric setTruncStoreAction(T, MVT::f16, Expand); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric // Expand unavailable integer operations. 1380b57cec5SDimitry Andric for (auto Op : 1390b57cec5SDimitry Andric {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU, 1400b57cec5SDimitry Andric ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS, 1410b57cec5SDimitry Andric ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) { 1420b57cec5SDimitry Andric for (auto T : {MVT::i32, MVT::i64}) 1430b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 1440b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) 1455ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 1460b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 149*fe6060f1SDimitry Andric if (Subtarget->hasNontrappingFPToInt()) 150*fe6060f1SDimitry Andric for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) 151*fe6060f1SDimitry Andric for (auto T : {MVT::i32, MVT::i64}) 152*fe6060f1SDimitry Andric setOperationAction(Op, T, Custom); 153*fe6060f1SDimitry Andric 1540b57cec5SDimitry Andric // SIMD-specific configuration 1550b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) { 1565ffd83dbSDimitry Andric // Hoist bitcasts out of shuffles 1575ffd83dbSDimitry Andric setTargetDAGCombine(ISD::VECTOR_SHUFFLE); 1585ffd83dbSDimitry Andric 159e8d8bef9SDimitry Andric // Combine extends of extract_subvectors into widening ops 160e8d8bef9SDimitry Andric setTargetDAGCombine(ISD::SIGN_EXTEND); 161e8d8bef9SDimitry Andric setTargetDAGCombine(ISD::ZERO_EXTEND); 162e8d8bef9SDimitry Andric 163*fe6060f1SDimitry Andric // Combine int_to_fp or fp_extend of extract_vectors and vice versa into 164*fe6060f1SDimitry Andric // conversions ops 165*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::SINT_TO_FP); 166*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::UINT_TO_FP); 167*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::FP_EXTEND); 168*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::EXTRACT_SUBVECTOR); 169*fe6060f1SDimitry Andric 170*fe6060f1SDimitry Andric // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa 171*fe6060f1SDimitry Andric // into conversion ops 172*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::FP_TO_SINT_SAT); 173*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::FP_TO_UINT_SAT); 174*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::FP_ROUND); 175*fe6060f1SDimitry Andric setTargetDAGCombine(ISD::CONCAT_VECTORS); 176*fe6060f1SDimitry Andric 1770b57cec5SDimitry Andric // Support saturating add for i8x16 and i16x8 1780b57cec5SDimitry Andric for (auto Op : {ISD::SADDSAT, ISD::UADDSAT}) 1790b57cec5SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16}) 1800b57cec5SDimitry Andric setOperationAction(Op, T, Legal); 1810b57cec5SDimitry Andric 1825ffd83dbSDimitry Andric // Support integer abs 183*fe6060f1SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 1845ffd83dbSDimitry Andric setOperationAction(ISD::ABS, T, Legal); 1855ffd83dbSDimitry Andric 1860b57cec5SDimitry Andric // Custom lower BUILD_VECTORs to minimize number of replace_lanes 1875ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 1885ffd83dbSDimitry Andric MVT::v2f64}) 1890b57cec5SDimitry Andric setOperationAction(ISD::BUILD_VECTOR, T, Custom); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric // We have custom shuffle lowering to expose the shuffle mask 1925ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 1935ffd83dbSDimitry Andric MVT::v2f64}) 1940b57cec5SDimitry Andric setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom); 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric // Custom lowering since wasm shifts must have a scalar shift amount 1975ffd83dbSDimitry Andric for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) 1985ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 1990b57cec5SDimitry Andric setOperationAction(Op, T, Custom); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric // Custom lower lane accesses to expand out variable indices 2025ffd83dbSDimitry Andric for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT}) 2035ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 2045ffd83dbSDimitry Andric MVT::v2f64}) 2050b57cec5SDimitry Andric setOperationAction(Op, T, Custom); 2060b57cec5SDimitry Andric 2075ffd83dbSDimitry Andric // There is no i8x16.mul instruction 2085ffd83dbSDimitry Andric setOperationAction(ISD::MUL, MVT::v16i8, Expand); 2090b57cec5SDimitry Andric 210e8d8bef9SDimitry Andric // There is no vector conditional select instruction 2115ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 2125ffd83dbSDimitry Andric MVT::v2f64}) 213e8d8bef9SDimitry Andric setOperationAction(ISD::SELECT_CC, T, Expand); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric // Expand integer operations supported for scalars but not SIMD 2160b57cec5SDimitry Andric for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP, ISD::SDIV, ISD::UDIV, 2175ffd83dbSDimitry Andric ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR}) 2185ffd83dbSDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 2190b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 2200b57cec5SDimitry Andric 221480093f4SDimitry Andric // But we do have integer min and max operations 222480093f4SDimitry Andric for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) 223480093f4SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) 224480093f4SDimitry Andric setOperationAction(Op, T, Legal); 225480093f4SDimitry Andric 226*fe6060f1SDimitry Andric // And we have popcnt for i8x16 227*fe6060f1SDimitry Andric setOperationAction(ISD::CTPOP, MVT::v16i8, Legal); 228*fe6060f1SDimitry Andric 2290b57cec5SDimitry Andric // Expand float operations supported for scalars but not SIMD 230*fe6060f1SDimitry Andric for (auto Op : {ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10, 2315ffd83dbSDimitry Andric ISD::FEXP, ISD::FEXP2, ISD::FRINT}) 2325ffd83dbSDimitry Andric for (auto T : {MVT::v4f32, MVT::v2f64}) 2335ffd83dbSDimitry Andric setOperationAction(Op, T, Expand); 2340b57cec5SDimitry Andric 235*fe6060f1SDimitry Andric // Unsigned comparison operations are unavailable for i64x2 vectors. 236*fe6060f1SDimitry Andric for (auto CC : {ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE}) 237*fe6060f1SDimitry Andric setCondCodeAction(CC, MVT::v2i64, Custom); 238480093f4SDimitry Andric 2395ffd83dbSDimitry Andric // 64x2 conversions are not in the spec 2405ffd83dbSDimitry Andric for (auto Op : 2415ffd83dbSDimitry Andric {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT}) 2425ffd83dbSDimitry Andric for (auto T : {MVT::v2i64, MVT::v2f64}) 2435ffd83dbSDimitry Andric setOperationAction(Op, T, Expand); 244*fe6060f1SDimitry Andric 245*fe6060f1SDimitry Andric // But saturating fp_to_int converstions are 246*fe6060f1SDimitry Andric for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) 247*fe6060f1SDimitry Andric setOperationAction(Op, MVT::v4i32, Custom); 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric // As a special case, these operators use the type to mean the type to 2510b57cec5SDimitry Andric // sign-extend from. 2520b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 2530b57cec5SDimitry Andric if (!Subtarget->hasSignExt()) { 2540b57cec5SDimitry Andric // Sign extends are legal only when extending a vector extract 2550b57cec5SDimitry Andric auto Action = Subtarget->hasSIMD128() ? Custom : Expand; 2560b57cec5SDimitry Andric for (auto T : {MVT::i8, MVT::i16, MVT::i32}) 2570b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action); 2580b57cec5SDimitry Andric } 2598bcb0991SDimitry Andric for (auto T : MVT::integer_fixedlen_vector_valuetypes()) 2600b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric // Dynamic stack allocation: use the default expansion. 2630b57cec5SDimitry Andric setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 2640b57cec5SDimitry Andric setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 2650b57cec5SDimitry Andric setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric setOperationAction(ISD::FrameIndex, MVT::i32, Custom); 2685ffd83dbSDimitry Andric setOperationAction(ISD::FrameIndex, MVT::i64, Custom); 2690b57cec5SDimitry Andric setOperationAction(ISD::CopyToReg, MVT::Other, Custom); 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric // Expand these forms; we pattern-match the forms that we can handle in isel. 2720b57cec5SDimitry Andric for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) 2730b57cec5SDimitry Andric for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) 2740b57cec5SDimitry Andric setOperationAction(Op, T, Expand); 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric // We have custom switch handling. 2770b57cec5SDimitry Andric setOperationAction(ISD::BR_JT, MVT::Other, Custom); 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric // WebAssembly doesn't have: 2800b57cec5SDimitry Andric // - Floating-point extending loads. 2810b57cec5SDimitry Andric // - Floating-point truncating stores. 2820b57cec5SDimitry Andric // - i1 extending loads. 2838bcb0991SDimitry Andric // - truncating SIMD stores and most extending loads 2840b57cec5SDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 2850b57cec5SDimitry Andric setTruncStoreAction(MVT::f64, MVT::f32, Expand); 2860b57cec5SDimitry Andric for (auto T : MVT::integer_valuetypes()) 2870b57cec5SDimitry Andric for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 2880b57cec5SDimitry Andric setLoadExtAction(Ext, T, MVT::i1, Promote); 2890b57cec5SDimitry Andric if (Subtarget->hasSIMD128()) { 2900b57cec5SDimitry Andric for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, 2910b57cec5SDimitry Andric MVT::v2f64}) { 2928bcb0991SDimitry Andric for (auto MemT : MVT::fixedlen_vector_valuetypes()) { 2930b57cec5SDimitry Andric if (MVT(T) != MemT) { 2940b57cec5SDimitry Andric setTruncStoreAction(T, MemT, Expand); 2950b57cec5SDimitry Andric for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 2960b57cec5SDimitry Andric setLoadExtAction(Ext, T, MemT, Expand); 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } 3008bcb0991SDimitry Andric // But some vector extending loads are legal 3018bcb0991SDimitry Andric for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) { 3028bcb0991SDimitry Andric setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal); 3038bcb0991SDimitry Andric setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal); 3048bcb0991SDimitry Andric setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal); 3058bcb0991SDimitry Andric } 306e8d8bef9SDimitry Andric // And some truncating stores are legal as well 307e8d8bef9SDimitry Andric setTruncStoreAction(MVT::v8i16, MVT::v8i8, Legal); 308e8d8bef9SDimitry Andric setTruncStoreAction(MVT::v4i32, MVT::v4i16, Legal); 3098bcb0991SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric // Don't do anything clever with build_pairs 3120b57cec5SDimitry Andric setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand); 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric // Trap lowers to wasm unreachable 3150b57cec5SDimitry Andric setOperationAction(ISD::TRAP, MVT::Other, Legal); 3165ffd83dbSDimitry Andric setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Exception handling intrinsics 3190b57cec5SDimitry Andric setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); 320e8d8bef9SDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 3210b57cec5SDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric setMaxAtomicSizeInBitsSupported(64); 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is 3260b57cec5SDimitry Andric // consistent with the f64 and f128 names. 3270b57cec5SDimitry Andric setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2"); 3280b57cec5SDimitry Andric setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2"); 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric // Define the emscripten name for return address helper. 331e8d8bef9SDimitry Andric // TODO: when implementing other Wasm backends, make this generic or only do 3320b57cec5SDimitry Andric // this on emscripten depending on what they end up doing. 3330b57cec5SDimitry Andric setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address"); 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric // Always convert switches to br_tables unless there is only one case, which 3360b57cec5SDimitry Andric // is equivalent to a simple branch. This reduces code size for wasm, and we 3370b57cec5SDimitry Andric // defer possible jump table optimizations to the VM. 3380b57cec5SDimitry Andric setMinimumJumpTableEntries(2); 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric TargetLowering::AtomicExpansionKind 3420b57cec5SDimitry Andric WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { 3430b57cec5SDimitry Andric // We have wasm instructions for these 3440b57cec5SDimitry Andric switch (AI->getOperation()) { 3450b57cec5SDimitry Andric case AtomicRMWInst::Add: 3460b57cec5SDimitry Andric case AtomicRMWInst::Sub: 3470b57cec5SDimitry Andric case AtomicRMWInst::And: 3480b57cec5SDimitry Andric case AtomicRMWInst::Or: 3490b57cec5SDimitry Andric case AtomicRMWInst::Xor: 3500b57cec5SDimitry Andric case AtomicRMWInst::Xchg: 3510b57cec5SDimitry Andric return AtomicExpansionKind::None; 3520b57cec5SDimitry Andric default: 3530b57cec5SDimitry Andric break; 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric return AtomicExpansionKind::CmpXChg; 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric 358*fe6060f1SDimitry Andric bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const { 359*fe6060f1SDimitry Andric // Implementation copied from X86TargetLowering. 360*fe6060f1SDimitry Andric unsigned Opc = VecOp.getOpcode(); 361*fe6060f1SDimitry Andric 362*fe6060f1SDimitry Andric // Assume target opcodes can't be scalarized. 363*fe6060f1SDimitry Andric // TODO - do we have any exceptions? 364*fe6060f1SDimitry Andric if (Opc >= ISD::BUILTIN_OP_END) 365*fe6060f1SDimitry Andric return false; 366*fe6060f1SDimitry Andric 367*fe6060f1SDimitry Andric // If the vector op is not supported, try to convert to scalar. 368*fe6060f1SDimitry Andric EVT VecVT = VecOp.getValueType(); 369*fe6060f1SDimitry Andric if (!isOperationLegalOrCustomOrPromote(Opc, VecVT)) 370*fe6060f1SDimitry Andric return true; 371*fe6060f1SDimitry Andric 372*fe6060f1SDimitry Andric // If the vector op is supported, but the scalar op is not, the transform may 373*fe6060f1SDimitry Andric // not be worthwhile. 374*fe6060f1SDimitry Andric EVT ScalarVT = VecVT.getScalarType(); 375*fe6060f1SDimitry Andric return isOperationLegalOrCustomOrPromote(Opc, ScalarVT); 376*fe6060f1SDimitry Andric } 377*fe6060f1SDimitry Andric 3780b57cec5SDimitry Andric FastISel *WebAssemblyTargetLowering::createFastISel( 3790b57cec5SDimitry Andric FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const { 3800b57cec5SDimitry Andric return WebAssembly::createFastISel(FuncInfo, LibInfo); 3810b57cec5SDimitry Andric } 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, 3840b57cec5SDimitry Andric EVT VT) const { 3850b57cec5SDimitry Andric unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1); 3860b57cec5SDimitry Andric if (BitWidth > 1 && BitWidth < 8) 3870b57cec5SDimitry Andric BitWidth = 8; 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric if (BitWidth > 64) { 3900b57cec5SDimitry Andric // The shift will be lowered to a libcall, and compiler-rt libcalls expect 3910b57cec5SDimitry Andric // the count to be an i32. 3920b57cec5SDimitry Andric BitWidth = 32; 3930b57cec5SDimitry Andric assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) && 3940b57cec5SDimitry Andric "32-bit shift counts ought to be enough for anyone"); 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric MVT Result = MVT::getIntegerVT(BitWidth); 3980b57cec5SDimitry Andric assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE && 3990b57cec5SDimitry Andric "Unable to represent scalar shift amount type"); 4000b57cec5SDimitry Andric return Result; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric // Lower an fp-to-int conversion operator from the LLVM opcode, which has an 4040b57cec5SDimitry Andric // undefined result on invalid/overflow, to the WebAssembly opcode, which 4050b57cec5SDimitry Andric // traps on invalid/overflow. 4060b57cec5SDimitry Andric static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL, 4070b57cec5SDimitry Andric MachineBasicBlock *BB, 4080b57cec5SDimitry Andric const TargetInstrInfo &TII, 4090b57cec5SDimitry Andric bool IsUnsigned, bool Int64, 4100b57cec5SDimitry Andric bool Float64, unsigned LoweredOpcode) { 4110b57cec5SDimitry Andric MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); 4120b57cec5SDimitry Andric 4138bcb0991SDimitry Andric Register OutReg = MI.getOperand(0).getReg(); 4148bcb0991SDimitry Andric Register InReg = MI.getOperand(1).getReg(); 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32; 4170b57cec5SDimitry Andric unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32; 4180b57cec5SDimitry Andric unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32; 4190b57cec5SDimitry Andric unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32; 4200b57cec5SDimitry Andric unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; 4210b57cec5SDimitry Andric unsigned Eqz = WebAssembly::EQZ_I32; 4220b57cec5SDimitry Andric unsigned And = WebAssembly::AND_I32; 4230b57cec5SDimitry Andric int64_t Limit = Int64 ? INT64_MIN : INT32_MIN; 4240b57cec5SDimitry Andric int64_t Substitute = IsUnsigned ? 0 : Limit; 4250b57cec5SDimitry Andric double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit; 4260b57cec5SDimitry Andric auto &Context = BB->getParent()->getFunction().getContext(); 4270b57cec5SDimitry Andric Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context); 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric const BasicBlock *LLVMBB = BB->getBasicBlock(); 4300b57cec5SDimitry Andric MachineFunction *F = BB->getParent(); 4310b57cec5SDimitry Andric MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB); 4320b57cec5SDimitry Andric MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB); 4330b57cec5SDimitry Andric MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB); 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric MachineFunction::iterator It = ++BB->getIterator(); 4360b57cec5SDimitry Andric F->insert(It, FalseMBB); 4370b57cec5SDimitry Andric F->insert(It, TrueMBB); 4380b57cec5SDimitry Andric F->insert(It, DoneMBB); 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric // Transfer the remainder of BB and its successor edges to DoneMBB. 4410b57cec5SDimitry Andric DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end()); 4420b57cec5SDimitry Andric DoneMBB->transferSuccessorsAndUpdatePHIs(BB); 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric BB->addSuccessor(TrueMBB); 4450b57cec5SDimitry Andric BB->addSuccessor(FalseMBB); 4460b57cec5SDimitry Andric TrueMBB->addSuccessor(DoneMBB); 4470b57cec5SDimitry Andric FalseMBB->addSuccessor(DoneMBB); 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg; 4500b57cec5SDimitry Andric Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 4510b57cec5SDimitry Andric Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 4520b57cec5SDimitry Andric CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 4530b57cec5SDimitry Andric EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 4540b57cec5SDimitry Andric FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 4550b57cec5SDimitry Andric TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric MI.eraseFromParent(); 4580b57cec5SDimitry Andric // For signed numbers, we can do a single comparison to determine whether 4590b57cec5SDimitry Andric // fabs(x) is within range. 4600b57cec5SDimitry Andric if (IsUnsigned) { 4610b57cec5SDimitry Andric Tmp0 = InReg; 4620b57cec5SDimitry Andric } else { 4630b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg); 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(FConst), Tmp1) 4660b57cec5SDimitry Andric .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal))); 4670b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1); 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric // For unsigned numbers, we have to do a separate comparison with zero. 4700b57cec5SDimitry Andric if (IsUnsigned) { 4710b57cec5SDimitry Andric Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 4728bcb0991SDimitry Andric Register SecondCmpReg = 4730b57cec5SDimitry Andric MRI.createVirtualRegister(&WebAssembly::I32RegClass); 4748bcb0991SDimitry Andric Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 4750b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(FConst), Tmp1) 4760b57cec5SDimitry Andric .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0))); 4770b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1); 4780b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg); 4790b57cec5SDimitry Andric CmpReg = AndReg; 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg); 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric // Create the CFG diamond to select between doing the conversion or using 4850b57cec5SDimitry Andric // the substitute value. 4860b57cec5SDimitry Andric BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg); 4870b57cec5SDimitry Andric BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg); 4880b57cec5SDimitry Andric BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB); 4890b57cec5SDimitry Andric BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute); 4900b57cec5SDimitry Andric BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg) 4910b57cec5SDimitry Andric .addReg(FalseReg) 4920b57cec5SDimitry Andric .addMBB(FalseMBB) 4930b57cec5SDimitry Andric .addReg(TrueReg) 4940b57cec5SDimitry Andric .addMBB(TrueMBB); 4950b57cec5SDimitry Andric 4960b57cec5SDimitry Andric return DoneMBB; 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 499*fe6060f1SDimitry Andric static MachineBasicBlock * 500*fe6060f1SDimitry Andric LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, 501*fe6060f1SDimitry Andric const WebAssemblySubtarget *Subtarget, 5025ffd83dbSDimitry Andric const TargetInstrInfo &TII) { 5035ffd83dbSDimitry Andric MachineInstr &CallParams = *CallResults.getPrevNode(); 5045ffd83dbSDimitry Andric assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS); 5055ffd83dbSDimitry Andric assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS || 5065ffd83dbSDimitry Andric CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS); 5075ffd83dbSDimitry Andric 5085ffd83dbSDimitry Andric bool IsIndirect = CallParams.getOperand(0).isReg(); 5095ffd83dbSDimitry Andric bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS; 5105ffd83dbSDimitry Andric 511*fe6060f1SDimitry Andric bool IsFuncrefCall = false; 512*fe6060f1SDimitry Andric if (IsIndirect) { 513*fe6060f1SDimitry Andric Register Reg = CallParams.getOperand(0).getReg(); 514*fe6060f1SDimitry Andric const MachineFunction *MF = BB->getParent(); 515*fe6060f1SDimitry Andric const MachineRegisterInfo &MRI = MF->getRegInfo(); 516*fe6060f1SDimitry Andric const TargetRegisterClass *TRC = MRI.getRegClass(Reg); 517*fe6060f1SDimitry Andric IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass); 518*fe6060f1SDimitry Andric assert(!IsFuncrefCall || Subtarget->hasReferenceTypes()); 519*fe6060f1SDimitry Andric } 520*fe6060f1SDimitry Andric 5215ffd83dbSDimitry Andric unsigned CallOp; 5225ffd83dbSDimitry Andric if (IsIndirect && IsRetCall) { 5235ffd83dbSDimitry Andric CallOp = WebAssembly::RET_CALL_INDIRECT; 5245ffd83dbSDimitry Andric } else if (IsIndirect) { 5255ffd83dbSDimitry Andric CallOp = WebAssembly::CALL_INDIRECT; 5265ffd83dbSDimitry Andric } else if (IsRetCall) { 5275ffd83dbSDimitry Andric CallOp = WebAssembly::RET_CALL; 5285ffd83dbSDimitry Andric } else { 5295ffd83dbSDimitry Andric CallOp = WebAssembly::CALL; 5305ffd83dbSDimitry Andric } 5315ffd83dbSDimitry Andric 5325ffd83dbSDimitry Andric MachineFunction &MF = *BB->getParent(); 5335ffd83dbSDimitry Andric const MCInstrDesc &MCID = TII.get(CallOp); 5345ffd83dbSDimitry Andric MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL)); 5355ffd83dbSDimitry Andric 536e8d8bef9SDimitry Andric // See if we must truncate the function pointer. 537e8d8bef9SDimitry Andric // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers 538e8d8bef9SDimitry Andric // as 64-bit for uniformity with other pointer types. 539*fe6060f1SDimitry Andric // See also: WebAssemblyFastISel::selectCall 540e8d8bef9SDimitry Andric if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) { 541e8d8bef9SDimitry Andric Register Reg32 = 542e8d8bef9SDimitry Andric MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); 543e8d8bef9SDimitry Andric auto &FnPtr = CallParams.getOperand(0); 544e8d8bef9SDimitry Andric BuildMI(*BB, CallResults.getIterator(), DL, 545e8d8bef9SDimitry Andric TII.get(WebAssembly::I32_WRAP_I64), Reg32) 546e8d8bef9SDimitry Andric .addReg(FnPtr.getReg()); 547e8d8bef9SDimitry Andric FnPtr.setReg(Reg32); 548e8d8bef9SDimitry Andric } 549e8d8bef9SDimitry Andric 5505ffd83dbSDimitry Andric // Move the function pointer to the end of the arguments for indirect calls 5515ffd83dbSDimitry Andric if (IsIndirect) { 5525ffd83dbSDimitry Andric auto FnPtr = CallParams.getOperand(0); 5535ffd83dbSDimitry Andric CallParams.RemoveOperand(0); 5545ffd83dbSDimitry Andric CallParams.addOperand(FnPtr); 5555ffd83dbSDimitry Andric } 5565ffd83dbSDimitry Andric 5575ffd83dbSDimitry Andric for (auto Def : CallResults.defs()) 5585ffd83dbSDimitry Andric MIB.add(Def); 5595ffd83dbSDimitry Andric 5605ffd83dbSDimitry Andric if (IsIndirect) { 561*fe6060f1SDimitry Andric // Placeholder for the type index. 5625ffd83dbSDimitry Andric MIB.addImm(0); 563*fe6060f1SDimitry Andric // The table into which this call_indirect indexes. 564*fe6060f1SDimitry Andric MCSymbolWasm *Table = IsFuncrefCall 565*fe6060f1SDimitry Andric ? WebAssembly::getOrCreateFuncrefCallTableSymbol( 566*fe6060f1SDimitry Andric MF.getContext(), Subtarget) 567*fe6060f1SDimitry Andric : WebAssembly::getOrCreateFunctionTableSymbol( 568*fe6060f1SDimitry Andric MF.getContext(), Subtarget); 569*fe6060f1SDimitry Andric if (Subtarget->hasReferenceTypes()) { 570*fe6060f1SDimitry Andric MIB.addSym(Table); 571*fe6060f1SDimitry Andric } else { 572*fe6060f1SDimitry Andric // For the MVP there is at most one table whose number is 0, but we can't 573*fe6060f1SDimitry Andric // write a table symbol or issue relocations. Instead we just ensure the 574*fe6060f1SDimitry Andric // table is live and write a zero. 575*fe6060f1SDimitry Andric Table->setNoStrip(); 5765ffd83dbSDimitry Andric MIB.addImm(0); 577*fe6060f1SDimitry Andric } 5785ffd83dbSDimitry Andric } 5795ffd83dbSDimitry Andric 5805ffd83dbSDimitry Andric for (auto Use : CallParams.uses()) 5815ffd83dbSDimitry Andric MIB.add(Use); 5825ffd83dbSDimitry Andric 5835ffd83dbSDimitry Andric BB->insert(CallResults.getIterator(), MIB); 5845ffd83dbSDimitry Andric CallParams.eraseFromParent(); 5855ffd83dbSDimitry Andric CallResults.eraseFromParent(); 5865ffd83dbSDimitry Andric 587*fe6060f1SDimitry Andric // If this is a funcref call, to avoid hidden GC roots, we need to clear the 588*fe6060f1SDimitry Andric // table slot with ref.null upon call_indirect return. 589*fe6060f1SDimitry Andric // 590*fe6060f1SDimitry Andric // This generates the following code, which comes right after a call_indirect 591*fe6060f1SDimitry Andric // of a funcref: 592*fe6060f1SDimitry Andric // 593*fe6060f1SDimitry Andric // i32.const 0 594*fe6060f1SDimitry Andric // ref.null func 595*fe6060f1SDimitry Andric // table.set __funcref_call_table 596*fe6060f1SDimitry Andric if (IsIndirect && IsFuncrefCall) { 597*fe6060f1SDimitry Andric MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( 598*fe6060f1SDimitry Andric MF.getContext(), Subtarget); 599*fe6060f1SDimitry Andric Register RegZero = 600*fe6060f1SDimitry Andric MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); 601*fe6060f1SDimitry Andric MachineInstr *Const0 = 602*fe6060f1SDimitry Andric BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0); 603*fe6060f1SDimitry Andric BB->insertAfter(MIB.getInstr()->getIterator(), Const0); 604*fe6060f1SDimitry Andric 605*fe6060f1SDimitry Andric Register RegFuncref = 606*fe6060f1SDimitry Andric MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass); 607*fe6060f1SDimitry Andric MachineInstr *RefNull = 608*fe6060f1SDimitry Andric BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref) 609*fe6060f1SDimitry Andric .addImm(static_cast<int32_t>(WebAssembly::HeapType::Funcref)); 610*fe6060f1SDimitry Andric BB->insertAfter(Const0->getIterator(), RefNull); 611*fe6060f1SDimitry Andric 612*fe6060f1SDimitry Andric MachineInstr *TableSet = 613*fe6060f1SDimitry Andric BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF)) 614*fe6060f1SDimitry Andric .addSym(Table) 615*fe6060f1SDimitry Andric .addReg(RegZero) 616*fe6060f1SDimitry Andric .addReg(RegFuncref); 617*fe6060f1SDimitry Andric BB->insertAfter(RefNull->getIterator(), TableSet); 618*fe6060f1SDimitry Andric } 619*fe6060f1SDimitry Andric 6205ffd83dbSDimitry Andric return BB; 6215ffd83dbSDimitry Andric } 6225ffd83dbSDimitry Andric 6230b57cec5SDimitry Andric MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter( 6240b57cec5SDimitry Andric MachineInstr &MI, MachineBasicBlock *BB) const { 6250b57cec5SDimitry Andric const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 6260b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric switch (MI.getOpcode()) { 6290b57cec5SDimitry Andric default: 6300b57cec5SDimitry Andric llvm_unreachable("Unexpected instr type to insert"); 6310b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I32_F32: 6320b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, false, false, 6330b57cec5SDimitry Andric WebAssembly::I32_TRUNC_S_F32); 6340b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I32_F32: 6350b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, false, false, 6360b57cec5SDimitry Andric WebAssembly::I32_TRUNC_U_F32); 6370b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I64_F32: 6380b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, true, false, 6390b57cec5SDimitry Andric WebAssembly::I64_TRUNC_S_F32); 6400b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I64_F32: 6410b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, true, false, 6420b57cec5SDimitry Andric WebAssembly::I64_TRUNC_U_F32); 6430b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I32_F64: 6440b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, false, true, 6450b57cec5SDimitry Andric WebAssembly::I32_TRUNC_S_F64); 6460b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I32_F64: 6470b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, false, true, 6480b57cec5SDimitry Andric WebAssembly::I32_TRUNC_U_F64); 6490b57cec5SDimitry Andric case WebAssembly::FP_TO_SINT_I64_F64: 6500b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, false, true, true, 6510b57cec5SDimitry Andric WebAssembly::I64_TRUNC_S_F64); 6520b57cec5SDimitry Andric case WebAssembly::FP_TO_UINT_I64_F64: 6530b57cec5SDimitry Andric return LowerFPToInt(MI, DL, BB, TII, true, true, true, 6540b57cec5SDimitry Andric WebAssembly::I64_TRUNC_U_F64); 6555ffd83dbSDimitry Andric case WebAssembly::CALL_RESULTS: 6565ffd83dbSDimitry Andric case WebAssembly::RET_CALL_RESULTS: 657*fe6060f1SDimitry Andric return LowerCallResults(MI, DL, BB, Subtarget, TII); 6580b57cec5SDimitry Andric } 6590b57cec5SDimitry Andric } 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric const char * 6620b57cec5SDimitry Andric WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const { 6630b57cec5SDimitry Andric switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { 6640b57cec5SDimitry Andric case WebAssemblyISD::FIRST_NUMBER: 665480093f4SDimitry Andric case WebAssemblyISD::FIRST_MEM_OPCODE: 6660b57cec5SDimitry Andric break; 6670b57cec5SDimitry Andric #define HANDLE_NODETYPE(NODE) \ 6680b57cec5SDimitry Andric case WebAssemblyISD::NODE: \ 6690b57cec5SDimitry Andric return "WebAssemblyISD::" #NODE; 670480093f4SDimitry Andric #define HANDLE_MEM_NODETYPE(NODE) HANDLE_NODETYPE(NODE) 6710b57cec5SDimitry Andric #include "WebAssemblyISD.def" 672480093f4SDimitry Andric #undef HANDLE_MEM_NODETYPE 6730b57cec5SDimitry Andric #undef HANDLE_NODETYPE 6740b57cec5SDimitry Andric } 6750b57cec5SDimitry Andric return nullptr; 6760b57cec5SDimitry Andric } 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric std::pair<unsigned, const TargetRegisterClass *> 6790b57cec5SDimitry Andric WebAssemblyTargetLowering::getRegForInlineAsmConstraint( 6800b57cec5SDimitry Andric const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 6810b57cec5SDimitry Andric // First, see if this is a constraint that directly corresponds to a 6820b57cec5SDimitry Andric // WebAssembly register class. 6830b57cec5SDimitry Andric if (Constraint.size() == 1) { 6840b57cec5SDimitry Andric switch (Constraint[0]) { 6850b57cec5SDimitry Andric case 'r': 6860b57cec5SDimitry Andric assert(VT != MVT::iPTR && "Pointer MVT not expected here"); 6870b57cec5SDimitry Andric if (Subtarget->hasSIMD128() && VT.isVector()) { 6880b57cec5SDimitry Andric if (VT.getSizeInBits() == 128) 6890b57cec5SDimitry Andric return std::make_pair(0U, &WebAssembly::V128RegClass); 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric if (VT.isInteger() && !VT.isVector()) { 6920b57cec5SDimitry Andric if (VT.getSizeInBits() <= 32) 6930b57cec5SDimitry Andric return std::make_pair(0U, &WebAssembly::I32RegClass); 6940b57cec5SDimitry Andric if (VT.getSizeInBits() <= 64) 6950b57cec5SDimitry Andric return std::make_pair(0U, &WebAssembly::I64RegClass); 6960b57cec5SDimitry Andric } 697e8d8bef9SDimitry Andric if (VT.isFloatingPoint() && !VT.isVector()) { 698e8d8bef9SDimitry Andric switch (VT.getSizeInBits()) { 699e8d8bef9SDimitry Andric case 32: 700e8d8bef9SDimitry Andric return std::make_pair(0U, &WebAssembly::F32RegClass); 701e8d8bef9SDimitry Andric case 64: 702e8d8bef9SDimitry Andric return std::make_pair(0U, &WebAssembly::F64RegClass); 703e8d8bef9SDimitry Andric default: 704e8d8bef9SDimitry Andric break; 705e8d8bef9SDimitry Andric } 706e8d8bef9SDimitry Andric } 7070b57cec5SDimitry Andric break; 7080b57cec5SDimitry Andric default: 7090b57cec5SDimitry Andric break; 7100b57cec5SDimitry Andric } 7110b57cec5SDimitry Andric } 7120b57cec5SDimitry Andric 7130b57cec5SDimitry Andric return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 7140b57cec5SDimitry Andric } 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const { 7170b57cec5SDimitry Andric // Assume ctz is a relatively cheap operation. 7180b57cec5SDimitry Andric return true; 7190b57cec5SDimitry Andric } 7200b57cec5SDimitry Andric 7210b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const { 7220b57cec5SDimitry Andric // Assume clz is a relatively cheap operation. 7230b57cec5SDimitry Andric return true; 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, 7270b57cec5SDimitry Andric const AddrMode &AM, 7280b57cec5SDimitry Andric Type *Ty, unsigned AS, 7290b57cec5SDimitry Andric Instruction *I) const { 7300b57cec5SDimitry Andric // WebAssembly offsets are added as unsigned without wrapping. The 7310b57cec5SDimitry Andric // isLegalAddressingMode gives us no way to determine if wrapping could be 7320b57cec5SDimitry Andric // happening, so we approximate this by accepting only non-negative offsets. 7330b57cec5SDimitry Andric if (AM.BaseOffs < 0) 7340b57cec5SDimitry Andric return false; 7350b57cec5SDimitry Andric 7360b57cec5SDimitry Andric // WebAssembly has no scale register operands. 7370b57cec5SDimitry Andric if (AM.Scale != 0) 7380b57cec5SDimitry Andric return false; 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric // Everything else is legal. 7410b57cec5SDimitry Andric return true; 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric 7440b57cec5SDimitry Andric bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( 745*fe6060f1SDimitry Andric EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/, 7460b57cec5SDimitry Andric MachineMemOperand::Flags /*Flags*/, bool *Fast) const { 7470b57cec5SDimitry Andric // WebAssembly supports unaligned accesses, though it should be declared 7480b57cec5SDimitry Andric // with the p2align attribute on loads and stores which do so, and there 7490b57cec5SDimitry Andric // may be a performance impact. We tell LLVM they're "fast" because 7500b57cec5SDimitry Andric // for the kinds of things that LLVM uses this for (merging adjacent stores 7510b57cec5SDimitry Andric // of constants, etc.), WebAssembly implementations will either want the 7520b57cec5SDimitry Andric // unaligned access or they'll split anyway. 7530b57cec5SDimitry Andric if (Fast) 7540b57cec5SDimitry Andric *Fast = true; 7550b57cec5SDimitry Andric return true; 7560b57cec5SDimitry Andric } 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, 7590b57cec5SDimitry Andric AttributeList Attr) const { 7600b57cec5SDimitry Andric // The current thinking is that wasm engines will perform this optimization, 7610b57cec5SDimitry Andric // so we can save on code size. 7620b57cec5SDimitry Andric return true; 7630b57cec5SDimitry Andric } 7640b57cec5SDimitry Andric 7658bcb0991SDimitry Andric bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { 76616d6b3b3SDimitry Andric EVT ExtT = ExtVal.getValueType(); 76716d6b3b3SDimitry Andric EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0); 7688bcb0991SDimitry Andric return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) || 7698bcb0991SDimitry Andric (ExtT == MVT::v4i32 && MemT == MVT::v4i16) || 7708bcb0991SDimitry Andric (ExtT == MVT::v2i64 && MemT == MVT::v2i32); 7718bcb0991SDimitry Andric } 7728bcb0991SDimitry Andric 7730b57cec5SDimitry Andric EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL, 7740b57cec5SDimitry Andric LLVMContext &C, 7750b57cec5SDimitry Andric EVT VT) const { 7760b57cec5SDimitry Andric if (VT.isVector()) 7770b57cec5SDimitry Andric return VT.changeVectorElementTypeToInteger(); 7780b57cec5SDimitry Andric 7795ffd83dbSDimitry Andric // So far, all branch instructions in Wasm take an I32 condition. 7805ffd83dbSDimitry Andric // The default TargetLowering::getSetCCResultType returns the pointer size, 7815ffd83dbSDimitry Andric // which would be useful to reduce instruction counts when testing 7825ffd83dbSDimitry Andric // against 64-bit pointers/values if at some point Wasm supports that. 7835ffd83dbSDimitry Andric return EVT::getIntegerVT(C, 32); 7840b57cec5SDimitry Andric } 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, 7870b57cec5SDimitry Andric const CallInst &I, 7880b57cec5SDimitry Andric MachineFunction &MF, 7890b57cec5SDimitry Andric unsigned Intrinsic) const { 7900b57cec5SDimitry Andric switch (Intrinsic) { 791e8d8bef9SDimitry Andric case Intrinsic::wasm_memory_atomic_notify: 7920b57cec5SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 7930b57cec5SDimitry Andric Info.memVT = MVT::i32; 7940b57cec5SDimitry Andric Info.ptrVal = I.getArgOperand(0); 7950b57cec5SDimitry Andric Info.offset = 0; 7968bcb0991SDimitry Andric Info.align = Align(4); 7970b57cec5SDimitry Andric // atomic.notify instruction does not really load the memory specified with 7980b57cec5SDimitry Andric // this argument, but MachineMemOperand should either be load or store, so 7990b57cec5SDimitry Andric // we set this to a load. 8000b57cec5SDimitry Andric // FIXME Volatile isn't really correct, but currently all LLVM atomic 8010b57cec5SDimitry Andric // instructions are treated as volatiles in the backend, so we should be 8020b57cec5SDimitry Andric // consistent. The same applies for wasm_atomic_wait intrinsics too. 8030b57cec5SDimitry Andric Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 8040b57cec5SDimitry Andric return true; 805e8d8bef9SDimitry Andric case Intrinsic::wasm_memory_atomic_wait32: 8060b57cec5SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 8070b57cec5SDimitry Andric Info.memVT = MVT::i32; 8080b57cec5SDimitry Andric Info.ptrVal = I.getArgOperand(0); 8090b57cec5SDimitry Andric Info.offset = 0; 8108bcb0991SDimitry Andric Info.align = Align(4); 8110b57cec5SDimitry Andric Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 8120b57cec5SDimitry Andric return true; 813e8d8bef9SDimitry Andric case Intrinsic::wasm_memory_atomic_wait64: 8140b57cec5SDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 8150b57cec5SDimitry Andric Info.memVT = MVT::i64; 8160b57cec5SDimitry Andric Info.ptrVal = I.getArgOperand(0); 8170b57cec5SDimitry Andric Info.offset = 0; 8188bcb0991SDimitry Andric Info.align = Align(8); 8190b57cec5SDimitry Andric Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 8200b57cec5SDimitry Andric return true; 8210b57cec5SDimitry Andric default: 8220b57cec5SDimitry Andric return false; 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric } 8250b57cec5SDimitry Andric 8260b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8270b57cec5SDimitry Andric // WebAssembly Lowering private implementation. 8280b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8310b57cec5SDimitry Andric // Lowering Code 8320b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8330b57cec5SDimitry Andric 8340b57cec5SDimitry Andric static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) { 8350b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 8360b57cec5SDimitry Andric DAG.getContext()->diagnose( 8370b57cec5SDimitry Andric DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc())); 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric 8400b57cec5SDimitry Andric // Test whether the given calling convention is supported. 8410b57cec5SDimitry Andric static bool callingConvSupported(CallingConv::ID CallConv) { 8420b57cec5SDimitry Andric // We currently support the language-independent target-independent 8430b57cec5SDimitry Andric // conventions. We don't yet have a way to annotate calls with properties like 8440b57cec5SDimitry Andric // "cold", and we don't have any call-clobbered registers, so these are mostly 8450b57cec5SDimitry Andric // all handled the same. 8460b57cec5SDimitry Andric return CallConv == CallingConv::C || CallConv == CallingConv::Fast || 8470b57cec5SDimitry Andric CallConv == CallingConv::Cold || 8480b57cec5SDimitry Andric CallConv == CallingConv::PreserveMost || 8490b57cec5SDimitry Andric CallConv == CallingConv::PreserveAll || 8508bcb0991SDimitry Andric CallConv == CallingConv::CXX_FAST_TLS || 8515ffd83dbSDimitry Andric CallConv == CallingConv::WASM_EmscriptenInvoke || 8525ffd83dbSDimitry Andric CallConv == CallingConv::Swift; 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric SDValue 8560b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, 8570b57cec5SDimitry Andric SmallVectorImpl<SDValue> &InVals) const { 8580b57cec5SDimitry Andric SelectionDAG &DAG = CLI.DAG; 8590b57cec5SDimitry Andric SDLoc DL = CLI.DL; 8600b57cec5SDimitry Andric SDValue Chain = CLI.Chain; 8610b57cec5SDimitry Andric SDValue Callee = CLI.Callee; 8620b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 8630b57cec5SDimitry Andric auto Layout = MF.getDataLayout(); 8640b57cec5SDimitry Andric 8650b57cec5SDimitry Andric CallingConv::ID CallConv = CLI.CallConv; 8660b57cec5SDimitry Andric if (!callingConvSupported(CallConv)) 8670b57cec5SDimitry Andric fail(DL, DAG, 8680b57cec5SDimitry Andric "WebAssembly doesn't support language-specific or target-specific " 8690b57cec5SDimitry Andric "calling conventions yet"); 8700b57cec5SDimitry Andric if (CLI.IsPatchPoint) 8710b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly doesn't support patch point yet"); 8720b57cec5SDimitry Andric 8738bcb0991SDimitry Andric if (CLI.IsTailCall) { 8745ffd83dbSDimitry Andric auto NoTail = [&](const char *Msg) { 8755ffd83dbSDimitry Andric if (CLI.CB && CLI.CB->isMustTailCall()) 8765ffd83dbSDimitry Andric fail(DL, DAG, Msg); 8775ffd83dbSDimitry Andric CLI.IsTailCall = false; 8785ffd83dbSDimitry Andric }; 8795ffd83dbSDimitry Andric 8805ffd83dbSDimitry Andric if (!Subtarget->hasTailCall()) 8815ffd83dbSDimitry Andric NoTail("WebAssembly 'tail-call' feature not enabled"); 8825ffd83dbSDimitry Andric 8835ffd83dbSDimitry Andric // Varargs calls cannot be tail calls because the buffer is on the stack 8845ffd83dbSDimitry Andric if (CLI.IsVarArg) 8855ffd83dbSDimitry Andric NoTail("WebAssembly does not support varargs tail calls"); 8865ffd83dbSDimitry Andric 8878bcb0991SDimitry Andric // Do not tail call unless caller and callee return types match 8888bcb0991SDimitry Andric const Function &F = MF.getFunction(); 8898bcb0991SDimitry Andric const TargetMachine &TM = getTargetMachine(); 8908bcb0991SDimitry Andric Type *RetTy = F.getReturnType(); 8918bcb0991SDimitry Andric SmallVector<MVT, 4> CallerRetTys; 8928bcb0991SDimitry Andric SmallVector<MVT, 4> CalleeRetTys; 8938bcb0991SDimitry Andric computeLegalValueVTs(F, TM, RetTy, CallerRetTys); 8948bcb0991SDimitry Andric computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys); 8958bcb0991SDimitry Andric bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() && 8968bcb0991SDimitry Andric std::equal(CallerRetTys.begin(), CallerRetTys.end(), 8978bcb0991SDimitry Andric CalleeRetTys.begin()); 8985ffd83dbSDimitry Andric if (!TypesMatch) 8995ffd83dbSDimitry Andric NoTail("WebAssembly tail call requires caller and callee return types to " 9005ffd83dbSDimitry Andric "match"); 9015ffd83dbSDimitry Andric 9025ffd83dbSDimitry Andric // If pointers to local stack values are passed, we cannot tail call 9035ffd83dbSDimitry Andric if (CLI.CB) { 9045ffd83dbSDimitry Andric for (auto &Arg : CLI.CB->args()) { 9055ffd83dbSDimitry Andric Value *Val = Arg.get(); 9065ffd83dbSDimitry Andric // Trace the value back through pointer operations 9075ffd83dbSDimitry Andric while (true) { 9085ffd83dbSDimitry Andric Value *Src = Val->stripPointerCastsAndAliases(); 9095ffd83dbSDimitry Andric if (auto *GEP = dyn_cast<GetElementPtrInst>(Src)) 9105ffd83dbSDimitry Andric Src = GEP->getPointerOperand(); 9115ffd83dbSDimitry Andric if (Val == Src) 9125ffd83dbSDimitry Andric break; 9135ffd83dbSDimitry Andric Val = Src; 9140b57cec5SDimitry Andric } 9155ffd83dbSDimitry Andric if (isa<AllocaInst>(Val)) { 9165ffd83dbSDimitry Andric NoTail( 9175ffd83dbSDimitry Andric "WebAssembly does not support tail calling with stack arguments"); 9185ffd83dbSDimitry Andric break; 9198bcb0991SDimitry Andric } 9208bcb0991SDimitry Andric } 9218bcb0991SDimitry Andric } 9228bcb0991SDimitry Andric } 9230b57cec5SDimitry Andric 9240b57cec5SDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 9250b57cec5SDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 9260b57cec5SDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 9278bcb0991SDimitry Andric 9288bcb0991SDimitry Andric // The generic code may have added an sret argument. If we're lowering an 9298bcb0991SDimitry Andric // invoke function, the ABI requires that the function pointer be the first 9308bcb0991SDimitry Andric // argument, so we may have to swap the arguments. 9318bcb0991SDimitry Andric if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 && 9328bcb0991SDimitry Andric Outs[0].Flags.isSRet()) { 9338bcb0991SDimitry Andric std::swap(Outs[0], Outs[1]); 9348bcb0991SDimitry Andric std::swap(OutVals[0], OutVals[1]); 9358bcb0991SDimitry Andric } 9368bcb0991SDimitry Andric 9375ffd83dbSDimitry Andric bool HasSwiftSelfArg = false; 9385ffd83dbSDimitry Andric bool HasSwiftErrorArg = false; 9390b57cec5SDimitry Andric unsigned NumFixedArgs = 0; 9400b57cec5SDimitry Andric for (unsigned I = 0; I < Outs.size(); ++I) { 9410b57cec5SDimitry Andric const ISD::OutputArg &Out = Outs[I]; 9420b57cec5SDimitry Andric SDValue &OutVal = OutVals[I]; 9435ffd83dbSDimitry Andric HasSwiftSelfArg |= Out.Flags.isSwiftSelf(); 9445ffd83dbSDimitry Andric HasSwiftErrorArg |= Out.Flags.isSwiftError(); 9450b57cec5SDimitry Andric if (Out.Flags.isNest()) 9460b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 9470b57cec5SDimitry Andric if (Out.Flags.isInAlloca()) 9480b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 9490b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegs()) 9500b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 9510b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegsLast()) 9520b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 9530b57cec5SDimitry Andric if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) { 9540b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 9550b57cec5SDimitry Andric int FI = MFI.CreateStackObject(Out.Flags.getByValSize(), 9565ffd83dbSDimitry Andric Out.Flags.getNonZeroByValAlign(), 9570b57cec5SDimitry Andric /*isSS=*/false); 9580b57cec5SDimitry Andric SDValue SizeNode = 9590b57cec5SDimitry Andric DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32); 9600b57cec5SDimitry Andric SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 9610b57cec5SDimitry Andric Chain = DAG.getMemcpy( 9625ffd83dbSDimitry Andric Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getNonZeroByValAlign(), 9630b57cec5SDimitry Andric /*isVolatile*/ false, /*AlwaysInline=*/false, 9640b57cec5SDimitry Andric /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); 9650b57cec5SDimitry Andric OutVal = FINode; 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric // Count the number of fixed args *after* legalization. 9680b57cec5SDimitry Andric NumFixedArgs += Out.IsFixed; 9690b57cec5SDimitry Andric } 9700b57cec5SDimitry Andric 9710b57cec5SDimitry Andric bool IsVarArg = CLI.IsVarArg; 9720b57cec5SDimitry Andric auto PtrVT = getPointerTy(Layout); 9730b57cec5SDimitry Andric 9745ffd83dbSDimitry Andric // For swiftcc, emit additional swiftself and swifterror arguments 9755ffd83dbSDimitry Andric // if there aren't. These additional arguments are also added for callee 9765ffd83dbSDimitry Andric // signature They are necessary to match callee and caller signature for 9775ffd83dbSDimitry Andric // indirect call. 9785ffd83dbSDimitry Andric if (CallConv == CallingConv::Swift) { 9795ffd83dbSDimitry Andric if (!HasSwiftSelfArg) { 9805ffd83dbSDimitry Andric NumFixedArgs++; 9815ffd83dbSDimitry Andric ISD::OutputArg Arg; 9825ffd83dbSDimitry Andric Arg.Flags.setSwiftSelf(); 9835ffd83dbSDimitry Andric CLI.Outs.push_back(Arg); 9845ffd83dbSDimitry Andric SDValue ArgVal = DAG.getUNDEF(PtrVT); 9855ffd83dbSDimitry Andric CLI.OutVals.push_back(ArgVal); 9865ffd83dbSDimitry Andric } 9875ffd83dbSDimitry Andric if (!HasSwiftErrorArg) { 9885ffd83dbSDimitry Andric NumFixedArgs++; 9895ffd83dbSDimitry Andric ISD::OutputArg Arg; 9905ffd83dbSDimitry Andric Arg.Flags.setSwiftError(); 9915ffd83dbSDimitry Andric CLI.Outs.push_back(Arg); 9925ffd83dbSDimitry Andric SDValue ArgVal = DAG.getUNDEF(PtrVT); 9935ffd83dbSDimitry Andric CLI.OutVals.push_back(ArgVal); 9945ffd83dbSDimitry Andric } 9955ffd83dbSDimitry Andric } 9965ffd83dbSDimitry Andric 9970b57cec5SDimitry Andric // Analyze operands of the call, assigning locations to each operand. 9980b57cec5SDimitry Andric SmallVector<CCValAssign, 16> ArgLocs; 9990b57cec5SDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric if (IsVarArg) { 10020b57cec5SDimitry Andric // Outgoing non-fixed arguments are placed in a buffer. First 10030b57cec5SDimitry Andric // compute their offsets and the total amount of buffer space needed. 10040b57cec5SDimitry Andric for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) { 10050b57cec5SDimitry Andric const ISD::OutputArg &Out = Outs[I]; 10060b57cec5SDimitry Andric SDValue &Arg = OutVals[I]; 10070b57cec5SDimitry Andric EVT VT = Arg.getValueType(); 10080b57cec5SDimitry Andric assert(VT != MVT::iPTR && "Legalized args should be concrete"); 10090b57cec5SDimitry Andric Type *Ty = VT.getTypeForEVT(*DAG.getContext()); 10105ffd83dbSDimitry Andric Align Alignment = 10115ffd83dbSDimitry Andric std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty)); 10125ffd83dbSDimitry Andric unsigned Offset = 10135ffd83dbSDimitry Andric CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment); 10140b57cec5SDimitry Andric CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), 10150b57cec5SDimitry Andric Offset, VT.getSimpleVT(), 10160b57cec5SDimitry Andric CCValAssign::Full)); 10170b57cec5SDimitry Andric } 10180b57cec5SDimitry Andric } 10190b57cec5SDimitry Andric 10200b57cec5SDimitry Andric unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric SDValue FINode; 10230b57cec5SDimitry Andric if (IsVarArg && NumBytes) { 10240b57cec5SDimitry Andric // For non-fixed arguments, next emit stores to store the argument values 10250b57cec5SDimitry Andric // to the stack buffer at the offsets computed above. 10260b57cec5SDimitry Andric int FI = MF.getFrameInfo().CreateStackObject(NumBytes, 10270b57cec5SDimitry Andric Layout.getStackAlignment(), 10280b57cec5SDimitry Andric /*isSS=*/false); 10290b57cec5SDimitry Andric unsigned ValNo = 0; 10300b57cec5SDimitry Andric SmallVector<SDValue, 8> Chains; 1031e8d8bef9SDimitry Andric for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) { 10320b57cec5SDimitry Andric assert(ArgLocs[ValNo].getValNo() == ValNo && 10330b57cec5SDimitry Andric "ArgLocs should remain in order and only hold varargs args"); 10340b57cec5SDimitry Andric unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); 10350b57cec5SDimitry Andric FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 10360b57cec5SDimitry Andric SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode, 10370b57cec5SDimitry Andric DAG.getConstant(Offset, DL, PtrVT)); 10380b57cec5SDimitry Andric Chains.push_back( 10390b57cec5SDimitry Andric DAG.getStore(Chain, DL, Arg, Add, 1040e8d8bef9SDimitry Andric MachinePointerInfo::getFixedStack(MF, FI, Offset))); 10410b57cec5SDimitry Andric } 10420b57cec5SDimitry Andric if (!Chains.empty()) 10430b57cec5SDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); 10440b57cec5SDimitry Andric } else if (IsVarArg) { 10450b57cec5SDimitry Andric FINode = DAG.getIntPtrConstant(0, DL); 10460b57cec5SDimitry Andric } 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric if (Callee->getOpcode() == ISD::GlobalAddress) { 10490b57cec5SDimitry Andric // If the callee is a GlobalAddress node (quite common, every direct call 10500b57cec5SDimitry Andric // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress 10510b57cec5SDimitry Andric // doesn't at MO_GOT which is not needed for direct calls. 10520b57cec5SDimitry Andric GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee); 10530b57cec5SDimitry Andric Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL, 10540b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout()), 10550b57cec5SDimitry Andric GA->getOffset()); 10560b57cec5SDimitry Andric Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL, 10570b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout()), Callee); 10580b57cec5SDimitry Andric } 10590b57cec5SDimitry Andric 10600b57cec5SDimitry Andric // Compute the operands for the CALLn node. 10610b57cec5SDimitry Andric SmallVector<SDValue, 16> Ops; 10620b57cec5SDimitry Andric Ops.push_back(Chain); 10630b57cec5SDimitry Andric Ops.push_back(Callee); 10640b57cec5SDimitry Andric 10650b57cec5SDimitry Andric // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs 10660b57cec5SDimitry Andric // isn't reliable. 10670b57cec5SDimitry Andric Ops.append(OutVals.begin(), 10680b57cec5SDimitry Andric IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); 10690b57cec5SDimitry Andric // Add a pointer to the vararg buffer. 10700b57cec5SDimitry Andric if (IsVarArg) 10710b57cec5SDimitry Andric Ops.push_back(FINode); 10720b57cec5SDimitry Andric 10730b57cec5SDimitry Andric SmallVector<EVT, 8> InTys; 10740b57cec5SDimitry Andric for (const auto &In : Ins) { 10750b57cec5SDimitry Andric assert(!In.Flags.isByVal() && "byval is not valid for return values"); 10760b57cec5SDimitry Andric assert(!In.Flags.isNest() && "nest is not valid for return values"); 10770b57cec5SDimitry Andric if (In.Flags.isInAlloca()) 10780b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values"); 10790b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegs()) 10800b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values"); 10810b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegsLast()) 10820b57cec5SDimitry Andric fail(DL, DAG, 10830b57cec5SDimitry Andric "WebAssembly hasn't implemented cons regs last return values"); 10845ffd83dbSDimitry Andric // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in 10850b57cec5SDimitry Andric // registers. 10860b57cec5SDimitry Andric InTys.push_back(In.VT); 10870b57cec5SDimitry Andric } 10880b57cec5SDimitry Andric 1089*fe6060f1SDimitry Andric // Lastly, if this is a call to a funcref we need to add an instruction 1090*fe6060f1SDimitry Andric // table.set to the chain and transform the call. 1091*fe6060f1SDimitry Andric if (CLI.CB && isFuncrefType(CLI.CB->getCalledOperand()->getType())) { 1092*fe6060f1SDimitry Andric // In the absence of function references proposal where a funcref call is 1093*fe6060f1SDimitry Andric // lowered to call_ref, using reference types we generate a table.set to set 1094*fe6060f1SDimitry Andric // the funcref to a special table used solely for this purpose, followed by 1095*fe6060f1SDimitry Andric // a call_indirect. Here we just generate the table set, and return the 1096*fe6060f1SDimitry Andric // SDValue of the table.set so that LowerCall can finalize the lowering by 1097*fe6060f1SDimitry Andric // generating the call_indirect. 1098*fe6060f1SDimitry Andric SDValue Chain = Ops[0]; 1099*fe6060f1SDimitry Andric 1100*fe6060f1SDimitry Andric MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( 1101*fe6060f1SDimitry Andric MF.getContext(), Subtarget); 1102*fe6060f1SDimitry Andric SDValue Sym = DAG.getMCSymbol(Table, PtrVT); 1103*fe6060f1SDimitry Andric SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32); 1104*fe6060f1SDimitry Andric SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee}; 1105*fe6060f1SDimitry Andric SDValue TableSet = DAG.getMemIntrinsicNode( 1106*fe6060f1SDimitry Andric WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps, 1107*fe6060f1SDimitry Andric MVT::funcref, 1108*fe6060f1SDimitry Andric // Machine Mem Operand args 1109*fe6060f1SDimitry Andric MachinePointerInfo(WasmAddressSpace::FUNCREF), 1110*fe6060f1SDimitry Andric CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()), 1111*fe6060f1SDimitry Andric MachineMemOperand::MOStore); 1112*fe6060f1SDimitry Andric 1113*fe6060f1SDimitry Andric Ops[0] = TableSet; // The new chain is the TableSet itself 1114*fe6060f1SDimitry Andric } 1115*fe6060f1SDimitry Andric 11160b57cec5SDimitry Andric if (CLI.IsTailCall) { 11170b57cec5SDimitry Andric // ret_calls do not return values to the current frame 11180b57cec5SDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 11190b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops); 11200b57cec5SDimitry Andric } 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric InTys.push_back(MVT::Other); 11230b57cec5SDimitry Andric SDVTList InTyList = DAG.getVTList(InTys); 11245ffd83dbSDimitry Andric SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops); 11250b57cec5SDimitry Andric 11265ffd83dbSDimitry Andric for (size_t I = 0; I < Ins.size(); ++I) 11275ffd83dbSDimitry Andric InVals.push_back(Res.getValue(I)); 11285ffd83dbSDimitry Andric 11295ffd83dbSDimitry Andric // Return the chain 11305ffd83dbSDimitry Andric return Res.getValue(Ins.size()); 11310b57cec5SDimitry Andric } 11320b57cec5SDimitry Andric 11330b57cec5SDimitry Andric bool WebAssemblyTargetLowering::CanLowerReturn( 11340b57cec5SDimitry Andric CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/, 11350b57cec5SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 11360b57cec5SDimitry Andric LLVMContext & /*Context*/) const { 11378bcb0991SDimitry Andric // WebAssembly can only handle returning tuples with multivalue enabled 11388bcb0991SDimitry Andric return Subtarget->hasMultivalue() || Outs.size() <= 1; 11390b57cec5SDimitry Andric } 11400b57cec5SDimitry Andric 11410b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerReturn( 11420b57cec5SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, 11430b57cec5SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 11440b57cec5SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 11450b57cec5SDimitry Andric SelectionDAG &DAG) const { 11468bcb0991SDimitry Andric assert((Subtarget->hasMultivalue() || Outs.size() <= 1) && 11478bcb0991SDimitry Andric "MVP WebAssembly can only return up to one value"); 11480b57cec5SDimitry Andric if (!callingConvSupported(CallConv)) 11490b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 11500b57cec5SDimitry Andric 11510b57cec5SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 11520b57cec5SDimitry Andric RetOps.append(OutVals.begin(), OutVals.end()); 11530b57cec5SDimitry Andric Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); 11540b57cec5SDimitry Andric 11550b57cec5SDimitry Andric // Record the number and types of the return values. 11560b57cec5SDimitry Andric for (const ISD::OutputArg &Out : Outs) { 11570b57cec5SDimitry Andric assert(!Out.Flags.isByVal() && "byval is not valid for return values"); 11580b57cec5SDimitry Andric assert(!Out.Flags.isNest() && "nest is not valid for return values"); 11590b57cec5SDimitry Andric assert(Out.IsFixed && "non-fixed return value is not valid"); 11600b57cec5SDimitry Andric if (Out.Flags.isInAlloca()) 11610b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca results"); 11620b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegs()) 11630b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs results"); 11640b57cec5SDimitry Andric if (Out.Flags.isInConsecutiveRegsLast()) 11650b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results"); 11660b57cec5SDimitry Andric } 11670b57cec5SDimitry Andric 11680b57cec5SDimitry Andric return Chain; 11690b57cec5SDimitry Andric } 11700b57cec5SDimitry Andric 11710b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFormalArguments( 11720b57cec5SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 11730b57cec5SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 11740b57cec5SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 11750b57cec5SDimitry Andric if (!callingConvSupported(CallConv)) 11760b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 11770b57cec5SDimitry Andric 11780b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 11790b57cec5SDimitry Andric auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); 11800b57cec5SDimitry Andric 11810b57cec5SDimitry Andric // Set up the incoming ARGUMENTS value, which serves to represent the liveness 11820b57cec5SDimitry Andric // of the incoming values before they're represented by virtual registers. 11830b57cec5SDimitry Andric MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); 11840b57cec5SDimitry Andric 11855ffd83dbSDimitry Andric bool HasSwiftErrorArg = false; 11865ffd83dbSDimitry Andric bool HasSwiftSelfArg = false; 11870b57cec5SDimitry Andric for (const ISD::InputArg &In : Ins) { 11885ffd83dbSDimitry Andric HasSwiftSelfArg |= In.Flags.isSwiftSelf(); 11895ffd83dbSDimitry Andric HasSwiftErrorArg |= In.Flags.isSwiftError(); 11900b57cec5SDimitry Andric if (In.Flags.isInAlloca()) 11910b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 11920b57cec5SDimitry Andric if (In.Flags.isNest()) 11930b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 11940b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegs()) 11950b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 11960b57cec5SDimitry Andric if (In.Flags.isInConsecutiveRegsLast()) 11970b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 11985ffd83dbSDimitry Andric // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in 11990b57cec5SDimitry Andric // registers. 12000b57cec5SDimitry Andric InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, 12010b57cec5SDimitry Andric DAG.getTargetConstant(InVals.size(), 12020b57cec5SDimitry Andric DL, MVT::i32)) 12030b57cec5SDimitry Andric : DAG.getUNDEF(In.VT)); 12040b57cec5SDimitry Andric 12050b57cec5SDimitry Andric // Record the number and types of arguments. 12060b57cec5SDimitry Andric MFI->addParam(In.VT); 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric 12095ffd83dbSDimitry Andric // For swiftcc, emit additional swiftself and swifterror arguments 12105ffd83dbSDimitry Andric // if there aren't. These additional arguments are also added for callee 12115ffd83dbSDimitry Andric // signature They are necessary to match callee and caller signature for 12125ffd83dbSDimitry Andric // indirect call. 12135ffd83dbSDimitry Andric auto PtrVT = getPointerTy(MF.getDataLayout()); 12145ffd83dbSDimitry Andric if (CallConv == CallingConv::Swift) { 12155ffd83dbSDimitry Andric if (!HasSwiftSelfArg) { 12165ffd83dbSDimitry Andric MFI->addParam(PtrVT); 12175ffd83dbSDimitry Andric } 12185ffd83dbSDimitry Andric if (!HasSwiftErrorArg) { 12195ffd83dbSDimitry Andric MFI->addParam(PtrVT); 12205ffd83dbSDimitry Andric } 12215ffd83dbSDimitry Andric } 12220b57cec5SDimitry Andric // Varargs are copied into a buffer allocated by the caller, and a pointer to 12230b57cec5SDimitry Andric // the buffer is passed as an argument. 12240b57cec5SDimitry Andric if (IsVarArg) { 12250b57cec5SDimitry Andric MVT PtrVT = getPointerTy(MF.getDataLayout()); 12268bcb0991SDimitry Andric Register VarargVreg = 12270b57cec5SDimitry Andric MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT)); 12280b57cec5SDimitry Andric MFI->setVarargBufferVreg(VarargVreg); 12290b57cec5SDimitry Andric Chain = DAG.getCopyToReg( 12300b57cec5SDimitry Andric Chain, DL, VarargVreg, 12310b57cec5SDimitry Andric DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT, 12320b57cec5SDimitry Andric DAG.getTargetConstant(Ins.size(), DL, MVT::i32))); 12330b57cec5SDimitry Andric MFI->addParam(PtrVT); 12340b57cec5SDimitry Andric } 12350b57cec5SDimitry Andric 12360b57cec5SDimitry Andric // Record the number and types of arguments and results. 12370b57cec5SDimitry Andric SmallVector<MVT, 4> Params; 12380b57cec5SDimitry Andric SmallVector<MVT, 4> Results; 12395ffd83dbSDimitry Andric computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(), 12405ffd83dbSDimitry Andric MF.getFunction(), DAG.getTarget(), Params, Results); 12410b57cec5SDimitry Andric for (MVT VT : Results) 12420b57cec5SDimitry Andric MFI->addResult(VT); 12430b57cec5SDimitry Andric // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify 12440b57cec5SDimitry Andric // the param logic here with ComputeSignatureVTs 12450b57cec5SDimitry Andric assert(MFI->getParams().size() == Params.size() && 12460b57cec5SDimitry Andric std::equal(MFI->getParams().begin(), MFI->getParams().end(), 12470b57cec5SDimitry Andric Params.begin())); 12480b57cec5SDimitry Andric 12490b57cec5SDimitry Andric return Chain; 12500b57cec5SDimitry Andric } 12510b57cec5SDimitry Andric 12520b57cec5SDimitry Andric void WebAssemblyTargetLowering::ReplaceNodeResults( 12530b57cec5SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 12540b57cec5SDimitry Andric switch (N->getOpcode()) { 12550b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 12560b57cec5SDimitry Andric // Do not add any results, signifying that N should not be custom lowered 12570b57cec5SDimitry Andric // after all. This happens because simd128 turns on custom lowering for 12580b57cec5SDimitry Andric // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an 12590b57cec5SDimitry Andric // illegal type. 12600b57cec5SDimitry Andric break; 12610b57cec5SDimitry Andric default: 12620b57cec5SDimitry Andric llvm_unreachable( 12630b57cec5SDimitry Andric "ReplaceNodeResults not implemented for this op for WebAssembly!"); 12640b57cec5SDimitry Andric } 12650b57cec5SDimitry Andric } 12660b57cec5SDimitry Andric 12670b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12680b57cec5SDimitry Andric // Custom lowering hooks. 12690b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12700b57cec5SDimitry Andric 12710b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, 12720b57cec5SDimitry Andric SelectionDAG &DAG) const { 12730b57cec5SDimitry Andric SDLoc DL(Op); 12740b57cec5SDimitry Andric switch (Op.getOpcode()) { 12750b57cec5SDimitry Andric default: 12760b57cec5SDimitry Andric llvm_unreachable("unimplemented operation lowering"); 12770b57cec5SDimitry Andric return SDValue(); 12780b57cec5SDimitry Andric case ISD::FrameIndex: 12790b57cec5SDimitry Andric return LowerFrameIndex(Op, DAG); 12800b57cec5SDimitry Andric case ISD::GlobalAddress: 12810b57cec5SDimitry Andric return LowerGlobalAddress(Op, DAG); 1282e8d8bef9SDimitry Andric case ISD::GlobalTLSAddress: 1283e8d8bef9SDimitry Andric return LowerGlobalTLSAddress(Op, DAG); 12840b57cec5SDimitry Andric case ISD::ExternalSymbol: 12850b57cec5SDimitry Andric return LowerExternalSymbol(Op, DAG); 12860b57cec5SDimitry Andric case ISD::JumpTable: 12870b57cec5SDimitry Andric return LowerJumpTable(Op, DAG); 12880b57cec5SDimitry Andric case ISD::BR_JT: 12890b57cec5SDimitry Andric return LowerBR_JT(Op, DAG); 12900b57cec5SDimitry Andric case ISD::VASTART: 12910b57cec5SDimitry Andric return LowerVASTART(Op, DAG); 12920b57cec5SDimitry Andric case ISD::BlockAddress: 12930b57cec5SDimitry Andric case ISD::BRIND: 12940b57cec5SDimitry Andric fail(DL, DAG, "WebAssembly hasn't implemented computed gotos"); 12950b57cec5SDimitry Andric return SDValue(); 12960b57cec5SDimitry Andric case ISD::RETURNADDR: 12970b57cec5SDimitry Andric return LowerRETURNADDR(Op, DAG); 12980b57cec5SDimitry Andric case ISD::FRAMEADDR: 12990b57cec5SDimitry Andric return LowerFRAMEADDR(Op, DAG); 13000b57cec5SDimitry Andric case ISD::CopyToReg: 13010b57cec5SDimitry Andric return LowerCopyToReg(Op, DAG); 13020b57cec5SDimitry Andric case ISD::EXTRACT_VECTOR_ELT: 13030b57cec5SDimitry Andric case ISD::INSERT_VECTOR_ELT: 13040b57cec5SDimitry Andric return LowerAccessVectorElement(Op, DAG); 13050b57cec5SDimitry Andric case ISD::INTRINSIC_VOID: 13060b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 13070b57cec5SDimitry Andric case ISD::INTRINSIC_W_CHAIN: 13080b57cec5SDimitry Andric return LowerIntrinsic(Op, DAG); 13090b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 13100b57cec5SDimitry Andric return LowerSIGN_EXTEND_INREG(Op, DAG); 13110b57cec5SDimitry Andric case ISD::BUILD_VECTOR: 13120b57cec5SDimitry Andric return LowerBUILD_VECTOR(Op, DAG); 13130b57cec5SDimitry Andric case ISD::VECTOR_SHUFFLE: 13140b57cec5SDimitry Andric return LowerVECTOR_SHUFFLE(Op, DAG); 1315480093f4SDimitry Andric case ISD::SETCC: 1316480093f4SDimitry Andric return LowerSETCC(Op, DAG); 13170b57cec5SDimitry Andric case ISD::SHL: 13180b57cec5SDimitry Andric case ISD::SRA: 13190b57cec5SDimitry Andric case ISD::SRL: 13200b57cec5SDimitry Andric return LowerShift(Op, DAG); 1321*fe6060f1SDimitry Andric case ISD::FP_TO_SINT_SAT: 1322*fe6060f1SDimitry Andric case ISD::FP_TO_UINT_SAT: 1323*fe6060f1SDimitry Andric return LowerFP_TO_INT_SAT(Op, DAG); 1324*fe6060f1SDimitry Andric case ISD::LOAD: 1325*fe6060f1SDimitry Andric return LowerLoad(Op, DAG); 1326*fe6060f1SDimitry Andric case ISD::STORE: 1327*fe6060f1SDimitry Andric return LowerStore(Op, DAG); 13280b57cec5SDimitry Andric } 13290b57cec5SDimitry Andric } 13300b57cec5SDimitry Andric 1331*fe6060f1SDimitry Andric static bool IsWebAssemblyGlobal(SDValue Op) { 1332*fe6060f1SDimitry Andric if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op)) 1333*fe6060f1SDimitry Andric return WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace()); 1334*fe6060f1SDimitry Andric 1335*fe6060f1SDimitry Andric return false; 1336*fe6060f1SDimitry Andric } 1337*fe6060f1SDimitry Andric 1338*fe6060f1SDimitry Andric static Optional<unsigned> IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG) { 1339*fe6060f1SDimitry Andric const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op); 1340*fe6060f1SDimitry Andric if (!FI) 1341*fe6060f1SDimitry Andric return None; 1342*fe6060f1SDimitry Andric 1343*fe6060f1SDimitry Andric auto &MF = DAG.getMachineFunction(); 1344*fe6060f1SDimitry Andric return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex()); 1345*fe6060f1SDimitry Andric } 1346*fe6060f1SDimitry Andric 1347*fe6060f1SDimitry Andric bool WebAssemblyTargetLowering::isFuncrefType(const Type *Ty) { 1348*fe6060f1SDimitry Andric return isa<PointerType>(Ty) && 1349*fe6060f1SDimitry Andric Ty->getPointerAddressSpace() == WasmAddressSpace::FUNCREF; 1350*fe6060f1SDimitry Andric } 1351*fe6060f1SDimitry Andric 1352*fe6060f1SDimitry Andric bool WebAssemblyTargetLowering::isExternrefType(const Type *Ty) { 1353*fe6060f1SDimitry Andric return isa<PointerType>(Ty) && 1354*fe6060f1SDimitry Andric Ty->getPointerAddressSpace() == WasmAddressSpace::EXTERNREF; 1355*fe6060f1SDimitry Andric } 1356*fe6060f1SDimitry Andric 1357*fe6060f1SDimitry Andric SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, 1358*fe6060f1SDimitry Andric SelectionDAG &DAG) const { 1359*fe6060f1SDimitry Andric SDLoc DL(Op); 1360*fe6060f1SDimitry Andric StoreSDNode *SN = cast<StoreSDNode>(Op.getNode()); 1361*fe6060f1SDimitry Andric const SDValue &Value = SN->getValue(); 1362*fe6060f1SDimitry Andric const SDValue &Base = SN->getBasePtr(); 1363*fe6060f1SDimitry Andric const SDValue &Offset = SN->getOffset(); 1364*fe6060f1SDimitry Andric 1365*fe6060f1SDimitry Andric if (IsWebAssemblyGlobal(Base)) { 1366*fe6060f1SDimitry Andric if (!Offset->isUndef()) 1367*fe6060f1SDimitry Andric report_fatal_error("unexpected offset when storing to webassembly global", 1368*fe6060f1SDimitry Andric false); 1369*fe6060f1SDimitry Andric 1370*fe6060f1SDimitry Andric SDVTList Tys = DAG.getVTList(MVT::Other); 1371*fe6060f1SDimitry Andric SDValue Ops[] = {SN->getChain(), Value, Base}; 1372*fe6060f1SDimitry Andric return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops, 1373*fe6060f1SDimitry Andric SN->getMemoryVT(), SN->getMemOperand()); 1374*fe6060f1SDimitry Andric } 1375*fe6060f1SDimitry Andric 1376*fe6060f1SDimitry Andric if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { 1377*fe6060f1SDimitry Andric if (!Offset->isUndef()) 1378*fe6060f1SDimitry Andric report_fatal_error("unexpected offset when storing to webassembly local", 1379*fe6060f1SDimitry Andric false); 1380*fe6060f1SDimitry Andric 1381*fe6060f1SDimitry Andric SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); 1382*fe6060f1SDimitry Andric SDVTList Tys = DAG.getVTList(MVT::Other); // The chain. 1383*fe6060f1SDimitry Andric SDValue Ops[] = {SN->getChain(), Idx, Value}; 1384*fe6060f1SDimitry Andric return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops); 1385*fe6060f1SDimitry Andric } 1386*fe6060f1SDimitry Andric 1387*fe6060f1SDimitry Andric return Op; 1388*fe6060f1SDimitry Andric } 1389*fe6060f1SDimitry Andric 1390*fe6060f1SDimitry Andric SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op, 1391*fe6060f1SDimitry Andric SelectionDAG &DAG) const { 1392*fe6060f1SDimitry Andric SDLoc DL(Op); 1393*fe6060f1SDimitry Andric LoadSDNode *LN = cast<LoadSDNode>(Op.getNode()); 1394*fe6060f1SDimitry Andric const SDValue &Base = LN->getBasePtr(); 1395*fe6060f1SDimitry Andric const SDValue &Offset = LN->getOffset(); 1396*fe6060f1SDimitry Andric 1397*fe6060f1SDimitry Andric if (IsWebAssemblyGlobal(Base)) { 1398*fe6060f1SDimitry Andric if (!Offset->isUndef()) 1399*fe6060f1SDimitry Andric report_fatal_error( 1400*fe6060f1SDimitry Andric "unexpected offset when loading from webassembly global", false); 1401*fe6060f1SDimitry Andric 1402*fe6060f1SDimitry Andric SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); 1403*fe6060f1SDimitry Andric SDValue Ops[] = {LN->getChain(), Base}; 1404*fe6060f1SDimitry Andric return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops, 1405*fe6060f1SDimitry Andric LN->getMemoryVT(), LN->getMemOperand()); 1406*fe6060f1SDimitry Andric } 1407*fe6060f1SDimitry Andric 1408*fe6060f1SDimitry Andric if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { 1409*fe6060f1SDimitry Andric if (!Offset->isUndef()) 1410*fe6060f1SDimitry Andric report_fatal_error( 1411*fe6060f1SDimitry Andric "unexpected offset when loading from webassembly local", false); 1412*fe6060f1SDimitry Andric 1413*fe6060f1SDimitry Andric SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); 1414*fe6060f1SDimitry Andric EVT LocalVT = LN->getValueType(0); 1415*fe6060f1SDimitry Andric SDValue LocalGet = DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, LocalVT, 1416*fe6060f1SDimitry Andric {LN->getChain(), Idx}); 1417*fe6060f1SDimitry Andric SDValue Result = DAG.getMergeValues({LocalGet, LN->getChain()}, DL); 1418*fe6060f1SDimitry Andric assert(Result->getNumValues() == 2 && "Loads must carry a chain!"); 1419*fe6060f1SDimitry Andric return Result; 1420*fe6060f1SDimitry Andric } 1421*fe6060f1SDimitry Andric 1422*fe6060f1SDimitry Andric return Op; 1423*fe6060f1SDimitry Andric } 1424*fe6060f1SDimitry Andric 14250b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op, 14260b57cec5SDimitry Andric SelectionDAG &DAG) const { 14270b57cec5SDimitry Andric SDValue Src = Op.getOperand(2); 14280b57cec5SDimitry Andric if (isa<FrameIndexSDNode>(Src.getNode())) { 14290b57cec5SDimitry Andric // CopyToReg nodes don't support FrameIndex operands. Other targets select 14300b57cec5SDimitry Andric // the FI to some LEA-like instruction, but since we don't have that, we 14310b57cec5SDimitry Andric // need to insert some kind of instruction that can take an FI operand and 14320b57cec5SDimitry Andric // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy 14330b57cec5SDimitry Andric // local.copy between Op and its FI operand. 14340b57cec5SDimitry Andric SDValue Chain = Op.getOperand(0); 14350b57cec5SDimitry Andric SDLoc DL(Op); 14360b57cec5SDimitry Andric unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg(); 14370b57cec5SDimitry Andric EVT VT = Src.getValueType(); 14380b57cec5SDimitry Andric SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32 14390b57cec5SDimitry Andric : WebAssembly::COPY_I64, 14400b57cec5SDimitry Andric DL, VT, Src), 14410b57cec5SDimitry Andric 0); 14420b57cec5SDimitry Andric return Op.getNode()->getNumValues() == 1 14430b57cec5SDimitry Andric ? DAG.getCopyToReg(Chain, DL, Reg, Copy) 14440b57cec5SDimitry Andric : DAG.getCopyToReg(Chain, DL, Reg, Copy, 14450b57cec5SDimitry Andric Op.getNumOperands() == 4 ? Op.getOperand(3) 14460b57cec5SDimitry Andric : SDValue()); 14470b57cec5SDimitry Andric } 14480b57cec5SDimitry Andric return SDValue(); 14490b57cec5SDimitry Andric } 14500b57cec5SDimitry Andric 14510b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, 14520b57cec5SDimitry Andric SelectionDAG &DAG) const { 14530b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Op)->getIndex(); 14540b57cec5SDimitry Andric return DAG.getTargetFrameIndex(FI, Op.getValueType()); 14550b57cec5SDimitry Andric } 14560b57cec5SDimitry Andric 14570b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op, 14580b57cec5SDimitry Andric SelectionDAG &DAG) const { 14590b57cec5SDimitry Andric SDLoc DL(Op); 14600b57cec5SDimitry Andric 14610b57cec5SDimitry Andric if (!Subtarget->getTargetTriple().isOSEmscripten()) { 14620b57cec5SDimitry Andric fail(DL, DAG, 14630b57cec5SDimitry Andric "Non-Emscripten WebAssembly hasn't implemented " 14640b57cec5SDimitry Andric "__builtin_return_address"); 14650b57cec5SDimitry Andric return SDValue(); 14660b57cec5SDimitry Andric } 14670b57cec5SDimitry Andric 14680b57cec5SDimitry Andric if (verifyReturnAddressArgumentIsConstant(Op, DAG)) 14690b57cec5SDimitry Andric return SDValue(); 14700b57cec5SDimitry Andric 14710b57cec5SDimitry Andric unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 14728bcb0991SDimitry Andric MakeLibCallOptions CallOptions; 14730b57cec5SDimitry Andric return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(), 14748bcb0991SDimitry Andric {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL) 14750b57cec5SDimitry Andric .first; 14760b57cec5SDimitry Andric } 14770b57cec5SDimitry Andric 14780b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op, 14790b57cec5SDimitry Andric SelectionDAG &DAG) const { 14800b57cec5SDimitry Andric // Non-zero depths are not supported by WebAssembly currently. Use the 14810b57cec5SDimitry Andric // legalizer's default expansion, which is to return 0 (what this function is 14820b57cec5SDimitry Andric // documented to do). 14830b57cec5SDimitry Andric if (Op.getConstantOperandVal(0) > 0) 14840b57cec5SDimitry Andric return SDValue(); 14850b57cec5SDimitry Andric 14860b57cec5SDimitry Andric DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true); 14870b57cec5SDimitry Andric EVT VT = Op.getValueType(); 14888bcb0991SDimitry Andric Register FP = 14890b57cec5SDimitry Andric Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); 14900b57cec5SDimitry Andric return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT); 14910b57cec5SDimitry Andric } 14920b57cec5SDimitry Andric 1493e8d8bef9SDimitry Andric SDValue 1494e8d8bef9SDimitry Andric WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, 1495e8d8bef9SDimitry Andric SelectionDAG &DAG) const { 1496e8d8bef9SDimitry Andric SDLoc DL(Op); 1497e8d8bef9SDimitry Andric const auto *GA = cast<GlobalAddressSDNode>(Op); 1498e8d8bef9SDimitry Andric MVT PtrVT = getPointerTy(DAG.getDataLayout()); 1499e8d8bef9SDimitry Andric 1500e8d8bef9SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 1501e8d8bef9SDimitry Andric if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory()) 1502e8d8bef9SDimitry Andric report_fatal_error("cannot use thread-local storage without bulk memory", 1503e8d8bef9SDimitry Andric false); 1504e8d8bef9SDimitry Andric 1505e8d8bef9SDimitry Andric const GlobalValue *GV = GA->getGlobal(); 1506e8d8bef9SDimitry Andric 1507e8d8bef9SDimitry Andric // Currently Emscripten does not support dynamic linking with threads. 1508e8d8bef9SDimitry Andric // Therefore, if we have thread-local storage, only the local-exec model 1509e8d8bef9SDimitry Andric // is possible. 1510e8d8bef9SDimitry Andric // TODO: remove this and implement proper TLS models once Emscripten 1511e8d8bef9SDimitry Andric // supports dynamic linking with threads. 1512e8d8bef9SDimitry Andric if (GV->getThreadLocalMode() != GlobalValue::LocalExecTLSModel && 1513e8d8bef9SDimitry Andric !Subtarget->getTargetTriple().isOSEmscripten()) { 1514e8d8bef9SDimitry Andric report_fatal_error("only -ftls-model=local-exec is supported for now on " 1515e8d8bef9SDimitry Andric "non-Emscripten OSes: variable " + 1516e8d8bef9SDimitry Andric GV->getName(), 1517e8d8bef9SDimitry Andric false); 1518e8d8bef9SDimitry Andric } 1519e8d8bef9SDimitry Andric 1520e8d8bef9SDimitry Andric auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 1521e8d8bef9SDimitry Andric : WebAssembly::GLOBAL_GET_I32; 1522e8d8bef9SDimitry Andric const char *BaseName = MF.createExternalSymbolName("__tls_base"); 1523e8d8bef9SDimitry Andric 1524e8d8bef9SDimitry Andric SDValue BaseAddr( 1525e8d8bef9SDimitry Andric DAG.getMachineNode(GlobalGet, DL, PtrVT, 1526e8d8bef9SDimitry Andric DAG.getTargetExternalSymbol(BaseName, PtrVT)), 1527e8d8bef9SDimitry Andric 0); 1528e8d8bef9SDimitry Andric 1529e8d8bef9SDimitry Andric SDValue TLSOffset = DAG.getTargetGlobalAddress( 1530e8d8bef9SDimitry Andric GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL); 1531e8d8bef9SDimitry Andric SDValue SymAddr = DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, TLSOffset); 1532e8d8bef9SDimitry Andric 1533e8d8bef9SDimitry Andric return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr); 1534e8d8bef9SDimitry Andric } 1535e8d8bef9SDimitry Andric 15360b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, 15370b57cec5SDimitry Andric SelectionDAG &DAG) const { 15380b57cec5SDimitry Andric SDLoc DL(Op); 15390b57cec5SDimitry Andric const auto *GA = cast<GlobalAddressSDNode>(Op); 15400b57cec5SDimitry Andric EVT VT = Op.getValueType(); 15410b57cec5SDimitry Andric assert(GA->getTargetFlags() == 0 && 15420b57cec5SDimitry Andric "Unexpected target flags on generic GlobalAddressSDNode"); 1543*fe6060f1SDimitry Andric if (!WebAssembly::isValidAddressSpace(GA->getAddressSpace())) 1544*fe6060f1SDimitry Andric fail(DL, DAG, "Invalid address space for WebAssembly target"); 15450b57cec5SDimitry Andric 15460b57cec5SDimitry Andric unsigned OperandFlags = 0; 15470b57cec5SDimitry Andric if (isPositionIndependent()) { 15480b57cec5SDimitry Andric const GlobalValue *GV = GA->getGlobal(); 15490b57cec5SDimitry Andric if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) { 15500b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 15510b57cec5SDimitry Andric MVT PtrVT = getPointerTy(MF.getDataLayout()); 15520b57cec5SDimitry Andric const char *BaseName; 15530b57cec5SDimitry Andric if (GV->getValueType()->isFunctionTy()) { 15540b57cec5SDimitry Andric BaseName = MF.createExternalSymbolName("__table_base"); 15550b57cec5SDimitry Andric OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL; 15560b57cec5SDimitry Andric } 15570b57cec5SDimitry Andric else { 15580b57cec5SDimitry Andric BaseName = MF.createExternalSymbolName("__memory_base"); 15590b57cec5SDimitry Andric OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL; 15600b57cec5SDimitry Andric } 15610b57cec5SDimitry Andric SDValue BaseAddr = 15620b57cec5SDimitry Andric DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, 15630b57cec5SDimitry Andric DAG.getTargetExternalSymbol(BaseName, PtrVT)); 15640b57cec5SDimitry Andric 15650b57cec5SDimitry Andric SDValue SymAddr = DAG.getNode( 15660b57cec5SDimitry Andric WebAssemblyISD::WrapperPIC, DL, VT, 15670b57cec5SDimitry Andric DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(), 15680b57cec5SDimitry Andric OperandFlags)); 15690b57cec5SDimitry Andric 15700b57cec5SDimitry Andric return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr); 15710b57cec5SDimitry Andric } else { 15720b57cec5SDimitry Andric OperandFlags = WebAssemblyII::MO_GOT; 15730b57cec5SDimitry Andric } 15740b57cec5SDimitry Andric } 15750b57cec5SDimitry Andric 15760b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 15770b57cec5SDimitry Andric DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, 15780b57cec5SDimitry Andric GA->getOffset(), OperandFlags)); 15790b57cec5SDimitry Andric } 15800b57cec5SDimitry Andric 15810b57cec5SDimitry Andric SDValue 15820b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op, 15830b57cec5SDimitry Andric SelectionDAG &DAG) const { 15840b57cec5SDimitry Andric SDLoc DL(Op); 15850b57cec5SDimitry Andric const auto *ES = cast<ExternalSymbolSDNode>(Op); 15860b57cec5SDimitry Andric EVT VT = Op.getValueType(); 15870b57cec5SDimitry Andric assert(ES->getTargetFlags() == 0 && 15880b57cec5SDimitry Andric "Unexpected target flags on generic ExternalSymbolSDNode"); 15890b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 15900b57cec5SDimitry Andric DAG.getTargetExternalSymbol(ES->getSymbol(), VT)); 15910b57cec5SDimitry Andric } 15920b57cec5SDimitry Andric 15930b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op, 15940b57cec5SDimitry Andric SelectionDAG &DAG) const { 15950b57cec5SDimitry Andric // There's no need for a Wrapper node because we always incorporate a jump 15960b57cec5SDimitry Andric // table operand into a BR_TABLE instruction, rather than ever 15970b57cec5SDimitry Andric // materializing it in a register. 15980b57cec5SDimitry Andric const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); 15990b57cec5SDimitry Andric return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(), 16000b57cec5SDimitry Andric JT->getTargetFlags()); 16010b57cec5SDimitry Andric } 16020b57cec5SDimitry Andric 16030b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, 16040b57cec5SDimitry Andric SelectionDAG &DAG) const { 16050b57cec5SDimitry Andric SDLoc DL(Op); 16060b57cec5SDimitry Andric SDValue Chain = Op.getOperand(0); 16070b57cec5SDimitry Andric const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1)); 16080b57cec5SDimitry Andric SDValue Index = Op.getOperand(2); 16090b57cec5SDimitry Andric assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags"); 16100b57cec5SDimitry Andric 16110b57cec5SDimitry Andric SmallVector<SDValue, 8> Ops; 16120b57cec5SDimitry Andric Ops.push_back(Chain); 16130b57cec5SDimitry Andric Ops.push_back(Index); 16140b57cec5SDimitry Andric 16150b57cec5SDimitry Andric MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo(); 16160b57cec5SDimitry Andric const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; 16170b57cec5SDimitry Andric 16180b57cec5SDimitry Andric // Add an operand for each case. 16190b57cec5SDimitry Andric for (auto MBB : MBBs) 16200b57cec5SDimitry Andric Ops.push_back(DAG.getBasicBlock(MBB)); 16210b57cec5SDimitry Andric 16225ffd83dbSDimitry Andric // Add the first MBB as a dummy default target for now. This will be replaced 16235ffd83dbSDimitry Andric // with the proper default target (and the preceding range check eliminated) 16245ffd83dbSDimitry Andric // if possible by WebAssemblyFixBrTableDefaults. 16255ffd83dbSDimitry Andric Ops.push_back(DAG.getBasicBlock(*MBBs.begin())); 16260b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops); 16270b57cec5SDimitry Andric } 16280b57cec5SDimitry Andric 16290b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, 16300b57cec5SDimitry Andric SelectionDAG &DAG) const { 16310b57cec5SDimitry Andric SDLoc DL(Op); 16320b57cec5SDimitry Andric EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); 16330b57cec5SDimitry Andric 16340b57cec5SDimitry Andric auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>(); 16350b57cec5SDimitry Andric const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 16360b57cec5SDimitry Andric 16370b57cec5SDimitry Andric SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL, 16380b57cec5SDimitry Andric MFI->getVarargBufferVreg(), PtrVT); 16390b57cec5SDimitry Andric return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1), 1640e8d8bef9SDimitry Andric MachinePointerInfo(SV)); 1641e8d8bef9SDimitry Andric } 1642e8d8bef9SDimitry Andric 1643e8d8bef9SDimitry Andric static SDValue getCppExceptionSymNode(SDValue Op, unsigned TagIndex, 1644e8d8bef9SDimitry Andric SelectionDAG &DAG) { 1645e8d8bef9SDimitry Andric // We only support C++ exceptions for now 1646e8d8bef9SDimitry Andric int Tag = 1647e8d8bef9SDimitry Andric cast<ConstantSDNode>(Op.getOperand(TagIndex).getNode())->getZExtValue(); 1648e8d8bef9SDimitry Andric if (Tag != WebAssembly::CPP_EXCEPTION) 1649e8d8bef9SDimitry Andric llvm_unreachable("Invalid tag: We only support C++ exceptions for now"); 1650e8d8bef9SDimitry Andric auto &MF = DAG.getMachineFunction(); 1651e8d8bef9SDimitry Andric const auto &TLI = DAG.getTargetLoweringInfo(); 1652e8d8bef9SDimitry Andric MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); 1653e8d8bef9SDimitry Andric const char *SymName = MF.createExternalSymbolName("__cpp_exception"); 1654e8d8bef9SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, SDLoc(Op), PtrVT, 1655e8d8bef9SDimitry Andric DAG.getTargetExternalSymbol(SymName, PtrVT)); 16560b57cec5SDimitry Andric } 16570b57cec5SDimitry Andric 16580b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, 16590b57cec5SDimitry Andric SelectionDAG &DAG) const { 16600b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 16610b57cec5SDimitry Andric unsigned IntNo; 16620b57cec5SDimitry Andric switch (Op.getOpcode()) { 16630b57cec5SDimitry Andric case ISD::INTRINSIC_VOID: 16640b57cec5SDimitry Andric case ISD::INTRINSIC_W_CHAIN: 16650b57cec5SDimitry Andric IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); 16660b57cec5SDimitry Andric break; 16670b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 16680b57cec5SDimitry Andric IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 16690b57cec5SDimitry Andric break; 16700b57cec5SDimitry Andric default: 16710b57cec5SDimitry Andric llvm_unreachable("Invalid intrinsic"); 16720b57cec5SDimitry Andric } 16730b57cec5SDimitry Andric SDLoc DL(Op); 16740b57cec5SDimitry Andric 16750b57cec5SDimitry Andric switch (IntNo) { 16760b57cec5SDimitry Andric default: 16770b57cec5SDimitry Andric return SDValue(); // Don't custom lower most intrinsics. 16780b57cec5SDimitry Andric 16790b57cec5SDimitry Andric case Intrinsic::wasm_lsda: { 16800b57cec5SDimitry Andric EVT VT = Op.getValueType(); 16810b57cec5SDimitry Andric const TargetLowering &TLI = DAG.getTargetLoweringInfo(); 16820b57cec5SDimitry Andric MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); 16830b57cec5SDimitry Andric auto &Context = MF.getMMI().getContext(); 16840b57cec5SDimitry Andric MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") + 16850b57cec5SDimitry Andric Twine(MF.getFunctionNumber())); 16860b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 16870b57cec5SDimitry Andric DAG.getMCSymbol(S, PtrVT)); 16880b57cec5SDimitry Andric } 16890b57cec5SDimitry Andric 16900b57cec5SDimitry Andric case Intrinsic::wasm_throw: { 1691e8d8bef9SDimitry Andric SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); 16920b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::THROW, DL, 16930b57cec5SDimitry Andric MVT::Other, // outchain type 16940b57cec5SDimitry Andric { 16950b57cec5SDimitry Andric Op.getOperand(0), // inchain 16960b57cec5SDimitry Andric SymNode, // exception symbol 16970b57cec5SDimitry Andric Op.getOperand(3) // thrown value 16980b57cec5SDimitry Andric }); 16990b57cec5SDimitry Andric } 17005ffd83dbSDimitry Andric 1701e8d8bef9SDimitry Andric case Intrinsic::wasm_catch: { 1702e8d8bef9SDimitry Andric SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); 1703e8d8bef9SDimitry Andric return DAG.getNode(WebAssemblyISD::CATCH, DL, 1704e8d8bef9SDimitry Andric { 1705e8d8bef9SDimitry Andric MVT::i32, // outchain type 1706e8d8bef9SDimitry Andric MVT::Other // return value 1707e8d8bef9SDimitry Andric }, 1708e8d8bef9SDimitry Andric { 1709e8d8bef9SDimitry Andric Op.getOperand(0), // inchain 1710e8d8bef9SDimitry Andric SymNode // exception symbol 1711e8d8bef9SDimitry Andric }); 1712e8d8bef9SDimitry Andric } 1713e8d8bef9SDimitry Andric 17145ffd83dbSDimitry Andric case Intrinsic::wasm_shuffle: { 17155ffd83dbSDimitry Andric // Drop in-chain and replace undefs, but otherwise pass through unchanged 17165ffd83dbSDimitry Andric SDValue Ops[18]; 17175ffd83dbSDimitry Andric size_t OpIdx = 0; 17185ffd83dbSDimitry Andric Ops[OpIdx++] = Op.getOperand(1); 17195ffd83dbSDimitry Andric Ops[OpIdx++] = Op.getOperand(2); 17205ffd83dbSDimitry Andric while (OpIdx < 18) { 17215ffd83dbSDimitry Andric const SDValue &MaskIdx = Op.getOperand(OpIdx + 1); 17225ffd83dbSDimitry Andric if (MaskIdx.isUndef() || 17235ffd83dbSDimitry Andric cast<ConstantSDNode>(MaskIdx.getNode())->getZExtValue() >= 32) { 17245ffd83dbSDimitry Andric Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32); 17255ffd83dbSDimitry Andric } else { 17265ffd83dbSDimitry Andric Ops[OpIdx++] = MaskIdx; 17275ffd83dbSDimitry Andric } 17285ffd83dbSDimitry Andric } 17295ffd83dbSDimitry Andric return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); 17305ffd83dbSDimitry Andric } 17310b57cec5SDimitry Andric } 17320b57cec5SDimitry Andric } 17330b57cec5SDimitry Andric 17340b57cec5SDimitry Andric SDValue 17350b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op, 17360b57cec5SDimitry Andric SelectionDAG &DAG) const { 17370b57cec5SDimitry Andric SDLoc DL(Op); 17380b57cec5SDimitry Andric // If sign extension operations are disabled, allow sext_inreg only if operand 17395ffd83dbSDimitry Andric // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign 17405ffd83dbSDimitry Andric // extension operations, but allowing sext_inreg in this context lets us have 17415ffd83dbSDimitry Andric // simple patterns to select extract_lane_s instructions. Expanding sext_inreg 17425ffd83dbSDimitry Andric // everywhere would be simpler in this file, but would necessitate large and 17435ffd83dbSDimitry Andric // brittle patterns to undo the expansion and select extract_lane_s 17445ffd83dbSDimitry Andric // instructions. 17450b57cec5SDimitry Andric assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128()); 17465ffd83dbSDimitry Andric if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT) 17475ffd83dbSDimitry Andric return SDValue(); 17485ffd83dbSDimitry Andric 17490b57cec5SDimitry Andric const SDValue &Extract = Op.getOperand(0); 17500b57cec5SDimitry Andric MVT VecT = Extract.getOperand(0).getSimpleValueType(); 17515ffd83dbSDimitry Andric if (VecT.getVectorElementType().getSizeInBits() > 32) 17525ffd83dbSDimitry Andric return SDValue(); 17535ffd83dbSDimitry Andric MVT ExtractedLaneT = 17545ffd83dbSDimitry Andric cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT(); 17550b57cec5SDimitry Andric MVT ExtractedVecT = 17560b57cec5SDimitry Andric MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits()); 17570b57cec5SDimitry Andric if (ExtractedVecT == VecT) 17580b57cec5SDimitry Andric return Op; 17595ffd83dbSDimitry Andric 17600b57cec5SDimitry Andric // Bitcast vector to appropriate type to ensure ISel pattern coverage 17615ffd83dbSDimitry Andric const SDNode *Index = Extract.getOperand(1).getNode(); 17625ffd83dbSDimitry Andric if (!isa<ConstantSDNode>(Index)) 17635ffd83dbSDimitry Andric return SDValue(); 17645ffd83dbSDimitry Andric unsigned IndexVal = cast<ConstantSDNode>(Index)->getZExtValue(); 17650b57cec5SDimitry Andric unsigned Scale = 17660b57cec5SDimitry Andric ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements(); 17670b57cec5SDimitry Andric assert(Scale > 1); 17680b57cec5SDimitry Andric SDValue NewIndex = 17695ffd83dbSDimitry Andric DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0)); 17700b57cec5SDimitry Andric SDValue NewExtract = DAG.getNode( 17710b57cec5SDimitry Andric ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(), 17720b57cec5SDimitry Andric DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex); 17735ffd83dbSDimitry Andric return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract, 17745ffd83dbSDimitry Andric Op.getOperand(1)); 17750b57cec5SDimitry Andric } 17760b57cec5SDimitry Andric 17770b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op, 17780b57cec5SDimitry Andric SelectionDAG &DAG) const { 17790b57cec5SDimitry Andric SDLoc DL(Op); 17800b57cec5SDimitry Andric const EVT VecT = Op.getValueType(); 17810b57cec5SDimitry Andric const EVT LaneT = Op.getOperand(0).getValueType(); 17820b57cec5SDimitry Andric const size_t Lanes = Op.getNumOperands(); 17835ffd83dbSDimitry Andric bool CanSwizzle = VecT == MVT::v16i8; 17848bcb0991SDimitry Andric 17858bcb0991SDimitry Andric // BUILD_VECTORs are lowered to the instruction that initializes the highest 17868bcb0991SDimitry Andric // possible number of lanes at once followed by a sequence of replace_lane 17878bcb0991SDimitry Andric // instructions to individually initialize any remaining lanes. 17888bcb0991SDimitry Andric 17898bcb0991SDimitry Andric // TODO: Tune this. For example, lanewise swizzling is very expensive, so 17908bcb0991SDimitry Andric // swizzled lanes should be given greater weight. 17918bcb0991SDimitry Andric 1792*fe6060f1SDimitry Andric // TODO: Investigate looping rather than always extracting/replacing specific 1793*fe6060f1SDimitry Andric // lanes to fill gaps. 17948bcb0991SDimitry Andric 17950b57cec5SDimitry Andric auto IsConstant = [](const SDValue &V) { 17960b57cec5SDimitry Andric return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP; 17970b57cec5SDimitry Andric }; 17980b57cec5SDimitry Andric 17998bcb0991SDimitry Andric // Returns the source vector and index vector pair if they exist. Checks for: 18008bcb0991SDimitry Andric // (extract_vector_elt 18018bcb0991SDimitry Andric // $src, 18028bcb0991SDimitry Andric // (sign_extend_inreg (extract_vector_elt $indices, $i)) 18038bcb0991SDimitry Andric // ) 18048bcb0991SDimitry Andric auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) { 18058bcb0991SDimitry Andric auto Bail = std::make_pair(SDValue(), SDValue()); 18068bcb0991SDimitry Andric if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 18078bcb0991SDimitry Andric return Bail; 18088bcb0991SDimitry Andric const SDValue &SwizzleSrc = Lane->getOperand(0); 18098bcb0991SDimitry Andric const SDValue &IndexExt = Lane->getOperand(1); 18108bcb0991SDimitry Andric if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG) 18118bcb0991SDimitry Andric return Bail; 18128bcb0991SDimitry Andric const SDValue &Index = IndexExt->getOperand(0); 18138bcb0991SDimitry Andric if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 18148bcb0991SDimitry Andric return Bail; 18158bcb0991SDimitry Andric const SDValue &SwizzleIndices = Index->getOperand(0); 18168bcb0991SDimitry Andric if (SwizzleSrc.getValueType() != MVT::v16i8 || 18178bcb0991SDimitry Andric SwizzleIndices.getValueType() != MVT::v16i8 || 18188bcb0991SDimitry Andric Index->getOperand(1)->getOpcode() != ISD::Constant || 18198bcb0991SDimitry Andric Index->getConstantOperandVal(1) != I) 18208bcb0991SDimitry Andric return Bail; 18218bcb0991SDimitry Andric return std::make_pair(SwizzleSrc, SwizzleIndices); 18228bcb0991SDimitry Andric }; 18238bcb0991SDimitry Andric 1824*fe6060f1SDimitry Andric // If the lane is extracted from another vector at a constant index, return 1825*fe6060f1SDimitry Andric // that vector. The source vector must not have more lanes than the dest 1826*fe6060f1SDimitry Andric // because the shufflevector indices are in terms of the destination lanes and 1827*fe6060f1SDimitry Andric // would not be able to address the smaller individual source lanes. 1828*fe6060f1SDimitry Andric auto GetShuffleSrc = [&](const SDValue &Lane) { 1829*fe6060f1SDimitry Andric if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 1830*fe6060f1SDimitry Andric return SDValue(); 1831*fe6060f1SDimitry Andric if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode())) 1832*fe6060f1SDimitry Andric return SDValue(); 1833*fe6060f1SDimitry Andric if (Lane->getOperand(0).getValueType().getVectorNumElements() > 1834*fe6060f1SDimitry Andric VecT.getVectorNumElements()) 1835*fe6060f1SDimitry Andric return SDValue(); 1836*fe6060f1SDimitry Andric return Lane->getOperand(0); 1837*fe6060f1SDimitry Andric }; 1838*fe6060f1SDimitry Andric 18398bcb0991SDimitry Andric using ValueEntry = std::pair<SDValue, size_t>; 18408bcb0991SDimitry Andric SmallVector<ValueEntry, 16> SplatValueCounts; 18418bcb0991SDimitry Andric 18428bcb0991SDimitry Andric using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>; 18438bcb0991SDimitry Andric SmallVector<SwizzleEntry, 16> SwizzleCounts; 18448bcb0991SDimitry Andric 1845*fe6060f1SDimitry Andric using ShuffleEntry = std::pair<SDValue, size_t>; 1846*fe6060f1SDimitry Andric SmallVector<ShuffleEntry, 16> ShuffleCounts; 1847*fe6060f1SDimitry Andric 18488bcb0991SDimitry Andric auto AddCount = [](auto &Counts, const auto &Val) { 1849e8d8bef9SDimitry Andric auto CountIt = 1850e8d8bef9SDimitry Andric llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; }); 18518bcb0991SDimitry Andric if (CountIt == Counts.end()) { 18528bcb0991SDimitry Andric Counts.emplace_back(Val, 1); 18530b57cec5SDimitry Andric } else { 18540b57cec5SDimitry Andric CountIt->second++; 18550b57cec5SDimitry Andric } 18568bcb0991SDimitry Andric }; 18570b57cec5SDimitry Andric 18588bcb0991SDimitry Andric auto GetMostCommon = [](auto &Counts) { 18598bcb0991SDimitry Andric auto CommonIt = 18608bcb0991SDimitry Andric std::max_element(Counts.begin(), Counts.end(), 18618bcb0991SDimitry Andric [](auto A, auto B) { return A.second < B.second; }); 18628bcb0991SDimitry Andric assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector"); 18638bcb0991SDimitry Andric return *CommonIt; 18648bcb0991SDimitry Andric }; 18658bcb0991SDimitry Andric 18668bcb0991SDimitry Andric size_t NumConstantLanes = 0; 18678bcb0991SDimitry Andric 18688bcb0991SDimitry Andric // Count eligible lanes for each type of vector creation op 18698bcb0991SDimitry Andric for (size_t I = 0; I < Lanes; ++I) { 18708bcb0991SDimitry Andric const SDValue &Lane = Op->getOperand(I); 18718bcb0991SDimitry Andric if (Lane.isUndef()) 18728bcb0991SDimitry Andric continue; 18738bcb0991SDimitry Andric 18748bcb0991SDimitry Andric AddCount(SplatValueCounts, Lane); 18758bcb0991SDimitry Andric 1876*fe6060f1SDimitry Andric if (IsConstant(Lane)) 18778bcb0991SDimitry Andric NumConstantLanes++; 1878*fe6060f1SDimitry Andric if (auto ShuffleSrc = GetShuffleSrc(Lane)) 1879*fe6060f1SDimitry Andric AddCount(ShuffleCounts, ShuffleSrc); 1880*fe6060f1SDimitry Andric if (CanSwizzle) { 18818bcb0991SDimitry Andric auto SwizzleSrcs = GetSwizzleSrcs(I, Lane); 18828bcb0991SDimitry Andric if (SwizzleSrcs.first) 18838bcb0991SDimitry Andric AddCount(SwizzleCounts, SwizzleSrcs); 18848bcb0991SDimitry Andric } 18858bcb0991SDimitry Andric } 18868bcb0991SDimitry Andric 18878bcb0991SDimitry Andric SDValue SplatValue; 18888bcb0991SDimitry Andric size_t NumSplatLanes; 18898bcb0991SDimitry Andric std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts); 18908bcb0991SDimitry Andric 18918bcb0991SDimitry Andric SDValue SwizzleSrc; 18928bcb0991SDimitry Andric SDValue SwizzleIndices; 18938bcb0991SDimitry Andric size_t NumSwizzleLanes = 0; 18948bcb0991SDimitry Andric if (SwizzleCounts.size()) 18958bcb0991SDimitry Andric std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices), 18968bcb0991SDimitry Andric NumSwizzleLanes) = GetMostCommon(SwizzleCounts); 18978bcb0991SDimitry Andric 1898*fe6060f1SDimitry Andric // Shuffles can draw from up to two vectors, so find the two most common 1899*fe6060f1SDimitry Andric // sources. 1900*fe6060f1SDimitry Andric SDValue ShuffleSrc1, ShuffleSrc2; 1901*fe6060f1SDimitry Andric size_t NumShuffleLanes = 0; 1902*fe6060f1SDimitry Andric if (ShuffleCounts.size()) { 1903*fe6060f1SDimitry Andric std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts); 1904*fe6060f1SDimitry Andric ShuffleCounts.erase(std::remove_if(ShuffleCounts.begin(), 1905*fe6060f1SDimitry Andric ShuffleCounts.end(), 1906*fe6060f1SDimitry Andric [&](const auto &Pair) { 1907*fe6060f1SDimitry Andric return Pair.first == ShuffleSrc1; 1908*fe6060f1SDimitry Andric }), 1909*fe6060f1SDimitry Andric ShuffleCounts.end()); 1910*fe6060f1SDimitry Andric } 1911*fe6060f1SDimitry Andric if (ShuffleCounts.size()) { 1912*fe6060f1SDimitry Andric size_t AdditionalShuffleLanes; 1913*fe6060f1SDimitry Andric std::tie(ShuffleSrc2, AdditionalShuffleLanes) = 1914*fe6060f1SDimitry Andric GetMostCommon(ShuffleCounts); 1915*fe6060f1SDimitry Andric NumShuffleLanes += AdditionalShuffleLanes; 1916*fe6060f1SDimitry Andric } 1917*fe6060f1SDimitry Andric 19188bcb0991SDimitry Andric // Predicate returning true if the lane is properly initialized by the 19198bcb0991SDimitry Andric // original instruction 19208bcb0991SDimitry Andric std::function<bool(size_t, const SDValue &)> IsLaneConstructed; 19218bcb0991SDimitry Andric SDValue Result; 1922*fe6060f1SDimitry Andric // Prefer swizzles over shuffles over vector consts over splats 1923*fe6060f1SDimitry Andric if (NumSwizzleLanes >= NumShuffleLanes && 1924*fe6060f1SDimitry Andric NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) { 19258bcb0991SDimitry Andric Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc, 19268bcb0991SDimitry Andric SwizzleIndices); 19278bcb0991SDimitry Andric auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices); 19288bcb0991SDimitry Andric IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) { 19298bcb0991SDimitry Andric return Swizzled == GetSwizzleSrcs(I, Lane); 19308bcb0991SDimitry Andric }; 1931*fe6060f1SDimitry Andric } else if (NumShuffleLanes >= NumConstantLanes && 1932*fe6060f1SDimitry Andric NumShuffleLanes >= NumSplatLanes) { 1933*fe6060f1SDimitry Andric size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8; 1934*fe6060f1SDimitry Andric size_t DestLaneCount = VecT.getVectorNumElements(); 1935*fe6060f1SDimitry Andric size_t Scale1 = 1; 1936*fe6060f1SDimitry Andric size_t Scale2 = 1; 1937*fe6060f1SDimitry Andric SDValue Src1 = ShuffleSrc1; 1938*fe6060f1SDimitry Andric SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT); 1939*fe6060f1SDimitry Andric if (Src1.getValueType() != VecT) { 1940*fe6060f1SDimitry Andric size_t LaneSize = 1941*fe6060f1SDimitry Andric Src1.getValueType().getVectorElementType().getFixedSizeInBits() / 8; 1942*fe6060f1SDimitry Andric assert(LaneSize > DestLaneSize); 1943*fe6060f1SDimitry Andric Scale1 = LaneSize / DestLaneSize; 1944*fe6060f1SDimitry Andric Src1 = DAG.getBitcast(VecT, Src1); 1945*fe6060f1SDimitry Andric } 1946*fe6060f1SDimitry Andric if (Src2.getValueType() != VecT) { 1947*fe6060f1SDimitry Andric size_t LaneSize = 1948*fe6060f1SDimitry Andric Src2.getValueType().getVectorElementType().getFixedSizeInBits() / 8; 1949*fe6060f1SDimitry Andric assert(LaneSize > DestLaneSize); 1950*fe6060f1SDimitry Andric Scale2 = LaneSize / DestLaneSize; 1951*fe6060f1SDimitry Andric Src2 = DAG.getBitcast(VecT, Src2); 1952*fe6060f1SDimitry Andric } 1953*fe6060f1SDimitry Andric 1954*fe6060f1SDimitry Andric int Mask[16]; 1955*fe6060f1SDimitry Andric assert(DestLaneCount <= 16); 1956*fe6060f1SDimitry Andric for (size_t I = 0; I < DestLaneCount; ++I) { 1957*fe6060f1SDimitry Andric const SDValue &Lane = Op->getOperand(I); 1958*fe6060f1SDimitry Andric SDValue Src = GetShuffleSrc(Lane); 1959*fe6060f1SDimitry Andric if (Src == ShuffleSrc1) { 1960*fe6060f1SDimitry Andric Mask[I] = Lane->getConstantOperandVal(1) * Scale1; 1961*fe6060f1SDimitry Andric } else if (Src && Src == ShuffleSrc2) { 1962*fe6060f1SDimitry Andric Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2; 1963*fe6060f1SDimitry Andric } else { 1964*fe6060f1SDimitry Andric Mask[I] = -1; 1965*fe6060f1SDimitry Andric } 1966*fe6060f1SDimitry Andric } 1967*fe6060f1SDimitry Andric ArrayRef<int> MaskRef(Mask, DestLaneCount); 1968*fe6060f1SDimitry Andric Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef); 1969*fe6060f1SDimitry Andric IsLaneConstructed = [&](size_t, const SDValue &Lane) { 1970*fe6060f1SDimitry Andric auto Src = GetShuffleSrc(Lane); 1971*fe6060f1SDimitry Andric return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2); 1972*fe6060f1SDimitry Andric }; 1973*fe6060f1SDimitry Andric } else if (NumConstantLanes >= NumSplatLanes) { 19740b57cec5SDimitry Andric SmallVector<SDValue, 16> ConstLanes; 19750b57cec5SDimitry Andric for (const SDValue &Lane : Op->op_values()) { 19760b57cec5SDimitry Andric if (IsConstant(Lane)) { 19770b57cec5SDimitry Andric ConstLanes.push_back(Lane); 19780b57cec5SDimitry Andric } else if (LaneT.isFloatingPoint()) { 19790b57cec5SDimitry Andric ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT)); 19800b57cec5SDimitry Andric } else { 19810b57cec5SDimitry Andric ConstLanes.push_back(DAG.getConstant(0, DL, LaneT)); 19820b57cec5SDimitry Andric } 19830b57cec5SDimitry Andric } 19848bcb0991SDimitry Andric Result = DAG.getBuildVector(VecT, DL, ConstLanes); 1985e8d8bef9SDimitry Andric IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) { 19868bcb0991SDimitry Andric return IsConstant(Lane); 19878bcb0991SDimitry Andric }; 1988e8d8bef9SDimitry Andric } else { 19898bcb0991SDimitry Andric // Use a splat, but possibly a load_splat 19908bcb0991SDimitry Andric LoadSDNode *SplattedLoad; 19915ffd83dbSDimitry Andric if ((SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) && 19928bcb0991SDimitry Andric SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) { 1993480093f4SDimitry Andric Result = DAG.getMemIntrinsicNode( 1994480093f4SDimitry Andric WebAssemblyISD::LOAD_SPLAT, DL, DAG.getVTList(VecT), 1995480093f4SDimitry Andric {SplattedLoad->getChain(), SplattedLoad->getBasePtr(), 1996480093f4SDimitry Andric SplattedLoad->getOffset()}, 1997480093f4SDimitry Andric SplattedLoad->getMemoryVT(), SplattedLoad->getMemOperand()); 19988bcb0991SDimitry Andric } else { 19998bcb0991SDimitry Andric Result = DAG.getSplatBuildVector(VecT, DL, SplatValue); 20008bcb0991SDimitry Andric } 2001e8d8bef9SDimitry Andric IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) { 20028bcb0991SDimitry Andric return Lane == SplatValue; 20038bcb0991SDimitry Andric }; 20048bcb0991SDimitry Andric } 20058bcb0991SDimitry Andric 2006e8d8bef9SDimitry Andric assert(Result); 2007e8d8bef9SDimitry Andric assert(IsLaneConstructed); 2008e8d8bef9SDimitry Andric 20098bcb0991SDimitry Andric // Add replace_lane instructions for any unhandled values 20100b57cec5SDimitry Andric for (size_t I = 0; I < Lanes; ++I) { 20110b57cec5SDimitry Andric const SDValue &Lane = Op->getOperand(I); 20128bcb0991SDimitry Andric if (!Lane.isUndef() && !IsLaneConstructed(I, Lane)) 20130b57cec5SDimitry Andric Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane, 20140b57cec5SDimitry Andric DAG.getConstant(I, DL, MVT::i32)); 20150b57cec5SDimitry Andric } 20168bcb0991SDimitry Andric 20170b57cec5SDimitry Andric return Result; 20180b57cec5SDimitry Andric } 20190b57cec5SDimitry Andric 20200b57cec5SDimitry Andric SDValue 20210b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, 20220b57cec5SDimitry Andric SelectionDAG &DAG) const { 20230b57cec5SDimitry Andric SDLoc DL(Op); 20240b57cec5SDimitry Andric ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask(); 20250b57cec5SDimitry Andric MVT VecType = Op.getOperand(0).getSimpleValueType(); 20260b57cec5SDimitry Andric assert(VecType.is128BitVector() && "Unexpected shuffle vector type"); 20270b57cec5SDimitry Andric size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8; 20280b57cec5SDimitry Andric 20290b57cec5SDimitry Andric // Space for two vector args and sixteen mask indices 20300b57cec5SDimitry Andric SDValue Ops[18]; 20310b57cec5SDimitry Andric size_t OpIdx = 0; 20320b57cec5SDimitry Andric Ops[OpIdx++] = Op.getOperand(0); 20330b57cec5SDimitry Andric Ops[OpIdx++] = Op.getOperand(1); 20340b57cec5SDimitry Andric 20350b57cec5SDimitry Andric // Expand mask indices to byte indices and materialize them as operands 20360b57cec5SDimitry Andric for (int M : Mask) { 20370b57cec5SDimitry Andric for (size_t J = 0; J < LaneBytes; ++J) { 20380b57cec5SDimitry Andric // Lower undefs (represented by -1 in mask) to zero 20390b57cec5SDimitry Andric uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J; 20400b57cec5SDimitry Andric Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32); 20410b57cec5SDimitry Andric } 20420b57cec5SDimitry Andric } 20430b57cec5SDimitry Andric 20440b57cec5SDimitry Andric return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); 20450b57cec5SDimitry Andric } 20460b57cec5SDimitry Andric 2047480093f4SDimitry Andric SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op, 2048480093f4SDimitry Andric SelectionDAG &DAG) const { 2049480093f4SDimitry Andric SDLoc DL(Op); 2050*fe6060f1SDimitry Andric // The legalizer does not know how to expand the unsupported comparison modes 2051*fe6060f1SDimitry Andric // of i64x2 vectors, so we manually unroll them here. 2052480093f4SDimitry Andric assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64); 2053480093f4SDimitry Andric SmallVector<SDValue, 2> LHS, RHS; 2054480093f4SDimitry Andric DAG.ExtractVectorElements(Op->getOperand(0), LHS); 2055480093f4SDimitry Andric DAG.ExtractVectorElements(Op->getOperand(1), RHS); 2056480093f4SDimitry Andric const SDValue &CC = Op->getOperand(2); 2057480093f4SDimitry Andric auto MakeLane = [&](unsigned I) { 2058480093f4SDimitry Andric return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I], 2059480093f4SDimitry Andric DAG.getConstant(uint64_t(-1), DL, MVT::i64), 2060480093f4SDimitry Andric DAG.getConstant(uint64_t(0), DL, MVT::i64), CC); 2061480093f4SDimitry Andric }; 2062480093f4SDimitry Andric return DAG.getBuildVector(Op->getValueType(0), DL, 2063480093f4SDimitry Andric {MakeLane(0), MakeLane(1)}); 2064480093f4SDimitry Andric } 2065480093f4SDimitry Andric 20660b57cec5SDimitry Andric SDValue 20670b57cec5SDimitry Andric WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op, 20680b57cec5SDimitry Andric SelectionDAG &DAG) const { 20690b57cec5SDimitry Andric // Allow constant lane indices, expand variable lane indices 20700b57cec5SDimitry Andric SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode(); 20710b57cec5SDimitry Andric if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef()) 20720b57cec5SDimitry Andric return Op; 20730b57cec5SDimitry Andric else 20740b57cec5SDimitry Andric // Perform default expansion 20750b57cec5SDimitry Andric return SDValue(); 20760b57cec5SDimitry Andric } 20770b57cec5SDimitry Andric 20780b57cec5SDimitry Andric static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) { 20790b57cec5SDimitry Andric EVT LaneT = Op.getSimpleValueType().getVectorElementType(); 20800b57cec5SDimitry Andric // 32-bit and 64-bit unrolled shifts will have proper semantics 20810b57cec5SDimitry Andric if (LaneT.bitsGE(MVT::i32)) 20820b57cec5SDimitry Andric return DAG.UnrollVectorOp(Op.getNode()); 20830b57cec5SDimitry Andric // Otherwise mask the shift value to get proper semantics from 32-bit shift 20840b57cec5SDimitry Andric SDLoc DL(Op); 20855ffd83dbSDimitry Andric size_t NumLanes = Op.getSimpleValueType().getVectorNumElements(); 20865ffd83dbSDimitry Andric SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32); 20875ffd83dbSDimitry Andric unsigned ShiftOpcode = Op.getOpcode(); 20885ffd83dbSDimitry Andric SmallVector<SDValue, 16> ShiftedElements; 20895ffd83dbSDimitry Andric DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32); 20905ffd83dbSDimitry Andric SmallVector<SDValue, 16> ShiftElements; 20915ffd83dbSDimitry Andric DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32); 20925ffd83dbSDimitry Andric SmallVector<SDValue, 16> UnrolledOps; 20935ffd83dbSDimitry Andric for (size_t i = 0; i < NumLanes; ++i) { 20945ffd83dbSDimitry Andric SDValue MaskedShiftValue = 20955ffd83dbSDimitry Andric DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask); 20965ffd83dbSDimitry Andric SDValue ShiftedValue = ShiftedElements[i]; 20975ffd83dbSDimitry Andric if (ShiftOpcode == ISD::SRA) 20985ffd83dbSDimitry Andric ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32, 20995ffd83dbSDimitry Andric ShiftedValue, DAG.getValueType(LaneT)); 21005ffd83dbSDimitry Andric UnrolledOps.push_back( 21015ffd83dbSDimitry Andric DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue)); 21025ffd83dbSDimitry Andric } 21035ffd83dbSDimitry Andric return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps); 21040b57cec5SDimitry Andric } 21050b57cec5SDimitry Andric 21060b57cec5SDimitry Andric SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, 21070b57cec5SDimitry Andric SelectionDAG &DAG) const { 21080b57cec5SDimitry Andric SDLoc DL(Op); 21090b57cec5SDimitry Andric 21100b57cec5SDimitry Andric // Only manually lower vector shifts 21110b57cec5SDimitry Andric assert(Op.getSimpleValueType().isVector()); 21120b57cec5SDimitry Andric 21135ffd83dbSDimitry Andric auto ShiftVal = DAG.getSplatValue(Op.getOperand(1)); 21145ffd83dbSDimitry Andric if (!ShiftVal) 21150b57cec5SDimitry Andric return unrollVectorShift(Op, DAG); 21160b57cec5SDimitry Andric 21175ffd83dbSDimitry Andric // Use anyext because none of the high bits can affect the shift 21185ffd83dbSDimitry Andric ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32); 21190b57cec5SDimitry Andric 21200b57cec5SDimitry Andric unsigned Opcode; 21210b57cec5SDimitry Andric switch (Op.getOpcode()) { 21220b57cec5SDimitry Andric case ISD::SHL: 21230b57cec5SDimitry Andric Opcode = WebAssemblyISD::VEC_SHL; 21240b57cec5SDimitry Andric break; 21250b57cec5SDimitry Andric case ISD::SRA: 21260b57cec5SDimitry Andric Opcode = WebAssemblyISD::VEC_SHR_S; 21270b57cec5SDimitry Andric break; 21280b57cec5SDimitry Andric case ISD::SRL: 21290b57cec5SDimitry Andric Opcode = WebAssemblyISD::VEC_SHR_U; 21300b57cec5SDimitry Andric break; 21310b57cec5SDimitry Andric default: 21320b57cec5SDimitry Andric llvm_unreachable("unexpected opcode"); 21330b57cec5SDimitry Andric } 21345ffd83dbSDimitry Andric 21355ffd83dbSDimitry Andric return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal); 21360b57cec5SDimitry Andric } 21370b57cec5SDimitry Andric 2138*fe6060f1SDimitry Andric SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op, 2139*fe6060f1SDimitry Andric SelectionDAG &DAG) const { 2140*fe6060f1SDimitry Andric SDLoc DL(Op); 2141*fe6060f1SDimitry Andric EVT ResT = Op.getValueType(); 2142*fe6060f1SDimitry Andric EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT(); 2143*fe6060f1SDimitry Andric 2144*fe6060f1SDimitry Andric if ((ResT == MVT::i32 || ResT == MVT::i64) && 2145*fe6060f1SDimitry Andric (SatVT == MVT::i32 || SatVT == MVT::i64)) 2146*fe6060f1SDimitry Andric return Op; 2147*fe6060f1SDimitry Andric 2148*fe6060f1SDimitry Andric if (ResT == MVT::v4i32 && SatVT == MVT::i32) 2149*fe6060f1SDimitry Andric return Op; 2150*fe6060f1SDimitry Andric 2151*fe6060f1SDimitry Andric return SDValue(); 2152*fe6060f1SDimitry Andric } 2153*fe6060f1SDimitry Andric 21540b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 21555ffd83dbSDimitry Andric // Custom DAG combine hooks 21560b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 21575ffd83dbSDimitry Andric static SDValue 21585ffd83dbSDimitry Andric performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { 21595ffd83dbSDimitry Andric auto &DAG = DCI.DAG; 21605ffd83dbSDimitry Andric auto Shuffle = cast<ShuffleVectorSDNode>(N); 21615ffd83dbSDimitry Andric 21625ffd83dbSDimitry Andric // Hoist vector bitcasts that don't change the number of lanes out of unary 21635ffd83dbSDimitry Andric // shuffles, where they are less likely to get in the way of other combines. 21645ffd83dbSDimitry Andric // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) -> 21655ffd83dbSDimitry Andric // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask)))) 21665ffd83dbSDimitry Andric SDValue Bitcast = N->getOperand(0); 21675ffd83dbSDimitry Andric if (Bitcast.getOpcode() != ISD::BITCAST) 21685ffd83dbSDimitry Andric return SDValue(); 21695ffd83dbSDimitry Andric if (!N->getOperand(1).isUndef()) 21705ffd83dbSDimitry Andric return SDValue(); 21715ffd83dbSDimitry Andric SDValue CastOp = Bitcast.getOperand(0); 21725ffd83dbSDimitry Andric MVT SrcType = CastOp.getSimpleValueType(); 21735ffd83dbSDimitry Andric MVT DstType = Bitcast.getSimpleValueType(); 21745ffd83dbSDimitry Andric if (!SrcType.is128BitVector() || 21755ffd83dbSDimitry Andric SrcType.getVectorNumElements() != DstType.getVectorNumElements()) 21765ffd83dbSDimitry Andric return SDValue(); 21775ffd83dbSDimitry Andric SDValue NewShuffle = DAG.getVectorShuffle( 21785ffd83dbSDimitry Andric SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask()); 21795ffd83dbSDimitry Andric return DAG.getBitcast(DstType, NewShuffle); 21805ffd83dbSDimitry Andric } 21815ffd83dbSDimitry Andric 2182*fe6060f1SDimitry Andric static SDValue 2183*fe6060f1SDimitry Andric performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { 2184e8d8bef9SDimitry Andric auto &DAG = DCI.DAG; 2185e8d8bef9SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND || 2186e8d8bef9SDimitry Andric N->getOpcode() == ISD::ZERO_EXTEND); 2187e8d8bef9SDimitry Andric 2188e8d8bef9SDimitry Andric // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if 2189e8d8bef9SDimitry Andric // possible before the extract_subvector can be expanded. 2190e8d8bef9SDimitry Andric auto Extract = N->getOperand(0); 2191e8d8bef9SDimitry Andric if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) 2192e8d8bef9SDimitry Andric return SDValue(); 2193e8d8bef9SDimitry Andric auto Source = Extract.getOperand(0); 2194e8d8bef9SDimitry Andric auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1)); 2195e8d8bef9SDimitry Andric if (IndexNode == nullptr) 2196e8d8bef9SDimitry Andric return SDValue(); 2197e8d8bef9SDimitry Andric auto Index = IndexNode->getZExtValue(); 2198e8d8bef9SDimitry Andric 2199*fe6060f1SDimitry Andric // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the 2200*fe6060f1SDimitry Andric // extracted subvector is the low or high half of its source. 2201e8d8bef9SDimitry Andric EVT ResVT = N->getValueType(0); 2202e8d8bef9SDimitry Andric if (ResVT == MVT::v8i16) { 2203e8d8bef9SDimitry Andric if (Extract.getValueType() != MVT::v8i8 || 2204e8d8bef9SDimitry Andric Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8)) 2205e8d8bef9SDimitry Andric return SDValue(); 2206e8d8bef9SDimitry Andric } else if (ResVT == MVT::v4i32) { 2207e8d8bef9SDimitry Andric if (Extract.getValueType() != MVT::v4i16 || 2208e8d8bef9SDimitry Andric Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4)) 2209e8d8bef9SDimitry Andric return SDValue(); 2210*fe6060f1SDimitry Andric } else if (ResVT == MVT::v2i64) { 2211*fe6060f1SDimitry Andric if (Extract.getValueType() != MVT::v2i32 || 2212*fe6060f1SDimitry Andric Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2)) 2213*fe6060f1SDimitry Andric return SDValue(); 2214e8d8bef9SDimitry Andric } else { 2215e8d8bef9SDimitry Andric return SDValue(); 2216e8d8bef9SDimitry Andric } 2217e8d8bef9SDimitry Andric 2218e8d8bef9SDimitry Andric bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND; 2219e8d8bef9SDimitry Andric bool IsLow = Index == 0; 2220e8d8bef9SDimitry Andric 2221*fe6060f1SDimitry Andric unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S 2222*fe6060f1SDimitry Andric : WebAssemblyISD::EXTEND_HIGH_S) 2223*fe6060f1SDimitry Andric : (IsLow ? WebAssemblyISD::EXTEND_LOW_U 2224*fe6060f1SDimitry Andric : WebAssemblyISD::EXTEND_HIGH_U); 2225e8d8bef9SDimitry Andric 2226e8d8bef9SDimitry Andric return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2227e8d8bef9SDimitry Andric } 2228e8d8bef9SDimitry Andric 2229*fe6060f1SDimitry Andric static SDValue 2230*fe6060f1SDimitry Andric performVectorConvertLowCombine(SDNode *N, 2231*fe6060f1SDimitry Andric TargetLowering::DAGCombinerInfo &DCI) { 2232*fe6060f1SDimitry Andric auto &DAG = DCI.DAG; 2233*fe6060f1SDimitry Andric 2234*fe6060f1SDimitry Andric EVT ResVT = N->getValueType(0); 2235*fe6060f1SDimitry Andric if (ResVT != MVT::v2f64) 2236*fe6060f1SDimitry Andric return SDValue(); 2237*fe6060f1SDimitry Andric 2238*fe6060f1SDimitry Andric auto GetWasmConversionOp = [](unsigned Op) { 2239*fe6060f1SDimitry Andric switch (Op) { 2240*fe6060f1SDimitry Andric case ISD::SINT_TO_FP: 2241*fe6060f1SDimitry Andric return WebAssemblyISD::CONVERT_LOW_S; 2242*fe6060f1SDimitry Andric case ISD::UINT_TO_FP: 2243*fe6060f1SDimitry Andric return WebAssemblyISD::CONVERT_LOW_U; 2244*fe6060f1SDimitry Andric case ISD::FP_EXTEND: 2245*fe6060f1SDimitry Andric return WebAssemblyISD::PROMOTE_LOW; 2246*fe6060f1SDimitry Andric } 2247*fe6060f1SDimitry Andric llvm_unreachable("unexpected op"); 2248*fe6060f1SDimitry Andric }; 2249*fe6060f1SDimitry Andric 2250*fe6060f1SDimitry Andric if (N->getOpcode() == ISD::EXTRACT_SUBVECTOR) { 2251*fe6060f1SDimitry Andric // Combine this: 2252*fe6060f1SDimitry Andric // 2253*fe6060f1SDimitry Andric // (v2f64 (extract_subvector 2254*fe6060f1SDimitry Andric // (v4f64 ({s,u}int_to_fp (v4i32 $x))), 0)) 2255*fe6060f1SDimitry Andric // 2256*fe6060f1SDimitry Andric // into (f64x2.convert_low_i32x4_{s,u} $x). 2257*fe6060f1SDimitry Andric // 2258*fe6060f1SDimitry Andric // Or this: 2259*fe6060f1SDimitry Andric // 2260*fe6060f1SDimitry Andric // (v2f64 (extract_subvector 2261*fe6060f1SDimitry Andric // (v4f64 (fp_extend (v4f32 $x))), 0)) 2262*fe6060f1SDimitry Andric // 2263*fe6060f1SDimitry Andric // into (f64x2.promote_low_f32x4 $x). 2264*fe6060f1SDimitry Andric auto Conversion = N->getOperand(0); 2265*fe6060f1SDimitry Andric auto ConversionOp = Conversion.getOpcode(); 2266*fe6060f1SDimitry Andric MVT ExpectedSourceType; 2267*fe6060f1SDimitry Andric switch (ConversionOp) { 2268*fe6060f1SDimitry Andric case ISD::SINT_TO_FP: 2269*fe6060f1SDimitry Andric case ISD::UINT_TO_FP: 2270*fe6060f1SDimitry Andric ExpectedSourceType = MVT::v4i32; 2271*fe6060f1SDimitry Andric break; 2272*fe6060f1SDimitry Andric case ISD::FP_EXTEND: 2273*fe6060f1SDimitry Andric ExpectedSourceType = MVT::v4f32; 2274*fe6060f1SDimitry Andric break; 2275*fe6060f1SDimitry Andric default: 2276*fe6060f1SDimitry Andric return SDValue(); 2277*fe6060f1SDimitry Andric } 2278*fe6060f1SDimitry Andric 2279*fe6060f1SDimitry Andric if (Conversion.getValueType() != MVT::v4f64) 2280*fe6060f1SDimitry Andric return SDValue(); 2281*fe6060f1SDimitry Andric 2282*fe6060f1SDimitry Andric auto Source = Conversion.getOperand(0); 2283*fe6060f1SDimitry Andric if (Source.getValueType() != ExpectedSourceType) 2284*fe6060f1SDimitry Andric return SDValue(); 2285*fe6060f1SDimitry Andric 2286*fe6060f1SDimitry Andric auto IndexNode = dyn_cast<ConstantSDNode>(N->getOperand(1)); 2287*fe6060f1SDimitry Andric if (IndexNode == nullptr || IndexNode->getZExtValue() != 0) 2288*fe6060f1SDimitry Andric return SDValue(); 2289*fe6060f1SDimitry Andric 2290*fe6060f1SDimitry Andric auto Op = GetWasmConversionOp(ConversionOp); 2291*fe6060f1SDimitry Andric return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2292*fe6060f1SDimitry Andric } 2293*fe6060f1SDimitry Andric 2294*fe6060f1SDimitry Andric // Combine this: 2295*fe6060f1SDimitry Andric // 2296*fe6060f1SDimitry Andric // (v2f64 ({s,u}int_to_fp 2297*fe6060f1SDimitry Andric // (v2i32 (extract_subvector (v4i32 $x), 0)))) 2298*fe6060f1SDimitry Andric // 2299*fe6060f1SDimitry Andric // into (f64x2.convert_low_i32x4_{s,u} $x). 2300*fe6060f1SDimitry Andric // 2301*fe6060f1SDimitry Andric // Or this: 2302*fe6060f1SDimitry Andric // 2303*fe6060f1SDimitry Andric // (v2f64 (fp_extend 2304*fe6060f1SDimitry Andric // (v2f32 (extract_subvector (v4f32 $x), 0)))) 2305*fe6060f1SDimitry Andric // 2306*fe6060f1SDimitry Andric // into (f64x2.promote_low_f32x4 $x). 2307*fe6060f1SDimitry Andric auto ConversionOp = N->getOpcode(); 2308*fe6060f1SDimitry Andric MVT ExpectedExtractType; 2309*fe6060f1SDimitry Andric MVT ExpectedSourceType; 2310*fe6060f1SDimitry Andric switch (ConversionOp) { 2311*fe6060f1SDimitry Andric case ISD::SINT_TO_FP: 2312*fe6060f1SDimitry Andric case ISD::UINT_TO_FP: 2313*fe6060f1SDimitry Andric ExpectedExtractType = MVT::v2i32; 2314*fe6060f1SDimitry Andric ExpectedSourceType = MVT::v4i32; 2315*fe6060f1SDimitry Andric break; 2316*fe6060f1SDimitry Andric case ISD::FP_EXTEND: 2317*fe6060f1SDimitry Andric ExpectedExtractType = MVT::v2f32; 2318*fe6060f1SDimitry Andric ExpectedSourceType = MVT::v4f32; 2319*fe6060f1SDimitry Andric break; 2320*fe6060f1SDimitry Andric default: 2321*fe6060f1SDimitry Andric llvm_unreachable("unexpected opcode"); 2322*fe6060f1SDimitry Andric } 2323*fe6060f1SDimitry Andric 2324*fe6060f1SDimitry Andric auto Extract = N->getOperand(0); 2325*fe6060f1SDimitry Andric if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) 2326*fe6060f1SDimitry Andric return SDValue(); 2327*fe6060f1SDimitry Andric 2328*fe6060f1SDimitry Andric if (Extract.getValueType() != ExpectedExtractType) 2329*fe6060f1SDimitry Andric return SDValue(); 2330*fe6060f1SDimitry Andric 2331*fe6060f1SDimitry Andric auto Source = Extract.getOperand(0); 2332*fe6060f1SDimitry Andric if (Source.getValueType() != ExpectedSourceType) 2333*fe6060f1SDimitry Andric return SDValue(); 2334*fe6060f1SDimitry Andric 2335*fe6060f1SDimitry Andric auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1)); 2336*fe6060f1SDimitry Andric if (IndexNode == nullptr || IndexNode->getZExtValue() != 0) 2337*fe6060f1SDimitry Andric return SDValue(); 2338*fe6060f1SDimitry Andric 2339*fe6060f1SDimitry Andric unsigned Op = GetWasmConversionOp(ConversionOp); 2340*fe6060f1SDimitry Andric return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2341*fe6060f1SDimitry Andric } 2342*fe6060f1SDimitry Andric 2343*fe6060f1SDimitry Andric static SDValue 2344*fe6060f1SDimitry Andric performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { 2345*fe6060f1SDimitry Andric auto &DAG = DCI.DAG; 2346*fe6060f1SDimitry Andric 2347*fe6060f1SDimitry Andric auto GetWasmConversionOp = [](unsigned Op) { 2348*fe6060f1SDimitry Andric switch (Op) { 2349*fe6060f1SDimitry Andric case ISD::FP_TO_SINT_SAT: 2350*fe6060f1SDimitry Andric return WebAssemblyISD::TRUNC_SAT_ZERO_S; 2351*fe6060f1SDimitry Andric case ISD::FP_TO_UINT_SAT: 2352*fe6060f1SDimitry Andric return WebAssemblyISD::TRUNC_SAT_ZERO_U; 2353*fe6060f1SDimitry Andric case ISD::FP_ROUND: 2354*fe6060f1SDimitry Andric return WebAssemblyISD::DEMOTE_ZERO; 2355*fe6060f1SDimitry Andric } 2356*fe6060f1SDimitry Andric llvm_unreachable("unexpected op"); 2357*fe6060f1SDimitry Andric }; 2358*fe6060f1SDimitry Andric 2359*fe6060f1SDimitry Andric auto IsZeroSplat = [](SDValue SplatVal) { 2360*fe6060f1SDimitry Andric auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode()); 2361*fe6060f1SDimitry Andric APInt SplatValue, SplatUndef; 2362*fe6060f1SDimitry Andric unsigned SplatBitSize; 2363*fe6060f1SDimitry Andric bool HasAnyUndefs; 2364*fe6060f1SDimitry Andric return Splat && 2365*fe6060f1SDimitry Andric Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, 2366*fe6060f1SDimitry Andric HasAnyUndefs) && 2367*fe6060f1SDimitry Andric SplatValue == 0; 2368*fe6060f1SDimitry Andric }; 2369*fe6060f1SDimitry Andric 2370*fe6060f1SDimitry Andric if (N->getOpcode() == ISD::CONCAT_VECTORS) { 2371*fe6060f1SDimitry Andric // Combine this: 2372*fe6060f1SDimitry Andric // 2373*fe6060f1SDimitry Andric // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0))) 2374*fe6060f1SDimitry Andric // 2375*fe6060f1SDimitry Andric // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). 2376*fe6060f1SDimitry Andric // 2377*fe6060f1SDimitry Andric // Or this: 2378*fe6060f1SDimitry Andric // 2379*fe6060f1SDimitry Andric // (concat_vectors (v2f32 (fp_round (v2f64 $x))), (v2f32 (splat 0))) 2380*fe6060f1SDimitry Andric // 2381*fe6060f1SDimitry Andric // into (f32x4.demote_zero_f64x2 $x). 2382*fe6060f1SDimitry Andric EVT ResVT; 2383*fe6060f1SDimitry Andric EVT ExpectedConversionType; 2384*fe6060f1SDimitry Andric auto Conversion = N->getOperand(0); 2385*fe6060f1SDimitry Andric auto ConversionOp = Conversion.getOpcode(); 2386*fe6060f1SDimitry Andric switch (ConversionOp) { 2387*fe6060f1SDimitry Andric case ISD::FP_TO_SINT_SAT: 2388*fe6060f1SDimitry Andric case ISD::FP_TO_UINT_SAT: 2389*fe6060f1SDimitry Andric ResVT = MVT::v4i32; 2390*fe6060f1SDimitry Andric ExpectedConversionType = MVT::v2i32; 2391*fe6060f1SDimitry Andric break; 2392*fe6060f1SDimitry Andric case ISD::FP_ROUND: 2393*fe6060f1SDimitry Andric ResVT = MVT::v4f32; 2394*fe6060f1SDimitry Andric ExpectedConversionType = MVT::v2f32; 2395*fe6060f1SDimitry Andric break; 2396*fe6060f1SDimitry Andric default: 2397*fe6060f1SDimitry Andric return SDValue(); 2398*fe6060f1SDimitry Andric } 2399*fe6060f1SDimitry Andric 2400*fe6060f1SDimitry Andric if (N->getValueType(0) != ResVT) 2401*fe6060f1SDimitry Andric return SDValue(); 2402*fe6060f1SDimitry Andric 2403*fe6060f1SDimitry Andric if (Conversion.getValueType() != ExpectedConversionType) 2404*fe6060f1SDimitry Andric return SDValue(); 2405*fe6060f1SDimitry Andric 2406*fe6060f1SDimitry Andric auto Source = Conversion.getOperand(0); 2407*fe6060f1SDimitry Andric if (Source.getValueType() != MVT::v2f64) 2408*fe6060f1SDimitry Andric return SDValue(); 2409*fe6060f1SDimitry Andric 2410*fe6060f1SDimitry Andric if (!IsZeroSplat(N->getOperand(1)) || 2411*fe6060f1SDimitry Andric N->getOperand(1).getValueType() != ExpectedConversionType) 2412*fe6060f1SDimitry Andric return SDValue(); 2413*fe6060f1SDimitry Andric 2414*fe6060f1SDimitry Andric unsigned Op = GetWasmConversionOp(ConversionOp); 2415*fe6060f1SDimitry Andric return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2416*fe6060f1SDimitry Andric } 2417*fe6060f1SDimitry Andric 2418*fe6060f1SDimitry Andric // Combine this: 2419*fe6060f1SDimitry Andric // 2420*fe6060f1SDimitry Andric // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32) 2421*fe6060f1SDimitry Andric // 2422*fe6060f1SDimitry Andric // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). 2423*fe6060f1SDimitry Andric // 2424*fe6060f1SDimitry Andric // Or this: 2425*fe6060f1SDimitry Andric // 2426*fe6060f1SDimitry Andric // (v4f32 (fp_round (concat_vectors $x, (v2f64 (splat 0))))) 2427*fe6060f1SDimitry Andric // 2428*fe6060f1SDimitry Andric // into (f32x4.demote_zero_f64x2 $x). 2429*fe6060f1SDimitry Andric EVT ResVT; 2430*fe6060f1SDimitry Andric auto ConversionOp = N->getOpcode(); 2431*fe6060f1SDimitry Andric switch (ConversionOp) { 2432*fe6060f1SDimitry Andric case ISD::FP_TO_SINT_SAT: 2433*fe6060f1SDimitry Andric case ISD::FP_TO_UINT_SAT: 2434*fe6060f1SDimitry Andric ResVT = MVT::v4i32; 2435*fe6060f1SDimitry Andric break; 2436*fe6060f1SDimitry Andric case ISD::FP_ROUND: 2437*fe6060f1SDimitry Andric ResVT = MVT::v4f32; 2438*fe6060f1SDimitry Andric break; 2439*fe6060f1SDimitry Andric default: 2440*fe6060f1SDimitry Andric llvm_unreachable("unexpected op"); 2441*fe6060f1SDimitry Andric } 2442*fe6060f1SDimitry Andric 2443*fe6060f1SDimitry Andric if (N->getValueType(0) != ResVT) 2444*fe6060f1SDimitry Andric return SDValue(); 2445*fe6060f1SDimitry Andric 2446*fe6060f1SDimitry Andric auto Concat = N->getOperand(0); 2447*fe6060f1SDimitry Andric if (Concat.getValueType() != MVT::v4f64) 2448*fe6060f1SDimitry Andric return SDValue(); 2449*fe6060f1SDimitry Andric 2450*fe6060f1SDimitry Andric auto Source = Concat.getOperand(0); 2451*fe6060f1SDimitry Andric if (Source.getValueType() != MVT::v2f64) 2452*fe6060f1SDimitry Andric return SDValue(); 2453*fe6060f1SDimitry Andric 2454*fe6060f1SDimitry Andric if (!IsZeroSplat(Concat.getOperand(1)) || 2455*fe6060f1SDimitry Andric Concat.getOperand(1).getValueType() != MVT::v2f64) 2456*fe6060f1SDimitry Andric return SDValue(); 2457*fe6060f1SDimitry Andric 2458*fe6060f1SDimitry Andric unsigned Op = GetWasmConversionOp(ConversionOp); 2459*fe6060f1SDimitry Andric return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2460*fe6060f1SDimitry Andric } 2461*fe6060f1SDimitry Andric 24625ffd83dbSDimitry Andric SDValue 24635ffd83dbSDimitry Andric WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, 24645ffd83dbSDimitry Andric DAGCombinerInfo &DCI) const { 24655ffd83dbSDimitry Andric switch (N->getOpcode()) { 24665ffd83dbSDimitry Andric default: 24675ffd83dbSDimitry Andric return SDValue(); 24685ffd83dbSDimitry Andric case ISD::VECTOR_SHUFFLE: 24695ffd83dbSDimitry Andric return performVECTOR_SHUFFLECombine(N, DCI); 2470e8d8bef9SDimitry Andric case ISD::SIGN_EXTEND: 2471e8d8bef9SDimitry Andric case ISD::ZERO_EXTEND: 2472*fe6060f1SDimitry Andric return performVectorExtendCombine(N, DCI); 2473*fe6060f1SDimitry Andric case ISD::SINT_TO_FP: 2474*fe6060f1SDimitry Andric case ISD::UINT_TO_FP: 2475*fe6060f1SDimitry Andric case ISD::FP_EXTEND: 2476*fe6060f1SDimitry Andric case ISD::EXTRACT_SUBVECTOR: 2477*fe6060f1SDimitry Andric return performVectorConvertLowCombine(N, DCI); 2478*fe6060f1SDimitry Andric case ISD::FP_TO_SINT_SAT: 2479*fe6060f1SDimitry Andric case ISD::FP_TO_UINT_SAT: 2480*fe6060f1SDimitry Andric case ISD::FP_ROUND: 2481*fe6060f1SDimitry Andric case ISD::CONCAT_VECTORS: 2482*fe6060f1SDimitry Andric return performVectorTruncZeroCombine(N, DCI); 24835ffd83dbSDimitry Andric } 24845ffd83dbSDimitry Andric } 2485