110e730a2SDan Gohman //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
210e730a2SDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610e730a2SDan Gohman //
710e730a2SDan Gohman //===----------------------------------------------------------------------===//
810e730a2SDan Gohman ///
910e730a2SDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file implements the WebAssemblyTargetLowering class.
1110e730a2SDan Gohman ///
1210e730a2SDan Gohman //===----------------------------------------------------------------------===//
1310e730a2SDan Gohman 
1410e730a2SDan Gohman #include "WebAssemblyISelLowering.h"
1510e730a2SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
1646667a10SPaulo Matos #include "Utils/WebAssemblyTypeUtilities.h"
170b2bc69bSHeejin Ahn #include "Utils/WebAssemblyUtilities.h"
1810e730a2SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
1910e730a2SDan Gohman #include "WebAssemblySubtarget.h"
2010e730a2SDan Gohman #include "WebAssemblyTargetMachine.h"
21af111db8SJF Bastien #include "llvm/CodeGen/CallingConvLower.h"
22989f1c72Sserge-sans-paille #include "llvm/CodeGen/MachineFrameInfo.h"
23989f1c72Sserge-sans-paille #include "llvm/CodeGen/MachineFunctionPass.h"
24cdd48b8aSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h"
25950a13cfSDan Gohman #include "llvm/CodeGen/MachineJumpTableInfo.h"
2624faf859SHeejin Ahn #include "llvm/CodeGen/MachineModuleInfo.h"
2710e730a2SDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
2810e730a2SDan Gohman #include "llvm/CodeGen/SelectionDAG.h"
29d7086af2SPaulo Matos #include "llvm/CodeGen/SelectionDAGNodes.h"
3002fa1c80SOliver Stannard #include "llvm/IR/DiagnosticInfo.h"
31b9073fb2SJF Bastien #include "llvm/IR/DiagnosticPrinter.h"
3210e730a2SDan Gohman #include "llvm/IR/Function.h"
3310e730a2SDan Gohman #include "llvm/IR/Intrinsics.h"
345d986953SReid Kleckner #include "llvm/IR/IntrinsicsWebAssembly.h"
3510e730a2SDan Gohman #include "llvm/Support/Debug.h"
3610e730a2SDan Gohman #include "llvm/Support/ErrorHandling.h"
37417e5006SThomas Lively #include "llvm/Support/KnownBits.h"
3872c628e8SThomas Lively #include "llvm/Support/MathExtras.h"
3910e730a2SDan Gohman #include "llvm/Support/raw_ostream.h"
4010e730a2SDan Gohman #include "llvm/Target/TargetOptions.h"
4110e730a2SDan Gohman using namespace llvm;
4210e730a2SDan Gohman 
4310e730a2SDan Gohman #define DEBUG_TYPE "wasm-lower"
4410e730a2SDan Gohman 
WebAssemblyTargetLowering(const TargetMachine & TM,const WebAssemblySubtarget & STI)4510e730a2SDan Gohman WebAssemblyTargetLowering::WebAssemblyTargetLowering(
4610e730a2SDan Gohman     const TargetMachine &TM, const WebAssemblySubtarget &STI)
47bfaf7e15SDan Gohman     : TargetLowering(TM), Subtarget(&STI) {
48af111db8SJF Bastien   auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
49af111db8SJF Bastien 
5071d29aceSJF Bastien   // Booleans always contain 0 or 1.
5171d29aceSJF Bastien   setBooleanContents(ZeroOrOneBooleanContent);
525ea17d45SThomas Lively   // Except in SIMD vectors
535ea17d45SThomas Lively   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
54489abd70SDan Gohman   // We don't know the microarchitecture here, so just reduce register pressure.
55489abd70SDan Gohman   setSchedulingPreference(Sched::RegPressure);
56b9073fb2SJF Bastien   // Tell ISel that we have a stack pointer.
57b9073fb2SJF Bastien   setStackPointerRegisterToSaveRestore(
58b9073fb2SJF Bastien       Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
59b9073fb2SJF Bastien   // Set up the register classes.
60d0bf9812SDan Gohman   addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
61d0bf9812SDan Gohman   addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
62d0bf9812SDan Gohman   addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
63d0bf9812SDan Gohman   addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
6439bf39f3SDerek Schuff   if (Subtarget->hasSIMD128()) {
6539bf39f3SDerek Schuff     addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
6639bf39f3SDerek Schuff     addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
6739bf39f3SDerek Schuff     addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
6839bf39f3SDerek Schuff     addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
695831e9ccSHeejin Ahn     addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
7051ed131eSDerek Schuff     addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
7139bf39f3SDerek Schuff   }
7246667a10SPaulo Matos   if (Subtarget->hasReferenceTypes()) {
7346667a10SPaulo Matos     addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass);
7446667a10SPaulo Matos     addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass);
7546667a10SPaulo Matos   }
76b9073fb2SJF Bastien   // Compute derived properties from the register classes.
77b9073fb2SJF Bastien   computeRegisterProperties(Subtarget->getRegisterInfo());
78b9073fb2SJF Bastien 
79d7086af2SPaulo Matos   // Transform loads and stores to pointers in address space 1 to loads and
80d7086af2SPaulo Matos   // stores to WebAssembly global variables, outside linear memory.
81d7086af2SPaulo Matos   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) {
82d7086af2SPaulo Matos     setOperationAction(ISD::LOAD, T, Custom);
83d7086af2SPaulo Matos     setOperationAction(ISD::STORE, T, Custom);
84d7086af2SPaulo Matos   }
85d7086af2SPaulo Matos   if (Subtarget->hasSIMD128()) {
86d7086af2SPaulo Matos     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
87d7086af2SPaulo Matos                    MVT::v2f64}) {
88d7086af2SPaulo Matos       setOperationAction(ISD::LOAD, T, Custom);
89d7086af2SPaulo Matos       setOperationAction(ISD::STORE, T, Custom);
90d7086af2SPaulo Matos     }
91d7086af2SPaulo Matos   }
9246667a10SPaulo Matos   if (Subtarget->hasReferenceTypes()) {
936d0c7bc1SPaulo Matos     // We need custom load and store lowering for both externref, funcref and
946d0c7bc1SPaulo Matos     // Other. The MVT::Other here represents tables of reference types.
956d0c7bc1SPaulo Matos     for (auto T : {MVT::externref, MVT::funcref, MVT::Other}) {
9646667a10SPaulo Matos       setOperationAction(ISD::LOAD, T, Custom);
9746667a10SPaulo Matos       setOperationAction(ISD::STORE, T, Custom);
9846667a10SPaulo Matos     }
9946667a10SPaulo Matos   }
100d7086af2SPaulo Matos 
101af111db8SJF Bastien   setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
102a083b28aSSam Clegg   setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom);
1032c8fe6a4SDan Gohman   setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
104950a13cfSDan Gohman   setOperationAction(ISD::JumpTable, MVTPtr, Custom);
10551699a83SDerek Schuff   setOperationAction(ISD::BlockAddress, MVTPtr, Custom);
10651699a83SDerek Schuff   setOperationAction(ISD::BRIND, MVT::Other, Custom);
107af111db8SJF Bastien 
10835bfb24cSDan Gohman   // Take the default expansion for va_arg, va_copy, and va_end. There is no
10935bfb24cSDan Gohman   // default action for va_start, so we do that custom.
11035bfb24cSDan Gohman   setOperationAction(ISD::VASTART, MVT::Other, Custom);
11135bfb24cSDan Gohman   setOperationAction(ISD::VAARG, MVT::Other, Expand);
11235bfb24cSDan Gohman   setOperationAction(ISD::VACOPY, MVT::Other, Expand);
11335bfb24cSDan Gohman   setOperationAction(ISD::VAEND, MVT::Other, Expand);
11435bfb24cSDan Gohman 
115ebd4c906SThomas Lively   for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
116da06bce8SJF Bastien     // Don't expand the floating-point types to constant pools.
117da06bce8SJF Bastien     setOperationAction(ISD::ConstantFP, T, Legal);
118da06bce8SJF Bastien     // Expand floating-point comparisons.
119da06bce8SJF Bastien     for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
120da06bce8SJF Bastien                     ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
121da06bce8SJF Bastien       setCondCodeAction(CC, T, Expand);
12232907a6bSDan Gohman     // Expand floating-point library function operators.
123f208f631SHeejin Ahn     for (auto Op :
124f208f631SHeejin Ahn          {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
12532907a6bSDan Gohman       setOperationAction(Op, T, Expand);
126896e53faSDan Gohman     // Note supported floating-point library function operators that otherwise
127896e53faSDan Gohman     // default to expand.
1287a6b9825SDan Gohman     for (auto Op :
1297a6b9825SDan Gohman          {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
130896e53faSDan Gohman       setOperationAction(Op, T, Legal);
13130f1d691SThomas Lively     // Support minimum and maximum, which otherwise default to expand.
13230f1d691SThomas Lively     setOperationAction(ISD::FMINIMUM, T, Legal);
13330f1d691SThomas Lively     setOperationAction(ISD::FMAXIMUM, T, Legal);
134a63e8eb1SDan Gohman     // WebAssembly currently has no builtin f16 support.
135a63e8eb1SDan Gohman     setOperationAction(ISD::FP16_TO_FP, T, Expand);
136a63e8eb1SDan Gohman     setOperationAction(ISD::FP_TO_FP16, T, Expand);
137a63e8eb1SDan Gohman     setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand);
138a63e8eb1SDan Gohman     setTruncStoreAction(T, MVT::f16, Expand);
139da06bce8SJF Bastien   }
14032907a6bSDan Gohman 
14132907a6bSDan Gohman   // Expand unavailable integer operations.
1427a6b9825SDan Gohman   for (auto Op :
143f208f631SHeejin Ahn        {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU,
144f208f631SHeejin Ahn         ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS,
145f208f631SHeejin Ahn         ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
1462b8b2978SThomas Lively     for (auto T : {MVT::i32, MVT::i64})
14732907a6bSDan Gohman       setOperationAction(Op, T, Expand);
1482b8b2978SThomas Lively     if (Subtarget->hasSIMD128())
14927748363SThomas Lively       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
15066ea30c7SThomas Lively         setOperationAction(Op, T, Expand);
15166ea30c7SThomas Lively   }
1522b8b2978SThomas Lively 
1535c729750SThomas Lively   if (Subtarget->hasNontrappingFPToInt())
1545c729750SThomas Lively     for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT})
1555c729750SThomas Lively       for (auto T : {MVT::i32, MVT::i64})
1565c729750SThomas Lively         setOperationAction(Op, T, Custom);
1575c729750SThomas Lively 
1582b8b2978SThomas Lively   // SIMD-specific configuration
1592b8b2978SThomas Lively   if (Subtarget->hasSIMD128()) {
16040af4810SThomas Lively     // Hoist bitcasts out of shuffles
16140af4810SThomas Lively     setTargetDAGCombine(ISD::VECTOR_SHUFFLE);
16240af4810SThomas Lively 
16311bb7eefSThomas Lively     // Combine extends of extract_subvectors into widening ops
164662b9fa0SShao-Ce SUN     setTargetDAGCombine({ISD::SIGN_EXTEND, ISD::ZERO_EXTEND});
16511bb7eefSThomas Lively 
166e5220104SThomas Lively     // Combine int_to_fp or fp_extend of extract_vectors and vice versa into
167e5220104SThomas Lively     // conversions ops
168662b9fa0SShao-Ce SUN     setTargetDAGCombine({ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_EXTEND,
169662b9fa0SShao-Ce SUN                          ISD::EXTRACT_SUBVECTOR});
170af7925b4SThomas Lively 
171cbabfc63SThomas Lively     // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa
172cbabfc63SThomas Lively     // into conversion ops
173662b9fa0SShao-Ce SUN     setTargetDAGCombine({ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT,
174662b9fa0SShao-Ce SUN                          ISD::FP_ROUND, ISD::CONCAT_VECTORS});
1755c729750SThomas Lively 
1762a4a229dSJing Bao     setTargetDAGCombine(ISD::TRUNCATE);
1772a4a229dSJing Bao 
1782b8b2978SThomas Lively     // Support saturating add for i8x16 and i16x8
1792b8b2978SThomas Lively     for (auto Op : {ISD::SADDSAT, ISD::UADDSAT})
1802b8b2978SThomas Lively       for (auto T : {MVT::v16i8, MVT::v8i16})
1812b8b2978SThomas Lively         setOperationAction(Op, T, Legal);
1822b8b2978SThomas Lively 
18334db3c3aSThomas Lively     // Support integer abs
18414ca2e5eSThomas Lively     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
18534db3c3aSThomas Lively       setOperationAction(ISD::ABS, T, Legal);
18634db3c3aSThomas Lively 
187079816efSThomas Lively     // Custom lower BUILD_VECTORs to minimize number of replace_lanes
18827748363SThomas Lively     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
18927748363SThomas Lively                    MVT::v2f64})
190079816efSThomas Lively       setOperationAction(ISD::BUILD_VECTOR, T, Custom);
191079816efSThomas Lively 
1922b8b2978SThomas Lively     // We have custom shuffle lowering to expose the shuffle mask
19327748363SThomas Lively     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
19427748363SThomas Lively                    MVT::v2f64})
1952b8b2978SThomas Lively       setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
1962b8b2978SThomas Lively 
1972b8b2978SThomas Lively     // Custom lowering since wasm shifts must have a scalar shift amount
19827748363SThomas Lively     for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
19927748363SThomas Lively       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
2002b8b2978SThomas Lively         setOperationAction(Op, T, Custom);
2012b8b2978SThomas Lively 
2022b8b2978SThomas Lively     // Custom lower lane accesses to expand out variable indices
20327748363SThomas Lively     for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT})
20427748363SThomas Lively       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
20527748363SThomas Lively                      MVT::v2f64})
2062b8b2978SThomas Lively         setOperationAction(Op, T, Custom);
20732907a6bSDan Gohman 
2083181273bSThomas Lively     // There is no i8x16.mul instruction
2093181273bSThomas Lively     setOperationAction(ISD::MUL, MVT::v16i8, Expand);
2102ee686daSThomas Lively 
211f0f97876SThomas Lively     // There is no vector conditional select instruction
21227748363SThomas Lively     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
21327748363SThomas Lively                    MVT::v2f64})
214ecb2e5bcSThomas Lively       setOperationAction(ISD::SELECT_CC, T, Expand);
215d4891a1bSThomas Lively 
21643876ae7SThomas Lively     // Expand integer operations supported for scalars but not SIMD
217fe1f0de0SCraig Topper     for (auto Op :
218fe1f0de0SCraig Topper          {ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR})
21927748363SThomas Lively       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
22043876ae7SThomas Lively         setOperationAction(Op, T, Expand);
22143876ae7SThomas Lively 
2223a93756dSThomas Lively     // But we do have integer min and max operations
2233a93756dSThomas Lively     for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX})
2243a93756dSThomas Lively       for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
2253a93756dSThomas Lively         setOperationAction(Op, T, Legal);
2263a93756dSThomas Lively 
227fe1f0de0SCraig Topper     // And we have popcnt for i8x16. It can be used to expand ctlz/cttz.
2288af333cfSThomas Lively     setOperationAction(ISD::CTPOP, MVT::v16i8, Legal);
229fe1f0de0SCraig Topper     setOperationAction(ISD::CTLZ, MVT::v16i8, Expand);
230fe1f0de0SCraig Topper     setOperationAction(ISD::CTTZ, MVT::v16i8, Expand);
231fe1f0de0SCraig Topper 
232fe1f0de0SCraig Topper     // Custom lower bit counting operations for other types to scalarize them.
233fe1f0de0SCraig Topper     for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP})
234fe1f0de0SCraig Topper       for (auto T : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
235fe1f0de0SCraig Topper         setOperationAction(Op, T, Custom);
2368af333cfSThomas Lively 
23743876ae7SThomas Lively     // Expand float operations supported for scalars but not SIMD
238af7ab81cSThomas Lively     for (auto Op : {ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10,
23927748363SThomas Lively                     ISD::FEXP, ISD::FEXP2, ISD::FRINT})
24027748363SThomas Lively       for (auto T : {MVT::v4f32, MVT::v2f64})
24127748363SThomas Lively         setOperationAction(Op, T, Expand);
24243876ae7SThomas Lively 
24345783d0eSThomas Lively     // Unsigned comparison operations are unavailable for i64x2 vectors.
24445783d0eSThomas Lively     for (auto CC : {ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE})
24545783d0eSThomas Lively       setCondCodeAction(CC, MVT::v2i64, Custom);
246ecb7daf6SThomas Lively 
24727748363SThomas Lively     // 64x2 conversions are not in the spec
24827748363SThomas Lively     for (auto Op :
24927748363SThomas Lively          {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT})
25027748363SThomas Lively       for (auto T : {MVT::v2i64, MVT::v2f64})
25127748363SThomas Lively         setOperationAction(Op, T, Expand);
2525c729750SThomas Lively 
2535c729750SThomas Lively     // But saturating fp_to_int converstions are
2545c729750SThomas Lively     for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT})
2555c729750SThomas Lively       setOperationAction(Op, MVT::v4i32, Custom);
2562b8b2978SThomas Lively   }
2572b8b2978SThomas Lively 
25832907a6bSDan Gohman   // As a special case, these operators use the type to mean the type to
25932907a6bSDan Gohman   // sign-extend from.
260a519fe5aSDerek Schuff   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
2615d2b9354SDan Gohman   if (!Subtarget->hasSignExt()) {
26264a39a1cSThomas Lively     // Sign extends are legal only when extending a vector extract
26364a39a1cSThomas Lively     auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
264a519fe5aSDerek Schuff     for (auto T : {MVT::i8, MVT::i16, MVT::i32})
26564a39a1cSThomas Lively       setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action);
266a519fe5aSDerek Schuff   }
2671a9195d8SGraham Hunter   for (auto T : MVT::integer_fixedlen_vector_valuetypes())
2685ea17d45SThomas Lively     setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
26932907a6bSDan Gohman 
27032907a6bSDan Gohman   // Dynamic stack allocation: use the default expansion.
27132907a6bSDan Gohman   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
27232907a6bSDan Gohman   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
2732683a553SDan Gohman   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
27473ff6afaSJF Bastien 
2759769debfSDerek Schuff   setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
276b9a539c0SWouter van Oortmerssen   setOperationAction(ISD::FrameIndex, MVT::i64, Custom);
277aadc89c2SDerek Schuff   setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
2789769debfSDerek Schuff 
279950a13cfSDan Gohman   // Expand these forms; we pattern-match the forms that we can handle in isel.
280950a13cfSDan Gohman   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
281950a13cfSDan Gohman     for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
282950a13cfSDan Gohman       setOperationAction(Op, T, Expand);
283950a13cfSDan Gohman 
284950a13cfSDan Gohman   // We have custom switch handling.
285950a13cfSDan Gohman   setOperationAction(ISD::BR_JT, MVT::Other, Custom);
286950a13cfSDan Gohman 
28773ff6afaSJF Bastien   // WebAssembly doesn't have:
28873ff6afaSJF Bastien   //  - Floating-point extending loads.
28973ff6afaSJF Bastien   //  - Floating-point truncating stores.
29073ff6afaSJF Bastien   //  - i1 extending loads.
29181125f73SThomas Lively   //  - truncating SIMD stores and most extending loads
29260bddf17SDan Gohman   setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
29373ff6afaSJF Bastien   setTruncStoreAction(MVT::f64, MVT::f32, Expand);
29473ff6afaSJF Bastien   for (auto T : MVT::integer_valuetypes())
29573ff6afaSJF Bastien     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
29673ff6afaSJF Bastien       setLoadExtAction(Ext, T, MVT::i1, Promote);
297325c9c5eSThomas Lively   if (Subtarget->hasSIMD128()) {
298325c9c5eSThomas Lively     for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
299325c9c5eSThomas Lively                    MVT::v2f64}) {
3001a9195d8SGraham Hunter       for (auto MemT : MVT::fixedlen_vector_valuetypes()) {
301325c9c5eSThomas Lively         if (MVT(T) != MemT) {
302325c9c5eSThomas Lively           setTruncStoreAction(T, MemT, Expand);
303325c9c5eSThomas Lively           for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
304325c9c5eSThomas Lively             setLoadExtAction(Ext, T, MemT, Expand);
305325c9c5eSThomas Lively         }
306325c9c5eSThomas Lively       }
307325c9c5eSThomas Lively     }
30881125f73SThomas Lively     // But some vector extending loads are legal
30981125f73SThomas Lively     for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
31081125f73SThomas Lively       setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal);
31181125f73SThomas Lively       setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal);
31281125f73SThomas Lively       setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal);
31381125f73SThomas Lively     }
314fec47492SThomas Lively     setLoadExtAction(ISD::EXTLOAD, MVT::v2f64, MVT::v2f32, Legal);
31581125f73SThomas Lively   }
316ffa143ceSDerek Schuff 
31733f87b8aSThomas Lively   // Don't do anything clever with build_pairs
31833f87b8aSThomas Lively   setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand);
31933f87b8aSThomas Lively 
320ffa143ceSDerek Schuff   // Trap lowers to wasm unreachable
321ffa143ceSDerek Schuff   setOperationAction(ISD::TRAP, MVT::Other, Legal);
322a07c08f7SThomas Lively   setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
32318ba1928SDerek Schuff 
3245ef4d5f9SHeejin Ahn   // Exception handling intrinsics
3255ef4d5f9SHeejin Ahn   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
3269e4eadebSHeejin Ahn   setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
327da419bdbSHeejin Ahn   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
3285ef4d5f9SHeejin Ahn 
32918ba1928SDerek Schuff   setMaxAtomicSizeInBitsSupported(64);
330d99af237SThomas Lively 
3313a7532e6SDan Gohman   // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is
3323a7532e6SDan Gohman   // consistent with the f64 and f128 names.
3333a7532e6SDan Gohman   setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
3343a7532e6SDan Gohman   setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
3353a7532e6SDan Gohman 
3361a3cbe72SThomas Lively   // Define the emscripten name for return address helper.
3371a69f023SThomas Lively   // TODO: when implementing other Wasm backends, make this generic or only do
3381a3cbe72SThomas Lively   // this on emscripten depending on what they end up doing.
3391a3cbe72SThomas Lively   setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address");
3401a3cbe72SThomas Lively 
341b9f282d3SHeejin Ahn   // Always convert switches to br_tables unless there is only one case, which
342b9f282d3SHeejin Ahn   // is equivalent to a simple branch. This reduces code size for wasm, and we
343b9f282d3SHeejin Ahn   // defer possible jump table optimizations to the VM.
344b9f282d3SHeejin Ahn   setMinimumJumpTableEntries(2);
345bfaf7e15SDan Gohman }
34610e730a2SDan Gohman 
getPointerTy(const DataLayout & DL,uint32_t AS) const34791fe069cSPaulo Matos MVT WebAssemblyTargetLowering::getPointerTy(const DataLayout &DL,
34891fe069cSPaulo Matos                                             uint32_t AS) const {
34991fe069cSPaulo Matos   if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF)
35091fe069cSPaulo Matos     return MVT::externref;
35191fe069cSPaulo Matos   if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF)
35291fe069cSPaulo Matos     return MVT::funcref;
35391fe069cSPaulo Matos   return TargetLowering::getPointerTy(DL, AS);
35491fe069cSPaulo Matos }
35591fe069cSPaulo Matos 
getPointerMemTy(const DataLayout & DL,uint32_t AS) const35691fe069cSPaulo Matos MVT WebAssemblyTargetLowering::getPointerMemTy(const DataLayout &DL,
35791fe069cSPaulo Matos                                                uint32_t AS) const {
35891fe069cSPaulo Matos   if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF)
35991fe069cSPaulo Matos     return MVT::externref;
36091fe069cSPaulo Matos   if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF)
36191fe069cSPaulo Matos     return MVT::funcref;
36291fe069cSPaulo Matos   return TargetLowering::getPointerMemTy(DL, AS);
36391fe069cSPaulo Matos }
36491fe069cSPaulo Matos 
365e8653bb8SHeejin Ahn TargetLowering::AtomicExpansionKind
shouldExpandAtomicRMWInIR(AtomicRMWInst * AI) const366e8653bb8SHeejin Ahn WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
367e8653bb8SHeejin Ahn   // We have wasm instructions for these
368e8653bb8SHeejin Ahn   switch (AI->getOperation()) {
369e8653bb8SHeejin Ahn   case AtomicRMWInst::Add:
370e8653bb8SHeejin Ahn   case AtomicRMWInst::Sub:
371e8653bb8SHeejin Ahn   case AtomicRMWInst::And:
372e8653bb8SHeejin Ahn   case AtomicRMWInst::Or:
373e8653bb8SHeejin Ahn   case AtomicRMWInst::Xor:
374e8653bb8SHeejin Ahn   case AtomicRMWInst::Xchg:
375e8653bb8SHeejin Ahn     return AtomicExpansionKind::None;
376e8653bb8SHeejin Ahn   default:
377e8653bb8SHeejin Ahn     break;
378e8653bb8SHeejin Ahn   }
379e8653bb8SHeejin Ahn   return AtomicExpansionKind::CmpXChg;
380e8653bb8SHeejin Ahn }
381e8653bb8SHeejin Ahn 
shouldScalarizeBinop(SDValue VecOp) const3823dd75f53SThomas Lively bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const {
3833dd75f53SThomas Lively   // Implementation copied from X86TargetLowering.
3843dd75f53SThomas Lively   unsigned Opc = VecOp.getOpcode();
3853dd75f53SThomas Lively 
3863dd75f53SThomas Lively   // Assume target opcodes can't be scalarized.
3873dd75f53SThomas Lively   // TODO - do we have any exceptions?
3883dd75f53SThomas Lively   if (Opc >= ISD::BUILTIN_OP_END)
3893dd75f53SThomas Lively     return false;
3903dd75f53SThomas Lively 
3913dd75f53SThomas Lively   // If the vector op is not supported, try to convert to scalar.
3923dd75f53SThomas Lively   EVT VecVT = VecOp.getValueType();
3933dd75f53SThomas Lively   if (!isOperationLegalOrCustomOrPromote(Opc, VecVT))
3943dd75f53SThomas Lively     return true;
3953dd75f53SThomas Lively 
3963dd75f53SThomas Lively   // If the vector op is supported, but the scalar op is not, the transform may
3973dd75f53SThomas Lively   // not be worthwhile.
3983dd75f53SThomas Lively   EVT ScalarVT = VecVT.getScalarType();
3993dd75f53SThomas Lively   return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
4003dd75f53SThomas Lively }
4013dd75f53SThomas Lively 
createFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo) const4027b63484bSDan Gohman FastISel *WebAssemblyTargetLowering::createFastISel(
4037b63484bSDan Gohman     FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
4047b63484bSDan Gohman   return WebAssembly::createFastISel(FuncInfo, LibInfo);
4057b63484bSDan Gohman }
4067b63484bSDan Gohman 
getScalarShiftAmountTy(const DataLayout &,EVT VT) const4077a6b9825SDan Gohman MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
408fda53373SJF Bastien                                                       EVT VT) const {
409a8483755SDan Gohman   unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
410f208f631SHeejin Ahn   if (BitWidth > 1 && BitWidth < 8)
411f208f631SHeejin Ahn     BitWidth = 8;
41241729538SDan Gohman 
41341729538SDan Gohman   if (BitWidth > 64) {
414a01e8bdeSDan Gohman     // The shift will be lowered to a libcall, and compiler-rt libcalls expect
415a01e8bdeSDan Gohman     // the count to be an i32.
416a01e8bdeSDan Gohman     BitWidth = 32;
41741729538SDan Gohman     assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&
418a01e8bdeSDan Gohman            "32-bit shift counts ought to be enough for anyone");
41941729538SDan Gohman   }
42041729538SDan Gohman 
421a8483755SDan Gohman   MVT Result = MVT::getIntegerVT(BitWidth);
422a8483755SDan Gohman   assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
423a8483755SDan Gohman          "Unable to represent scalar shift amount type");
424a8483755SDan Gohman   return Result;
425fda53373SJF Bastien }
426fda53373SJF Bastien 
427cdd48b8aSDan Gohman // Lower an fp-to-int conversion operator from the LLVM opcode, which has an
428cdd48b8aSDan Gohman // undefined result on invalid/overflow, to the WebAssembly opcode, which
429cdd48b8aSDan Gohman // traps on invalid/overflow.
LowerFPToInt(MachineInstr & MI,DebugLoc DL,MachineBasicBlock * BB,const TargetInstrInfo & TII,bool IsUnsigned,bool Int64,bool Float64,unsigned LoweredOpcode)430f208f631SHeejin Ahn static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
431cdd48b8aSDan Gohman                                        MachineBasicBlock *BB,
432cdd48b8aSDan Gohman                                        const TargetInstrInfo &TII,
433f208f631SHeejin Ahn                                        bool IsUnsigned, bool Int64,
434f208f631SHeejin Ahn                                        bool Float64, unsigned LoweredOpcode) {
435cdd48b8aSDan Gohman   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
436cdd48b8aSDan Gohman 
43705c145d6SDaniel Sanders   Register OutReg = MI.getOperand(0).getReg();
43805c145d6SDaniel Sanders   Register InReg = MI.getOperand(1).getReg();
439cdd48b8aSDan Gohman 
440cdd48b8aSDan Gohman   unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
441cdd48b8aSDan Gohman   unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
442cdd48b8aSDan Gohman   unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
443580c102aSDan Gohman   unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
444cdd48b8aSDan Gohman   unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
445580c102aSDan Gohman   unsigned Eqz = WebAssembly::EQZ_I32;
446580c102aSDan Gohman   unsigned And = WebAssembly::AND_I32;
447cdd48b8aSDan Gohman   int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
448cdd48b8aSDan Gohman   int64_t Substitute = IsUnsigned ? 0 : Limit;
449cdd48b8aSDan Gohman   double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
45021109249SDavid Blaikie   auto &Context = BB->getParent()->getFunction().getContext();
451cdd48b8aSDan Gohman   Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
452cdd48b8aSDan Gohman 
45318c56a07SHeejin Ahn   const BasicBlock *LLVMBB = BB->getBasicBlock();
454cdd48b8aSDan Gohman   MachineFunction *F = BB->getParent();
45518c56a07SHeejin Ahn   MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
45618c56a07SHeejin Ahn   MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB);
45718c56a07SHeejin Ahn   MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
458cdd48b8aSDan Gohman 
459cdd48b8aSDan Gohman   MachineFunction::iterator It = ++BB->getIterator();
460cdd48b8aSDan Gohman   F->insert(It, FalseMBB);
461cdd48b8aSDan Gohman   F->insert(It, TrueMBB);
462cdd48b8aSDan Gohman   F->insert(It, DoneMBB);
463cdd48b8aSDan Gohman 
464cdd48b8aSDan Gohman   // Transfer the remainder of BB and its successor edges to DoneMBB.
4655c644c9bSHeejin Ahn   DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
466cdd48b8aSDan Gohman   DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
467cdd48b8aSDan Gohman 
468cdd48b8aSDan Gohman   BB->addSuccessor(TrueMBB);
469cdd48b8aSDan Gohman   BB->addSuccessor(FalseMBB);
470cdd48b8aSDan Gohman   TrueMBB->addSuccessor(DoneMBB);
471cdd48b8aSDan Gohman   FalseMBB->addSuccessor(DoneMBB);
472cdd48b8aSDan Gohman 
473580c102aSDan Gohman   unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
474cdd48b8aSDan Gohman   Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
475cdd48b8aSDan Gohman   Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
476580c102aSDan Gohman   CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
477580c102aSDan Gohman   EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
478580c102aSDan Gohman   FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
479580c102aSDan Gohman   TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
480cdd48b8aSDan Gohman 
481cdd48b8aSDan Gohman   MI.eraseFromParent();
482580c102aSDan Gohman   // For signed numbers, we can do a single comparison to determine whether
483580c102aSDan Gohman   // fabs(x) is within range.
484cdd48b8aSDan Gohman   if (IsUnsigned) {
485cdd48b8aSDan Gohman     Tmp0 = InReg;
486cdd48b8aSDan Gohman   } else {
487f208f631SHeejin Ahn     BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
488cdd48b8aSDan Gohman   }
489cdd48b8aSDan Gohman   BuildMI(BB, DL, TII.get(FConst), Tmp1)
490cdd48b8aSDan Gohman       .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
491f208f631SHeejin Ahn   BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
492580c102aSDan Gohman 
493580c102aSDan Gohman   // For unsigned numbers, we have to do a separate comparison with zero.
494580c102aSDan Gohman   if (IsUnsigned) {
495580c102aSDan Gohman     Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
49605c145d6SDaniel Sanders     Register SecondCmpReg =
497f208f631SHeejin Ahn         MRI.createVirtualRegister(&WebAssembly::I32RegClass);
49805c145d6SDaniel Sanders     Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
499580c102aSDan Gohman     BuildMI(BB, DL, TII.get(FConst), Tmp1)
500580c102aSDan Gohman         .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
501f208f631SHeejin Ahn     BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
502f208f631SHeejin Ahn     BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
503580c102aSDan Gohman     CmpReg = AndReg;
504580c102aSDan Gohman   }
505580c102aSDan Gohman 
506f208f631SHeejin Ahn   BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
507580c102aSDan Gohman 
508580c102aSDan Gohman   // Create the CFG diamond to select between doing the conversion or using
509580c102aSDan Gohman   // the substitute value.
510f208f631SHeejin Ahn   BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
511f208f631SHeejin Ahn   BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
512f208f631SHeejin Ahn   BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
513f208f631SHeejin Ahn   BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
514cdd48b8aSDan Gohman   BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
515580c102aSDan Gohman       .addReg(FalseReg)
516cdd48b8aSDan Gohman       .addMBB(FalseMBB)
517580c102aSDan Gohman       .addReg(TrueReg)
518cdd48b8aSDan Gohman       .addMBB(TrueMBB);
519cdd48b8aSDan Gohman 
520cdd48b8aSDan Gohman   return DoneMBB;
521cdd48b8aSDan Gohman }
522cdd48b8aSDan Gohman 
5232632ba6aSAndy Wingo static MachineBasicBlock *
LowerCallResults(MachineInstr & CallResults,DebugLoc DL,MachineBasicBlock * BB,const WebAssemblySubtarget * Subtarget,const TargetInstrInfo & TII)5242632ba6aSAndy Wingo LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
5252632ba6aSAndy Wingo                  const WebAssemblySubtarget *Subtarget,
526d5191096SThomas Lively                  const TargetInstrInfo &TII) {
527d5191096SThomas Lively   MachineInstr &CallParams = *CallResults.getPrevNode();
528d5191096SThomas Lively   assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
529ca9ba764SThomas Lively   assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||
530ca9ba764SThomas Lively          CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS);
531d5191096SThomas Lively 
5329d37f5afSThomas Lively   bool IsIndirect = CallParams.getOperand(0).isReg();
533ca9ba764SThomas Lively   bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
534ca9ba764SThomas Lively 
53546667a10SPaulo Matos   bool IsFuncrefCall = false;
53646667a10SPaulo Matos   if (IsIndirect) {
53746667a10SPaulo Matos     Register Reg = CallParams.getOperand(0).getReg();
53846667a10SPaulo Matos     const MachineFunction *MF = BB->getParent();
53946667a10SPaulo Matos     const MachineRegisterInfo &MRI = MF->getRegInfo();
54046667a10SPaulo Matos     const TargetRegisterClass *TRC = MRI.getRegClass(Reg);
54146667a10SPaulo Matos     IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass);
54246667a10SPaulo Matos     assert(!IsFuncrefCall || Subtarget->hasReferenceTypes());
54346667a10SPaulo Matos   }
54446667a10SPaulo Matos 
545ca9ba764SThomas Lively   unsigned CallOp;
546ca9ba764SThomas Lively   if (IsIndirect && IsRetCall) {
547ca9ba764SThomas Lively     CallOp = WebAssembly::RET_CALL_INDIRECT;
548ca9ba764SThomas Lively   } else if (IsIndirect) {
549ca9ba764SThomas Lively     CallOp = WebAssembly::CALL_INDIRECT;
550ca9ba764SThomas Lively   } else if (IsRetCall) {
551ca9ba764SThomas Lively     CallOp = WebAssembly::RET_CALL;
552ca9ba764SThomas Lively   } else {
553ca9ba764SThomas Lively     CallOp = WebAssembly::CALL;
554ca9ba764SThomas Lively   }
5559d37f5afSThomas Lively 
556d5191096SThomas Lively   MachineFunction &MF = *BB->getParent();
5579d37f5afSThomas Lively   const MCInstrDesc &MCID = TII.get(CallOp);
558d5191096SThomas Lively   MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
559d5191096SThomas Lively 
560cc1b9b68SWouter van Oortmerssen   // See if we must truncate the function pointer.
561cc1b9b68SWouter van Oortmerssen   // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
562cc1b9b68SWouter van Oortmerssen   // as 64-bit for uniformity with other pointer types.
563275c6af7SWouter van Oortmerssen   // See also: WebAssemblyFastISel::selectCall
564cc1b9b68SWouter van Oortmerssen   if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) {
565cc1b9b68SWouter van Oortmerssen     Register Reg32 =
566cc1b9b68SWouter van Oortmerssen         MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
567cc1b9b68SWouter van Oortmerssen     auto &FnPtr = CallParams.getOperand(0);
568cc1b9b68SWouter van Oortmerssen     BuildMI(*BB, CallResults.getIterator(), DL,
569cc1b9b68SWouter van Oortmerssen             TII.get(WebAssembly::I32_WRAP_I64), Reg32)
570cc1b9b68SWouter van Oortmerssen         .addReg(FnPtr.getReg());
571cc1b9b68SWouter van Oortmerssen     FnPtr.setReg(Reg32);
572cc1b9b68SWouter van Oortmerssen   }
573cc1b9b68SWouter van Oortmerssen 
5749d37f5afSThomas Lively   // Move the function pointer to the end of the arguments for indirect calls
5759d37f5afSThomas Lively   if (IsIndirect) {
5769d37f5afSThomas Lively     auto FnPtr = CallParams.getOperand(0);
57737b37838SShengchen Kan     CallParams.removeOperand(0);
5780c749584SPaulo Matos 
5790c749584SPaulo Matos     // For funcrefs, call_indirect is done through __funcref_call_table and the
580*3696a789SAndrew Brown     // funcref is always installed in slot 0 of the table, therefore instead of
581*3696a789SAndrew Brown     // having the function pointer added at the end of the params list, a zero
582*3696a789SAndrew Brown     // (the index in
5830c749584SPaulo Matos     // __funcref_call_table is added).
5840c749584SPaulo Matos     if (IsFuncrefCall) {
5850c749584SPaulo Matos       Register RegZero =
5860c749584SPaulo Matos           MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
5870c749584SPaulo Matos       MachineInstrBuilder MIBC0 =
5880c749584SPaulo Matos           BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
5890c749584SPaulo Matos 
5900c749584SPaulo Matos       BB->insert(CallResults.getIterator(), MIBC0);
5910c749584SPaulo Matos       MachineInstrBuilder(MF, CallParams).addReg(RegZero);
5920c749584SPaulo Matos     } else
5939d37f5afSThomas Lively       CallParams.addOperand(FnPtr);
5949d37f5afSThomas Lively   }
5959d37f5afSThomas Lively 
596d5191096SThomas Lively   for (auto Def : CallResults.defs())
597d5191096SThomas Lively     MIB.add(Def);
5989d37f5afSThomas Lively 
5999d37f5afSThomas Lively   if (IsIndirect) {
6002632ba6aSAndy Wingo     // Placeholder for the type index.
6019d37f5afSThomas Lively     MIB.addImm(0);
6022632ba6aSAndy Wingo     // The table into which this call_indirect indexes.
60346667a10SPaulo Matos     MCSymbolWasm *Table = IsFuncrefCall
60446667a10SPaulo Matos                               ? WebAssembly::getOrCreateFuncrefCallTableSymbol(
60546667a10SPaulo Matos                                     MF.getContext(), Subtarget)
60646667a10SPaulo Matos                               : WebAssembly::getOrCreateFunctionTableSymbol(
60746667a10SPaulo Matos                                     MF.getContext(), Subtarget);
6082632ba6aSAndy Wingo     if (Subtarget->hasReferenceTypes()) {
6092632ba6aSAndy Wingo       MIB.addSym(Table);
6102632ba6aSAndy Wingo     } else {
6112632ba6aSAndy Wingo       // For the MVP there is at most one table whose number is 0, but we can't
6122632ba6aSAndy Wingo       // write a table symbol or issue relocations.  Instead we just ensure the
6132632ba6aSAndy Wingo       // table is live and write a zero.
6142632ba6aSAndy Wingo       Table->setNoStrip();
61596ef4f30SSam Clegg       MIB.addImm(0);
6162632ba6aSAndy Wingo     }
6179d37f5afSThomas Lively   }
6189d37f5afSThomas Lively 
619d5191096SThomas Lively   for (auto Use : CallParams.uses())
620d5191096SThomas Lively     MIB.add(Use);
621d5191096SThomas Lively 
622d5191096SThomas Lively   BB->insert(CallResults.getIterator(), MIB);
623d5191096SThomas Lively   CallParams.eraseFromParent();
624d5191096SThomas Lively   CallResults.eraseFromParent();
625d5191096SThomas Lively 
62646667a10SPaulo Matos   // If this is a funcref call, to avoid hidden GC roots, we need to clear the
62746667a10SPaulo Matos   // table slot with ref.null upon call_indirect return.
62846667a10SPaulo Matos   //
62946667a10SPaulo Matos   // This generates the following code, which comes right after a call_indirect
63046667a10SPaulo Matos   // of a funcref:
63146667a10SPaulo Matos   //
63246667a10SPaulo Matos   //    i32.const 0
63346667a10SPaulo Matos   //    ref.null func
63446667a10SPaulo Matos   //    table.set __funcref_call_table
63546667a10SPaulo Matos   if (IsIndirect && IsFuncrefCall) {
63646667a10SPaulo Matos     MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol(
63746667a10SPaulo Matos         MF.getContext(), Subtarget);
63846667a10SPaulo Matos     Register RegZero =
63946667a10SPaulo Matos         MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
64046667a10SPaulo Matos     MachineInstr *Const0 =
64146667a10SPaulo Matos         BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
64246667a10SPaulo Matos     BB->insertAfter(MIB.getInstr()->getIterator(), Const0);
64346667a10SPaulo Matos 
64446667a10SPaulo Matos     Register RegFuncref =
64546667a10SPaulo Matos         MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass);
64646667a10SPaulo Matos     MachineInstr *RefNull =
647a96d8285SPaulo Matos         BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref);
64846667a10SPaulo Matos     BB->insertAfter(Const0->getIterator(), RefNull);
64946667a10SPaulo Matos 
65046667a10SPaulo Matos     MachineInstr *TableSet =
65146667a10SPaulo Matos         BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF))
65246667a10SPaulo Matos             .addSym(Table)
65346667a10SPaulo Matos             .addReg(RegZero)
65446667a10SPaulo Matos             .addReg(RegFuncref);
65546667a10SPaulo Matos     BB->insertAfter(RefNull->getIterator(), TableSet);
65646667a10SPaulo Matos   }
65746667a10SPaulo Matos 
658d5191096SThomas Lively   return BB;
659d5191096SThomas Lively }
660d5191096SThomas Lively 
EmitInstrWithCustomInserter(MachineInstr & MI,MachineBasicBlock * BB) const661f208f631SHeejin Ahn MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
662f208f631SHeejin Ahn     MachineInstr &MI, MachineBasicBlock *BB) const {
663cdd48b8aSDan Gohman   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
664cdd48b8aSDan Gohman   DebugLoc DL = MI.getDebugLoc();
665cdd48b8aSDan Gohman 
666cdd48b8aSDan Gohman   switch (MI.getOpcode()) {
667f208f631SHeejin Ahn   default:
668f208f631SHeejin Ahn     llvm_unreachable("Unexpected instr type to insert");
669cdd48b8aSDan Gohman   case WebAssembly::FP_TO_SINT_I32_F32:
670cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, false, false, false,
671cdd48b8aSDan Gohman                         WebAssembly::I32_TRUNC_S_F32);
672cdd48b8aSDan Gohman   case WebAssembly::FP_TO_UINT_I32_F32:
673cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, true, false, false,
674cdd48b8aSDan Gohman                         WebAssembly::I32_TRUNC_U_F32);
675cdd48b8aSDan Gohman   case WebAssembly::FP_TO_SINT_I64_F32:
676cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, false, true, false,
677cdd48b8aSDan Gohman                         WebAssembly::I64_TRUNC_S_F32);
678cdd48b8aSDan Gohman   case WebAssembly::FP_TO_UINT_I64_F32:
679cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, true, true, false,
680cdd48b8aSDan Gohman                         WebAssembly::I64_TRUNC_U_F32);
681cdd48b8aSDan Gohman   case WebAssembly::FP_TO_SINT_I32_F64:
682cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, false, false, true,
683cdd48b8aSDan Gohman                         WebAssembly::I32_TRUNC_S_F64);
684cdd48b8aSDan Gohman   case WebAssembly::FP_TO_UINT_I32_F64:
685cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, true, false, true,
686cdd48b8aSDan Gohman                         WebAssembly::I32_TRUNC_U_F64);
687cdd48b8aSDan Gohman   case WebAssembly::FP_TO_SINT_I64_F64:
688cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, false, true, true,
689cdd48b8aSDan Gohman                         WebAssembly::I64_TRUNC_S_F64);
690cdd48b8aSDan Gohman   case WebAssembly::FP_TO_UINT_I64_F64:
691cdd48b8aSDan Gohman     return LowerFPToInt(MI, DL, BB, TII, true, true, true,
692cdd48b8aSDan Gohman                         WebAssembly::I64_TRUNC_U_F64);
693d5191096SThomas Lively   case WebAssembly::CALL_RESULTS:
694ca9ba764SThomas Lively   case WebAssembly::RET_CALL_RESULTS:
6952632ba6aSAndy Wingo     return LowerCallResults(MI, DL, BB, Subtarget, TII);
696cdd48b8aSDan Gohman   }
697cdd48b8aSDan Gohman }
698cdd48b8aSDan Gohman 
699f208f631SHeejin Ahn const char *
getTargetNodeName(unsigned Opcode) const700f208f631SHeejin Ahn WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
701480c8408SJF Bastien   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
702af111db8SJF Bastien   case WebAssemblyISD::FIRST_NUMBER:
7033479fd25SThomas Lively   case WebAssemblyISD::FIRST_MEM_OPCODE:
704af111db8SJF Bastien     break;
705af111db8SJF Bastien #define HANDLE_NODETYPE(NODE)                                                  \
706af111db8SJF Bastien   case WebAssemblyISD::NODE:                                                   \
707af111db8SJF Bastien     return "WebAssemblyISD::" #NODE;
7083479fd25SThomas Lively #define HANDLE_MEM_NODETYPE(NODE) HANDLE_NODETYPE(NODE)
709af111db8SJF Bastien #include "WebAssemblyISD.def"
7103479fd25SThomas Lively #undef HANDLE_MEM_NODETYPE
711af111db8SJF Bastien #undef HANDLE_NODETYPE
712480c8408SJF Bastien   }
713480c8408SJF Bastien   return nullptr;
714480c8408SJF Bastien }
715480c8408SJF Bastien 
716f19ed562SDan Gohman std::pair<unsigned, const TargetRegisterClass *>
getRegForInlineAsmConstraint(const TargetRegisterInfo * TRI,StringRef Constraint,MVT VT) const717f19ed562SDan Gohman WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
718f19ed562SDan Gohman     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
719f19ed562SDan Gohman   // First, see if this is a constraint that directly corresponds to a
720f19ed562SDan Gohman   // WebAssembly register class.
721f19ed562SDan Gohman   if (Constraint.size() == 1) {
722f19ed562SDan Gohman     switch (Constraint[0]) {
723f19ed562SDan Gohman     case 'r':
724284384b6SDan Gohman       assert(VT != MVT::iPTR && "Pointer MVT not expected here");
72539bf39f3SDerek Schuff       if (Subtarget->hasSIMD128() && VT.isVector()) {
72639bf39f3SDerek Schuff         if (VT.getSizeInBits() == 128)
72739bf39f3SDerek Schuff           return std::make_pair(0U, &WebAssembly::V128RegClass);
72839bf39f3SDerek Schuff       }
729284384b6SDan Gohman       if (VT.isInteger() && !VT.isVector()) {
730284384b6SDan Gohman         if (VT.getSizeInBits() <= 32)
731f19ed562SDan Gohman           return std::make_pair(0U, &WebAssembly::I32RegClass);
732284384b6SDan Gohman         if (VT.getSizeInBits() <= 64)
733a774d719SDan Gohman           return std::make_pair(0U, &WebAssembly::I64RegClass);
734284384b6SDan Gohman       }
735803af31eSsnek       if (VT.isFloatingPoint() && !VT.isVector()) {
736803af31eSsnek         switch (VT.getSizeInBits()) {
737803af31eSsnek         case 32:
738803af31eSsnek           return std::make_pair(0U, &WebAssembly::F32RegClass);
739803af31eSsnek         case 64:
740803af31eSsnek           return std::make_pair(0U, &WebAssembly::F64RegClass);
741803af31eSsnek         default:
742803af31eSsnek           break;
743803af31eSsnek         }
744803af31eSsnek       }
745a774d719SDan Gohman       break;
746f19ed562SDan Gohman     default:
747f19ed562SDan Gohman       break;
748f19ed562SDan Gohman     }
749f19ed562SDan Gohman   }
750f19ed562SDan Gohman 
751f19ed562SDan Gohman   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
752f19ed562SDan Gohman }
753f19ed562SDan Gohman 
isCheapToSpeculateCttz() const7543192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
7553192ddfeSDan Gohman   // Assume ctz is a relatively cheap operation.
7563192ddfeSDan Gohman   return true;
7573192ddfeSDan Gohman }
7583192ddfeSDan Gohman 
isCheapToSpeculateCtlz() const7593192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
7603192ddfeSDan Gohman   // Assume clz is a relatively cheap operation.
7613192ddfeSDan Gohman   return true;
7623192ddfeSDan Gohman }
7633192ddfeSDan Gohman 
isLegalAddressingMode(const DataLayout & DL,const AddrMode & AM,Type * Ty,unsigned AS,Instruction * I) const7644b9d7916SDan Gohman bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
7654b9d7916SDan Gohman                                                       const AddrMode &AM,
766f208f631SHeejin Ahn                                                       Type *Ty, unsigned AS,
767024e3194SJonas Paulsson                                                       Instruction *I) const {
7684b9d7916SDan Gohman   // WebAssembly offsets are added as unsigned without wrapping. The
7694b9d7916SDan Gohman   // isLegalAddressingMode gives us no way to determine if wrapping could be
7704b9d7916SDan Gohman   // happening, so we approximate this by accepting only non-negative offsets.
771f208f631SHeejin Ahn   if (AM.BaseOffs < 0)
772f208f631SHeejin Ahn     return false;
7734b9d7916SDan Gohman 
7744b9d7916SDan Gohman   // WebAssembly has no scale register operands.
775f208f631SHeejin Ahn   if (AM.Scale != 0)
776f208f631SHeejin Ahn     return false;
7774b9d7916SDan Gohman 
7784b9d7916SDan Gohman   // Everything else is legal.
7794b9d7916SDan Gohman   return true;
7804b9d7916SDan Gohman }
7814b9d7916SDan Gohman 
allowsMisalignedMemoryAccesses(EVT,unsigned,Align,MachineMemOperand::Flags,bool * Fast) const782bb372243SDan Gohman bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
78311ef356dSCraig Topper     EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/,
7844e0648a5SSimon Pilgrim     MachineMemOperand::Flags /*Flags*/, bool *Fast) const {
785bb372243SDan Gohman   // WebAssembly supports unaligned accesses, though it should be declared
786bb372243SDan Gohman   // with the p2align attribute on loads and stores which do so, and there
787bb372243SDan Gohman   // may be a performance impact. We tell LLVM they're "fast" because
788fb619e96SDan Gohman   // for the kinds of things that LLVM uses this for (merging adjacent stores
789bb372243SDan Gohman   // of constants, etc.), WebAssembly implementations will either want the
790bb372243SDan Gohman   // unaligned access or they'll split anyway.
791f208f631SHeejin Ahn   if (Fast)
792f208f631SHeejin Ahn     *Fast = true;
793bb372243SDan Gohman   return true;
794bb372243SDan Gohman }
795bb372243SDan Gohman 
isIntDivCheap(EVT VT,AttributeList Attr) const796b518054bSReid Kleckner bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
797b518054bSReid Kleckner                                               AttributeList Attr) const {
798b4c3c382SDan Gohman   // The current thinking is that wasm engines will perform this optimization,
799b4c3c382SDan Gohman   // so we can save on code size.
800b4c3c382SDan Gohman   return true;
801b4c3c382SDan Gohman }
802b4c3c382SDan Gohman 
isVectorLoadExtDesirable(SDValue ExtVal) const80381125f73SThomas Lively bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
804caee15a0SThomas Lively   EVT ExtT = ExtVal.getValueType();
805caee15a0SThomas Lively   EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0);
80681125f73SThomas Lively   return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
80781125f73SThomas Lively          (ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
80881125f73SThomas Lively          (ExtT == MVT::v2i64 && MemT == MVT::v2i32);
80981125f73SThomas Lively }
81081125f73SThomas Lively 
isOffsetFoldingLegal(const GlobalAddressSDNode * GA) const81178e87970SHeejin Ahn bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
81278e87970SHeejin Ahn     const GlobalAddressSDNode *GA) const {
81378e87970SHeejin Ahn   // Wasm doesn't support function addresses with offsets
81478e87970SHeejin Ahn   const GlobalValue *GV = GA->getGlobal();
81578e87970SHeejin Ahn   return isa<Function>(GV) ? false : TargetLowering::isOffsetFoldingLegal(GA);
81678e87970SHeejin Ahn }
81778e87970SHeejin Ahn 
getSetCCResultType(const DataLayout & DL,LLVMContext & C,EVT VT) const81899f70167SSimon Pilgrim EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
81999f70167SSimon Pilgrim                                                   LLVMContext &C,
82099f70167SSimon Pilgrim                                                   EVT VT) const {
82199f70167SSimon Pilgrim   if (VT.isVector())
82299f70167SSimon Pilgrim     return VT.changeVectorElementTypeToInteger();
82399f70167SSimon Pilgrim 
824b9a539c0SWouter van Oortmerssen   // So far, all branch instructions in Wasm take an I32 condition.
825b9a539c0SWouter van Oortmerssen   // The default TargetLowering::getSetCCResultType returns the pointer size,
826b9a539c0SWouter van Oortmerssen   // which would be useful to reduce instruction counts when testing
827b9a539c0SWouter van Oortmerssen   // against 64-bit pointers/values if at some point Wasm supports that.
828b9a539c0SWouter van Oortmerssen   return EVT::getIntegerVT(C, 32);
82999f70167SSimon Pilgrim }
83099f70167SSimon Pilgrim 
getTgtMemIntrinsic(IntrinsicInfo & Info,const CallInst & I,MachineFunction & MF,unsigned Intrinsic) const8314128cb0bSHeejin Ahn bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
8324128cb0bSHeejin Ahn                                                    const CallInst &I,
8334128cb0bSHeejin Ahn                                                    MachineFunction &MF,
8344128cb0bSHeejin Ahn                                                    unsigned Intrinsic) const {
8354128cb0bSHeejin Ahn   switch (Intrinsic) {
836902ea588SHeejin Ahn   case Intrinsic::wasm_memory_atomic_notify:
8374128cb0bSHeejin Ahn     Info.opc = ISD::INTRINSIC_W_CHAIN;
8384128cb0bSHeejin Ahn     Info.memVT = MVT::i32;
8394128cb0bSHeejin Ahn     Info.ptrVal = I.getArgOperand(0);
8404128cb0bSHeejin Ahn     Info.offset = 0;
841c97a3d15SGuillaume Chatelet     Info.align = Align(4);
8424128cb0bSHeejin Ahn     // atomic.notify instruction does not really load the memory specified with
8434128cb0bSHeejin Ahn     // this argument, but MachineMemOperand should either be load or store, so
8444128cb0bSHeejin Ahn     // we set this to a load.
8454128cb0bSHeejin Ahn     // FIXME Volatile isn't really correct, but currently all LLVM atomic
8464128cb0bSHeejin Ahn     // instructions are treated as volatiles in the backend, so we should be
8474128cb0bSHeejin Ahn     // consistent. The same applies for wasm_atomic_wait intrinsics too.
8484128cb0bSHeejin Ahn     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
8494128cb0bSHeejin Ahn     return true;
850902ea588SHeejin Ahn   case Intrinsic::wasm_memory_atomic_wait32:
8514128cb0bSHeejin Ahn     Info.opc = ISD::INTRINSIC_W_CHAIN;
8524128cb0bSHeejin Ahn     Info.memVT = MVT::i32;
8534128cb0bSHeejin Ahn     Info.ptrVal = I.getArgOperand(0);
8544128cb0bSHeejin Ahn     Info.offset = 0;
855c97a3d15SGuillaume Chatelet     Info.align = Align(4);
8564128cb0bSHeejin Ahn     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
8574128cb0bSHeejin Ahn     return true;
858902ea588SHeejin Ahn   case Intrinsic::wasm_memory_atomic_wait64:
8594128cb0bSHeejin Ahn     Info.opc = ISD::INTRINSIC_W_CHAIN;
8604128cb0bSHeejin Ahn     Info.memVT = MVT::i64;
8614128cb0bSHeejin Ahn     Info.ptrVal = I.getArgOperand(0);
8624128cb0bSHeejin Ahn     Info.offset = 0;
863c97a3d15SGuillaume Chatelet     Info.align = Align(8);
8644128cb0bSHeejin Ahn     Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
8654128cb0bSHeejin Ahn     return true;
8664128cb0bSHeejin Ahn   default:
8674128cb0bSHeejin Ahn     return false;
8684128cb0bSHeejin Ahn   }
8694128cb0bSHeejin Ahn }
8704128cb0bSHeejin Ahn 
computeKnownBitsForTargetNode(const SDValue Op,KnownBits & Known,const APInt & DemandedElts,const SelectionDAG & DAG,unsigned Depth) const871417e5006SThomas Lively void WebAssemblyTargetLowering::computeKnownBitsForTargetNode(
872417e5006SThomas Lively     const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
873417e5006SThomas Lively     const SelectionDAG &DAG, unsigned Depth) const {
874417e5006SThomas Lively   switch (Op.getOpcode()) {
875417e5006SThomas Lively   default:
876417e5006SThomas Lively     break;
877417e5006SThomas Lively   case ISD::INTRINSIC_WO_CHAIN: {
878aa0b0fbbSHeejin Ahn     unsigned IntNo = Op.getConstantOperandVal(0);
879417e5006SThomas Lively     switch (IntNo) {
880417e5006SThomas Lively     default:
881417e5006SThomas Lively       break;
882417e5006SThomas Lively     case Intrinsic::wasm_bitmask: {
883417e5006SThomas Lively       unsigned BitWidth = Known.getBitWidth();
884417e5006SThomas Lively       EVT VT = Op.getOperand(1).getSimpleValueType();
885417e5006SThomas Lively       unsigned PossibleBits = VT.getVectorNumElements();
886417e5006SThomas Lively       APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits);
887417e5006SThomas Lively       Known.Zero |= ZeroMask;
888417e5006SThomas Lively       break;
889417e5006SThomas Lively     }
890417e5006SThomas Lively     }
891417e5006SThomas Lively   }
892417e5006SThomas Lively   }
893417e5006SThomas Lively }
894417e5006SThomas Lively 
895b69374caSThomas Lively TargetLoweringBase::LegalizeTypeAction
getPreferredVectorAction(MVT VT) const896b69374caSThomas Lively WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const {
897b69374caSThomas Lively   if (VT.isFixedLengthVector()) {
898b69374caSThomas Lively     MVT EltVT = VT.getVectorElementType();
899b69374caSThomas Lively     // We have legal vector types with these lane types, so widening the
900b69374caSThomas Lively     // vector would let us use some of the lanes directly without having to
901b69374caSThomas Lively     // extend or truncate values.
902b69374caSThomas Lively     if (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
903b69374caSThomas Lively         EltVT == MVT::i64 || EltVT == MVT::f32 || EltVT == MVT::f64)
904b69374caSThomas Lively       return TypeWidenVector;
905b69374caSThomas Lively   }
906b69374caSThomas Lively 
907b69374caSThomas Lively   return TargetLoweringBase::getPreferredVectorAction(VT);
908b69374caSThomas Lively }
909b69374caSThomas Lively 
shouldSimplifyDemandedVectorElts(SDValue Op,const TargetLoweringOpt & TLO) const910b8038a91SHeejin Ahn bool WebAssemblyTargetLowering::shouldSimplifyDemandedVectorElts(
911b8038a91SHeejin Ahn     SDValue Op, const TargetLoweringOpt &TLO) const {
912b8038a91SHeejin Ahn   // ISel process runs DAGCombiner after legalization; this step is called
913b8038a91SHeejin Ahn   // SelectionDAG optimization phase. This post-legalization combining process
914b8038a91SHeejin Ahn   // runs DAGCombiner on each node, and if there was a change to be made,
915b8038a91SHeejin Ahn   // re-runs legalization again on it and its user nodes to make sure
916b8038a91SHeejin Ahn   // everythiing is in a legalized state.
917b8038a91SHeejin Ahn   //
918b8038a91SHeejin Ahn   // The legalization calls lowering routines, and we do our custom lowering for
919b8038a91SHeejin Ahn   // build_vectors (LowerBUILD_VECTOR), which converts undef vector elements
920b8038a91SHeejin Ahn   // into zeros. But there is a set of routines in DAGCombiner that turns unused
921b8038a91SHeejin Ahn   // (= not demanded) nodes into undef, among which SimplifyDemandedVectorElts
922b8038a91SHeejin Ahn   // turns unused vector elements into undefs. But this routine does not work
923b8038a91SHeejin Ahn   // with our custom LowerBUILD_VECTOR, which turns undefs into zeros. This
924b8038a91SHeejin Ahn   // combination can result in a infinite loop, in which undefs are converted to
925b8038a91SHeejin Ahn   // zeros in legalization and back to undefs in combining.
926b8038a91SHeejin Ahn   //
927b8038a91SHeejin Ahn   // So after DAG is legalized, we prevent SimplifyDemandedVectorElts from
928b8038a91SHeejin Ahn   // running for build_vectors.
929b8038a91SHeejin Ahn   if (Op.getOpcode() == ISD::BUILD_VECTOR && TLO.LegalOps && TLO.LegalTys)
930b8038a91SHeejin Ahn     return false;
931b8038a91SHeejin Ahn   return true;
932b8038a91SHeejin Ahn }
933b8038a91SHeejin Ahn 
93410e730a2SDan Gohman //===----------------------------------------------------------------------===//
93510e730a2SDan Gohman // WebAssembly Lowering private implementation.
93610e730a2SDan Gohman //===----------------------------------------------------------------------===//
93710e730a2SDan Gohman 
93810e730a2SDan Gohman //===----------------------------------------------------------------------===//
93910e730a2SDan Gohman // Lowering Code
94010e730a2SDan Gohman //===----------------------------------------------------------------------===//
94110e730a2SDan Gohman 
fail(const SDLoc & DL,SelectionDAG & DAG,const char * Msg)94218c56a07SHeejin Ahn static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
943b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
944b9073fb2SJF Bastien   DAG.getContext()->diagnose(
94518c56a07SHeejin Ahn       DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
946b9073fb2SJF Bastien }
947b9073fb2SJF Bastien 
94885dbdda1SDan Gohman // Test whether the given calling convention is supported.
callingConvSupported(CallingConv::ID CallConv)94918c56a07SHeejin Ahn static bool callingConvSupported(CallingConv::ID CallConv) {
95085dbdda1SDan Gohman   // We currently support the language-independent target-independent
9511ce2b1afSDan Gohman   // conventions. We don't yet have a way to annotate calls with properties like
9521ce2b1afSDan Gohman   // "cold", and we don't have any call-clobbered registers, so these are mostly
9531ce2b1afSDan Gohman   // all handled the same.
954a3f5ce5fSDan Gohman   return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
9551ce2b1afSDan Gohman          CallConv == CallingConv::Cold ||
9561ce2b1afSDan Gohman          CallConv == CallingConv::PreserveMost ||
9571ce2b1afSDan Gohman          CallConv == CallingConv::PreserveAll ||
9585c3cdef8SKeno Fischer          CallConv == CallingConv::CXX_FAST_TLS ||
959c5bd3d07SYuta Saito          CallConv == CallingConv::WASM_EmscriptenInvoke ||
960c5bd3d07SYuta Saito          CallConv == CallingConv::Swift;
96185dbdda1SDan Gohman }
96285dbdda1SDan Gohman 
963f208f631SHeejin Ahn SDValue
LowerCall(CallLoweringInfo & CLI,SmallVectorImpl<SDValue> & InVals) const964f208f631SHeejin Ahn WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
965f208f631SHeejin Ahn                                      SmallVectorImpl<SDValue> &InVals) const {
966d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
967d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
968d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
969d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
970d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
971992d83fdSDerek Schuff   auto Layout = MF.getDataLayout();
972d8a9d66dSJF Bastien 
973d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
97418c56a07SHeejin Ahn   if (!callingConvSupported(CallConv))
9759cc692b0SDan Gohman     fail(DL, DAG,
9769cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
9779cc692b0SDan Gohman          "calling conventions yet");
978d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
979d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
980d8a9d66dSJF Bastien 
981e0a9dce5SThomas Lively   if (CLI.IsTailCall) {
982918e9055SThomas Lively     auto NoTail = [&](const char *Msg) {
983113f37a1SCraig Topper       if (CLI.CB && CLI.CB->isMustTailCall())
984918e9055SThomas Lively         fail(DL, DAG, Msg);
985918e9055SThomas Lively       CLI.IsTailCall = false;
986918e9055SThomas Lively     };
987918e9055SThomas Lively 
988918e9055SThomas Lively     if (!Subtarget->hasTailCall())
989918e9055SThomas Lively       NoTail("WebAssembly 'tail-call' feature not enabled");
990918e9055SThomas Lively 
991918e9055SThomas Lively     // Varargs calls cannot be tail calls because the buffer is on the stack
992918e9055SThomas Lively     if (CLI.IsVarArg)
993918e9055SThomas Lively       NoTail("WebAssembly does not support varargs tail calls");
994918e9055SThomas Lively 
995e0a9dce5SThomas Lively     // Do not tail call unless caller and callee return types match
996e0a9dce5SThomas Lively     const Function &F = MF.getFunction();
997e0a9dce5SThomas Lively     const TargetMachine &TM = getTargetMachine();
998e0a9dce5SThomas Lively     Type *RetTy = F.getReturnType();
999e0a9dce5SThomas Lively     SmallVector<MVT, 4> CallerRetTys;
1000e0a9dce5SThomas Lively     SmallVector<MVT, 4> CalleeRetTys;
1001e0a9dce5SThomas Lively     computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
1002e0a9dce5SThomas Lively     computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys);
1003e0a9dce5SThomas Lively     bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() &&
1004e0a9dce5SThomas Lively                       std::equal(CallerRetTys.begin(), CallerRetTys.end(),
1005e0a9dce5SThomas Lively                                  CalleeRetTys.begin());
1006918e9055SThomas Lively     if (!TypesMatch)
1007918e9055SThomas Lively       NoTail("WebAssembly tail call requires caller and callee return types to "
1008918e9055SThomas Lively              "match");
1009918e9055SThomas Lively 
1010918e9055SThomas Lively     // If pointers to local stack values are passed, we cannot tail call
1011113f37a1SCraig Topper     if (CLI.CB) {
1012113f37a1SCraig Topper       for (auto &Arg : CLI.CB->args()) {
1013918e9055SThomas Lively         Value *Val = Arg.get();
1014918e9055SThomas Lively         // Trace the value back through pointer operations
1015918e9055SThomas Lively         while (true) {
1016918e9055SThomas Lively           Value *Src = Val->stripPointerCastsAndAliases();
1017918e9055SThomas Lively           if (auto *GEP = dyn_cast<GetElementPtrInst>(Src))
1018918e9055SThomas Lively             Src = GEP->getPointerOperand();
1019918e9055SThomas Lively           if (Val == Src)
1020918e9055SThomas Lively             break;
1021918e9055SThomas Lively           Val = Src;
1022a1d97a96SThomas Lively         }
1023918e9055SThomas Lively         if (isa<AllocaInst>(Val)) {
1024918e9055SThomas Lively           NoTail(
1025918e9055SThomas Lively               "WebAssembly does not support tail calling with stack arguments");
1026918e9055SThomas Lively           break;
1027e0a9dce5SThomas Lively         }
1028e0a9dce5SThomas Lively       }
1029e0a9dce5SThomas Lively     }
1030e0a9dce5SThomas Lively   }
10319cc692b0SDan Gohman 
1032d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
10332d822e73SDan Gohman   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
10344dd67786SDerek Schuff   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
10355c3cdef8SKeno Fischer 
10365c3cdef8SKeno Fischer   // The generic code may have added an sret argument. If we're lowering an
10375c3cdef8SKeno Fischer   // invoke function, the ABI requires that the function pointer be the first
10385c3cdef8SKeno Fischer   // argument, so we may have to swap the arguments.
10395c3cdef8SKeno Fischer   if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 &&
10405c3cdef8SKeno Fischer       Outs[0].Flags.isSRet()) {
10415c3cdef8SKeno Fischer     std::swap(Outs[0], Outs[1]);
10425c3cdef8SKeno Fischer     std::swap(OutVals[0], OutVals[1]);
10435c3cdef8SKeno Fischer   }
10445c3cdef8SKeno Fischer 
104508670d43SYuta Saito   bool HasSwiftSelfArg = false;
104608670d43SYuta Saito   bool HasSwiftErrorArg = false;
1047910ba33dSDan Gohman   unsigned NumFixedArgs = 0;
104818c56a07SHeejin Ahn   for (unsigned I = 0; I < Outs.size(); ++I) {
104918c56a07SHeejin Ahn     const ISD::OutputArg &Out = Outs[I];
105018c56a07SHeejin Ahn     SDValue &OutVal = OutVals[I];
105108670d43SYuta Saito     HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
105208670d43SYuta Saito     HasSwiftErrorArg |= Out.Flags.isSwiftError();
10537935fa3dSDan Gohman     if (Out.Flags.isNest())
10547935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
10552d822e73SDan Gohman     if (Out.Flags.isInAlloca())
10567935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
10572d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegs())
10587935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
10592d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
10607935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1061a6771b37SDan Gohman     if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
1062941a705bSMatthias Braun       auto &MFI = MF.getFrameInfo();
1063941a705bSMatthias Braun       int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
1064333f2ad8SGuillaume Chatelet                                      Out.Flags.getNonZeroByValAlign(),
10654dd67786SDerek Schuff                                      /*isSS=*/false);
10664dd67786SDerek Schuff       SDValue SizeNode =
10674dd67786SDerek Schuff           DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
1068992d83fdSDerek Schuff       SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
10694dd67786SDerek Schuff       Chain = DAG.getMemcpy(
1070333f2ad8SGuillaume Chatelet           Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getNonZeroByValAlign(),
1071476ffcecSDan Gohman           /*isVolatile*/ false, /*AlwaysInline=*/false,
10724dd67786SDerek Schuff           /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
10734dd67786SDerek Schuff       OutVal = FINode;
10744dd67786SDerek Schuff     }
1075910ba33dSDan Gohman     // Count the number of fixed args *after* legalization.
1076910ba33dSDan Gohman     NumFixedArgs += Out.IsFixed;
10772d822e73SDan Gohman   }
10782d822e73SDan Gohman 
1079d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
1080992d83fdSDerek Schuff   auto PtrVT = getPointerTy(Layout);
1081e590b33bSDan Gohman 
108208670d43SYuta Saito   // For swiftcc, emit additional swiftself and swifterror arguments
108308670d43SYuta Saito   // if there aren't. These additional arguments are also added for callee
108408670d43SYuta Saito   // signature They are necessary to match callee and caller signature for
108508670d43SYuta Saito   // indirect call.
108608670d43SYuta Saito   if (CallConv == CallingConv::Swift) {
108708670d43SYuta Saito     if (!HasSwiftSelfArg) {
108808670d43SYuta Saito       NumFixedArgs++;
108908670d43SYuta Saito       ISD::OutputArg Arg;
109008670d43SYuta Saito       Arg.Flags.setSwiftSelf();
109108670d43SYuta Saito       CLI.Outs.push_back(Arg);
109208670d43SYuta Saito       SDValue ArgVal = DAG.getUNDEF(PtrVT);
109308670d43SYuta Saito       CLI.OutVals.push_back(ArgVal);
109408670d43SYuta Saito     }
109508670d43SYuta Saito     if (!HasSwiftErrorArg) {
109608670d43SYuta Saito       NumFixedArgs++;
109708670d43SYuta Saito       ISD::OutputArg Arg;
109808670d43SYuta Saito       Arg.Flags.setSwiftError();
109908670d43SYuta Saito       CLI.Outs.push_back(Arg);
110008670d43SYuta Saito       SDValue ArgVal = DAG.getUNDEF(PtrVT);
110108670d43SYuta Saito       CLI.OutVals.push_back(ArgVal);
110208670d43SYuta Saito     }
110308670d43SYuta Saito   }
110408670d43SYuta Saito 
1105d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
1106d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
1107d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
1108d8a9d66dSJF Bastien 
110935bfb24cSDan Gohman   if (IsVarArg) {
111027501e20SDerek Schuff     // Outgoing non-fixed arguments are placed in a buffer. First
111127501e20SDerek Schuff     // compute their offsets and the total amount of buffer space needed.
1112c71132c0SDan Gohman     for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
1113c71132c0SDan Gohman       const ISD::OutputArg &Out = Outs[I];
1114c71132c0SDan Gohman       SDValue &Arg = OutVals[I];
111535bfb24cSDan Gohman       EVT VT = Arg.getValueType();
111635bfb24cSDan Gohman       assert(VT != MVT::iPTR && "Legalized args should be concrete");
111735bfb24cSDan Gohman       Type *Ty = VT.getTypeForEVT(*DAG.getContext());
11181778564fSGuillaume Chatelet       Align Alignment =
11192e7bba69SGuillaume Chatelet           std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty));
11201778564fSGuillaume Chatelet       unsigned Offset =
11211778564fSGuillaume Chatelet           CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment);
112235bfb24cSDan Gohman       CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
112335bfb24cSDan Gohman                                         Offset, VT.getSimpleVT(),
112435bfb24cSDan Gohman                                         CCValAssign::Full));
112535bfb24cSDan Gohman     }
112635bfb24cSDan Gohman   }
112735bfb24cSDan Gohman 
112835bfb24cSDan Gohman   unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
112935bfb24cSDan Gohman 
113027501e20SDerek Schuff   SDValue FINode;
113127501e20SDerek Schuff   if (IsVarArg && NumBytes) {
113235bfb24cSDan Gohman     // For non-fixed arguments, next emit stores to store the argument values
113327501e20SDerek Schuff     // to the stack buffer at the offsets computed above.
1134941a705bSMatthias Braun     int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
1135992d83fdSDerek Schuff                                                  Layout.getStackAlignment(),
113627501e20SDerek Schuff                                                  /*isSS=*/false);
113735bfb24cSDan Gohman     unsigned ValNo = 0;
113835bfb24cSDan Gohman     SmallVector<SDValue, 8> Chains;
11392efcbe24SKazu Hirata     for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) {
114035bfb24cSDan Gohman       assert(ArgLocs[ValNo].getValNo() == ValNo &&
114135bfb24cSDan Gohman              "ArgLocs should remain in order and only hold varargs args");
114235bfb24cSDan Gohman       unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
1143992d83fdSDerek Schuff       FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
114427501e20SDerek Schuff       SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
114535bfb24cSDan Gohman                                 DAG.getConstant(Offset, DL, PtrVT));
1146f208f631SHeejin Ahn       Chains.push_back(
1147f208f631SHeejin Ahn           DAG.getStore(Chain, DL, Arg, Add,
1148c193a689SCraig Topper                        MachinePointerInfo::getFixedStack(MF, FI, Offset)));
114935bfb24cSDan Gohman     }
115035bfb24cSDan Gohman     if (!Chains.empty())
115135bfb24cSDan Gohman       Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
115227501e20SDerek Schuff   } else if (IsVarArg) {
115327501e20SDerek Schuff     FINode = DAG.getIntPtrConstant(0, DL);
115435bfb24cSDan Gohman   }
115535bfb24cSDan Gohman 
1156492f7529SSam Clegg   if (Callee->getOpcode() == ISD::GlobalAddress) {
1157492f7529SSam Clegg     // If the callee is a GlobalAddress node (quite common, every direct call
1158492f7529SSam Clegg     // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
1159492f7529SSam Clegg     // doesn't at MO_GOT which is not needed for direct calls.
1160492f7529SSam Clegg     GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Callee);
1161492f7529SSam Clegg     Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL,
1162492f7529SSam Clegg                                         getPointerTy(DAG.getDataLayout()),
1163492f7529SSam Clegg                                         GA->getOffset());
1164492f7529SSam Clegg     Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
1165492f7529SSam Clegg                          getPointerTy(DAG.getDataLayout()), Callee);
1166492f7529SSam Clegg   }
1167492f7529SSam Clegg 
116835bfb24cSDan Gohman   // Compute the operands for the CALLn node.
1169d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
1170d8a9d66dSJF Bastien   Ops.push_back(Chain);
1171af111db8SJF Bastien   Ops.push_back(Callee);
117235bfb24cSDan Gohman 
117335bfb24cSDan Gohman   // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
117435bfb24cSDan Gohman   // isn't reliable.
117535bfb24cSDan Gohman   Ops.append(OutVals.begin(),
117635bfb24cSDan Gohman              IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
117727501e20SDerek Schuff   // Add a pointer to the vararg buffer.
1178f208f631SHeejin Ahn   if (IsVarArg)
1179f208f631SHeejin Ahn     Ops.push_back(FINode);
1180d8a9d66dSJF Bastien 
118127501e20SDerek Schuff   SmallVector<EVT, 8> InTys;
11822d822e73SDan Gohman   for (const auto &In : Ins) {
11837935fa3dSDan Gohman     assert(!In.Flags.isByVal() && "byval is not valid for return values");
11847935fa3dSDan Gohman     assert(!In.Flags.isNest() && "nest is not valid for return values");
11852d822e73SDan Gohman     if (In.Flags.isInAlloca())
11867935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
11872d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegs())
11887935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
11892d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegsLast())
11904b9d7916SDan Gohman       fail(DL, DAG,
11914b9d7916SDan Gohman            "WebAssembly hasn't implemented cons regs last return values");
11922e7bba69SGuillaume Chatelet     // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
11932d822e73SDan Gohman     // registers.
119427501e20SDerek Schuff     InTys.push_back(In.VT);
11952d822e73SDan Gohman   }
1196a1d97a96SThomas Lively 
119746667a10SPaulo Matos   // Lastly, if this is a call to a funcref we need to add an instruction
119846667a10SPaulo Matos   // table.set to the chain and transform the call.
119991fe069cSPaulo Matos   if (CLI.CB &&
120091fe069cSPaulo Matos       WebAssembly::isFuncrefType(CLI.CB->getCalledOperand()->getType())) {
120146667a10SPaulo Matos     // In the absence of function references proposal where a funcref call is
120246667a10SPaulo Matos     // lowered to call_ref, using reference types we generate a table.set to set
120346667a10SPaulo Matos     // the funcref to a special table used solely for this purpose, followed by
120446667a10SPaulo Matos     // a call_indirect. Here we just generate the table set, and return the
120546667a10SPaulo Matos     // SDValue of the table.set so that LowerCall can finalize the lowering by
120646667a10SPaulo Matos     // generating the call_indirect.
120746667a10SPaulo Matos     SDValue Chain = Ops[0];
120846667a10SPaulo Matos 
120946667a10SPaulo Matos     MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol(
121046667a10SPaulo Matos         MF.getContext(), Subtarget);
121146667a10SPaulo Matos     SDValue Sym = DAG.getMCSymbol(Table, PtrVT);
121246667a10SPaulo Matos     SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32);
121346667a10SPaulo Matos     SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee};
121446667a10SPaulo Matos     SDValue TableSet = DAG.getMemIntrinsicNode(
121546667a10SPaulo Matos         WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps,
121646667a10SPaulo Matos         MVT::funcref,
121746667a10SPaulo Matos         // Machine Mem Operand args
121891fe069cSPaulo Matos         MachinePointerInfo(
121991fe069cSPaulo Matos             WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF),
122046667a10SPaulo Matos         CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()),
122146667a10SPaulo Matos         MachineMemOperand::MOStore);
122246667a10SPaulo Matos 
122346667a10SPaulo Matos     Ops[0] = TableSet; // The new chain is the TableSet itself
122446667a10SPaulo Matos   }
122546667a10SPaulo Matos 
1226a1d97a96SThomas Lively   if (CLI.IsTailCall) {
1227a1d97a96SThomas Lively     // ret_calls do not return values to the current frame
1228a1d97a96SThomas Lively     SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
1229a1d97a96SThomas Lively     return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops);
1230a1d97a96SThomas Lively   }
1231a1d97a96SThomas Lively 
123227501e20SDerek Schuff   InTys.push_back(MVT::Other);
12337b64a590SThomas Lively   SDVTList InTyList = DAG.getVTList(InTys);
1234ca9ba764SThomas Lively   SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops);
1235d8a9d66dSJF Bastien 
12367b64a590SThomas Lively   for (size_t I = 0; I < Ins.size(); ++I)
12377b64a590SThomas Lively     InVals.push_back(Res.getValue(I));
12387b64a590SThomas Lively 
12397b64a590SThomas Lively   // Return the chain
12407b64a590SThomas Lively   return Res.getValue(Ins.size());
1241d8a9d66dSJF Bastien }
1242d8a9d66dSJF Bastien 
CanLowerReturn(CallingConv::ID,MachineFunction &,bool,const SmallVectorImpl<ISD::OutputArg> & Outs,LLVMContext &) const1243b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
12447a6b9825SDan Gohman     CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
12457a6b9825SDan Gohman     const SmallVectorImpl<ISD::OutputArg> &Outs,
12467a6b9825SDan Gohman     LLVMContext & /*Context*/) const {
124700f9e5aaSThomas Lively   // WebAssembly can only handle returning tuples with multivalue enabled
124800f9e5aaSThomas Lively   return Subtarget->hasMultivalue() || Outs.size() <= 1;
1249b9073fb2SJF Bastien }
1250b9073fb2SJF Bastien 
LowerReturn(SDValue Chain,CallingConv::ID CallConv,bool,const SmallVectorImpl<ISD::OutputArg> & Outs,const SmallVectorImpl<SDValue> & OutVals,const SDLoc & DL,SelectionDAG & DAG) const1251b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
125235bfb24cSDan Gohman     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
1253b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
1254bdc4956bSBenjamin Kramer     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
1255b9073fb2SJF Bastien     SelectionDAG &DAG) const {
1256788ba151SSimon Pilgrim   assert((Subtarget->hasMultivalue() || Outs.size() <= 1) &&
1257788ba151SSimon Pilgrim          "MVP WebAssembly can only return up to one value");
125818c56a07SHeejin Ahn   if (!callingConvSupported(CallConv))
1259b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1260b9073fb2SJF Bastien 
1261600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
1262600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
12634a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
1264b9073fb2SJF Bastien 
1265754cd11dSDan Gohman   // Record the number and types of the return values.
1266754cd11dSDan Gohman   for (const ISD::OutputArg &Out : Outs) {
1267ac132e93SDan Gohman     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
1268ac132e93SDan Gohman     assert(!Out.Flags.isNest() && "nest is not valid for return values");
126935bfb24cSDan Gohman     assert(Out.IsFixed && "non-fixed return value is not valid");
1270754cd11dSDan Gohman     if (Out.Flags.isInAlloca())
1271754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
1272754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegs())
1273754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
1274754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
1275754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
1276754cd11dSDan Gohman   }
1277754cd11dSDan Gohman 
1278b9073fb2SJF Bastien   return Chain;
1279b9073fb2SJF Bastien }
1280b9073fb2SJF Bastien 
LowerFormalArguments(SDValue Chain,CallingConv::ID CallConv,bool IsVarArg,const SmallVectorImpl<ISD::InputArg> & Ins,const SDLoc & DL,SelectionDAG & DAG,SmallVectorImpl<SDValue> & InVals) const1281b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
128227501e20SDerek Schuff     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
1283bdc4956bSBenjamin Kramer     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
1284bdc4956bSBenjamin Kramer     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
128518c56a07SHeejin Ahn   if (!callingConvSupported(CallConv))
1286b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1287b9073fb2SJF Bastien 
12882726b88cSDan Gohman   MachineFunction &MF = DAG.getMachineFunction();
12892726b88cSDan Gohman   auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
12902726b88cSDan Gohman 
1291fb3e0594SDan Gohman   // Set up the incoming ARGUMENTS value, which serves to represent the liveness
1292fb3e0594SDan Gohman   // of the incoming values before they're represented by virtual registers.
1293fb3e0594SDan Gohman   MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
1294fb3e0594SDan Gohman 
129508670d43SYuta Saito   bool HasSwiftErrorArg = false;
129608670d43SYuta Saito   bool HasSwiftSelfArg = false;
1297600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
129808670d43SYuta Saito     HasSwiftSelfArg |= In.Flags.isSwiftSelf();
129908670d43SYuta Saito     HasSwiftErrorArg |= In.Flags.isSwiftError();
1300600aee98SJF Bastien     if (In.Flags.isInAlloca())
1301600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1302600aee98SJF Bastien     if (In.Flags.isNest())
1303600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1304600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
1305600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1306600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
1307600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
13082e7bba69SGuillaume Chatelet     // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
13099c54d3b4SDan Gohman     // registers.
1310f208f631SHeejin Ahn     InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
1311f208f631SHeejin Ahn                                            DAG.getTargetConstant(InVals.size(),
1312f208f631SHeejin Ahn                                                                  DL, MVT::i32))
1313cb7940f9SDan Gohman                              : DAG.getUNDEF(In.VT));
1314754cd11dSDan Gohman 
1315754cd11dSDan Gohman     // Record the number and types of arguments.
131627501e20SDerek Schuff     MFI->addParam(In.VT);
1317600aee98SJF Bastien   }
1318b9073fb2SJF Bastien 
131908670d43SYuta Saito   // For swiftcc, emit additional swiftself and swifterror arguments
132008670d43SYuta Saito   // if there aren't. These additional arguments are also added for callee
132108670d43SYuta Saito   // signature They are necessary to match callee and caller signature for
132208670d43SYuta Saito   // indirect call.
132308670d43SYuta Saito   auto PtrVT = getPointerTy(MF.getDataLayout());
132408670d43SYuta Saito   if (CallConv == CallingConv::Swift) {
132508670d43SYuta Saito     if (!HasSwiftSelfArg) {
132608670d43SYuta Saito       MFI->addParam(PtrVT);
132708670d43SYuta Saito     }
132808670d43SYuta Saito     if (!HasSwiftErrorArg) {
132908670d43SYuta Saito       MFI->addParam(PtrVT);
133008670d43SYuta Saito     }
133108670d43SYuta Saito   }
133227501e20SDerek Schuff   // Varargs are copied into a buffer allocated by the caller, and a pointer to
133327501e20SDerek Schuff   // the buffer is passed as an argument.
133427501e20SDerek Schuff   if (IsVarArg) {
133527501e20SDerek Schuff     MVT PtrVT = getPointerTy(MF.getDataLayout());
133605c145d6SDaniel Sanders     Register VarargVreg =
133727501e20SDerek Schuff         MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT));
133827501e20SDerek Schuff     MFI->setVarargBufferVreg(VarargVreg);
133927501e20SDerek Schuff     Chain = DAG.getCopyToReg(
134027501e20SDerek Schuff         Chain, DL, VarargVreg,
134127501e20SDerek Schuff         DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
134227501e20SDerek Schuff                     DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
134327501e20SDerek Schuff     MFI->addParam(PtrVT);
134427501e20SDerek Schuff   }
134535bfb24cSDan Gohman 
134677a7a380SDerek Schuff   // Record the number and types of arguments and results.
13472726b88cSDan Gohman   SmallVector<MVT, 4> Params;
13482726b88cSDan Gohman   SmallVector<MVT, 4> Results;
134908670d43SYuta Saito   computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(),
135008670d43SYuta Saito                       MF.getFunction(), DAG.getTarget(), Params, Results);
13512726b88cSDan Gohman   for (MVT VT : Results)
13522726b88cSDan Gohman     MFI->addResult(VT);
135377a7a380SDerek Schuff   // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
135477a7a380SDerek Schuff   // the param logic here with ComputeSignatureVTs
135577a7a380SDerek Schuff   assert(MFI->getParams().size() == Params.size() &&
135677a7a380SDerek Schuff          std::equal(MFI->getParams().begin(), MFI->getParams().end(),
135777a7a380SDerek Schuff                     Params.begin()));
13582726b88cSDan Gohman 
1359b9073fb2SJF Bastien   return Chain;
1360b9073fb2SJF Bastien }
1361b9073fb2SJF Bastien 
ReplaceNodeResults(SDNode * N,SmallVectorImpl<SDValue> & Results,SelectionDAG & DAG) const1362e18b5c62SThomas Lively void WebAssemblyTargetLowering::ReplaceNodeResults(
1363e18b5c62SThomas Lively     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
1364e18b5c62SThomas Lively   switch (N->getOpcode()) {
1365e18b5c62SThomas Lively   case ISD::SIGN_EXTEND_INREG:
1366e18b5c62SThomas Lively     // Do not add any results, signifying that N should not be custom lowered
1367e18b5c62SThomas Lively     // after all. This happens because simd128 turns on custom lowering for
1368e18b5c62SThomas Lively     // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
1369e18b5c62SThomas Lively     // illegal type.
1370e18b5c62SThomas Lively     break;
1371e18b5c62SThomas Lively   default:
1372e18b5c62SThomas Lively     llvm_unreachable(
1373e18b5c62SThomas Lively         "ReplaceNodeResults not implemented for this op for WebAssembly!");
1374e18b5c62SThomas Lively   }
1375e18b5c62SThomas Lively }
1376e18b5c62SThomas Lively 
137710e730a2SDan Gohman //===----------------------------------------------------------------------===//
1378af111db8SJF Bastien //  Custom lowering hooks.
137910e730a2SDan Gohman //===----------------------------------------------------------------------===//
138010e730a2SDan Gohman 
LowerOperation(SDValue Op,SelectionDAG & DAG) const1381af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
1382af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
138351699a83SDerek Schuff   SDLoc DL(Op);
1384af111db8SJF Bastien   switch (Op.getOpcode()) {
1385af111db8SJF Bastien   default:
1386af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
1387af111db8SJF Bastien     return SDValue();
13889769debfSDerek Schuff   case ISD::FrameIndex:
13899769debfSDerek Schuff     return LowerFrameIndex(Op, DAG);
1390af111db8SJF Bastien   case ISD::GlobalAddress:
1391af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
1392a083b28aSSam Clegg   case ISD::GlobalTLSAddress:
1393a083b28aSSam Clegg     return LowerGlobalTLSAddress(Op, DAG);
13942c8fe6a4SDan Gohman   case ISD::ExternalSymbol:
13952c8fe6a4SDan Gohman     return LowerExternalSymbol(Op, DAG);
1396950a13cfSDan Gohman   case ISD::JumpTable:
1397950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
1398950a13cfSDan Gohman   case ISD::BR_JT:
1399950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
140035bfb24cSDan Gohman   case ISD::VASTART:
140135bfb24cSDan Gohman     return LowerVASTART(Op, DAG);
140251699a83SDerek Schuff   case ISD::BlockAddress:
140351699a83SDerek Schuff   case ISD::BRIND:
140451699a83SDerek Schuff     fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
140551699a83SDerek Schuff     return SDValue();
14061a3cbe72SThomas Lively   case ISD::RETURNADDR:
14071a3cbe72SThomas Lively     return LowerRETURNADDR(Op, DAG);
140894c65660SDan Gohman   case ISD::FRAMEADDR:
140994c65660SDan Gohman     return LowerFRAMEADDR(Op, DAG);
1410aadc89c2SDerek Schuff   case ISD::CopyToReg:
1411aadc89c2SDerek Schuff     return LowerCopyToReg(Op, DAG);
1412fb84fd7cSThomas Lively   case ISD::EXTRACT_VECTOR_ELT:
1413fb84fd7cSThomas Lively   case ISD::INSERT_VECTOR_ELT:
1414fb84fd7cSThomas Lively     return LowerAccessVectorElement(Op, DAG);
1415da419bdbSHeejin Ahn   case ISD::INTRINSIC_VOID:
1416d6f48786SHeejin Ahn   case ISD::INTRINSIC_WO_CHAIN:
1417d6f48786SHeejin Ahn   case ISD::INTRINSIC_W_CHAIN:
1418d6f48786SHeejin Ahn     return LowerIntrinsic(Op, DAG);
141964a39a1cSThomas Lively   case ISD::SIGN_EXTEND_INREG:
142064a39a1cSThomas Lively     return LowerSIGN_EXTEND_INREG(Op, DAG);
1421079816efSThomas Lively   case ISD::BUILD_VECTOR:
1422079816efSThomas Lively     return LowerBUILD_VECTOR(Op, DAG);
1423a0d25815SThomas Lively   case ISD::VECTOR_SHUFFLE:
1424a0d25815SThomas Lively     return LowerVECTOR_SHUFFLE(Op, DAG);
1425ecb7daf6SThomas Lively   case ISD::SETCC:
1426ecb7daf6SThomas Lively     return LowerSETCC(Op, DAG);
142755735d52SThomas Lively   case ISD::SHL:
142855735d52SThomas Lively   case ISD::SRA:
142955735d52SThomas Lively   case ISD::SRL:
143055735d52SThomas Lively     return LowerShift(Op, DAG);
14315c729750SThomas Lively   case ISD::FP_TO_SINT_SAT:
14325c729750SThomas Lively   case ISD::FP_TO_UINT_SAT:
14335c729750SThomas Lively     return LowerFP_TO_INT_SAT(Op, DAG);
1434d7086af2SPaulo Matos   case ISD::LOAD:
1435d7086af2SPaulo Matos     return LowerLoad(Op, DAG);
1436d7086af2SPaulo Matos   case ISD::STORE:
1437d7086af2SPaulo Matos     return LowerStore(Op, DAG);
1438fe1f0de0SCraig Topper   case ISD::CTPOP:
1439fe1f0de0SCraig Topper   case ISD::CTLZ:
1440fe1f0de0SCraig Topper   case ISD::CTTZ:
1441fe1f0de0SCraig Topper     return DAG.UnrollVectorOp(Op.getNode());
1442af111db8SJF Bastien   }
1443af111db8SJF Bastien }
1444af111db8SJF Bastien 
IsWebAssemblyGlobal(SDValue Op)1445d7086af2SPaulo Matos static bool IsWebAssemblyGlobal(SDValue Op) {
1446d7086af2SPaulo Matos   if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op))
1447d7086af2SPaulo Matos     return WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace());
1448d7086af2SPaulo Matos 
1449d7086af2SPaulo Matos   return false;
1450d7086af2SPaulo Matos }
1451d7086af2SPaulo Matos 
IsWebAssemblyLocal(SDValue Op,SelectionDAG & DAG)145282f92e35SAndy Wingo static Optional<unsigned> IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG) {
145382f92e35SAndy Wingo   const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op);
145482f92e35SAndy Wingo   if (!FI)
145582f92e35SAndy Wingo     return None;
145682f92e35SAndy Wingo 
145782f92e35SAndy Wingo   auto &MF = DAG.getMachineFunction();
145882f92e35SAndy Wingo   return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex());
145982f92e35SAndy Wingo }
146082f92e35SAndy Wingo 
IsWebAssemblyTable(SDValue Op)14616d0c7bc1SPaulo Matos static bool IsWebAssemblyTable(SDValue Op) {
14626d0c7bc1SPaulo Matos   const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op);
14636d0c7bc1SPaulo Matos   if (GA && WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace())) {
14646d0c7bc1SPaulo Matos     const GlobalValue *Value = GA->getGlobal();
14656d0c7bc1SPaulo Matos     const Type *Ty = Value->getValueType();
14666d0c7bc1SPaulo Matos 
14676d0c7bc1SPaulo Matos     if (Ty->isArrayTy() && WebAssembly::isRefType(Ty->getArrayElementType()))
14686d0c7bc1SPaulo Matos       return true;
14696d0c7bc1SPaulo Matos   }
14706d0c7bc1SPaulo Matos   return false;
14716d0c7bc1SPaulo Matos }
14726d0c7bc1SPaulo Matos 
14736d0c7bc1SPaulo Matos // This function will accept as Op any access to a table, so Op can
14746d0c7bc1SPaulo Matos // be the actual table or an offset into the table.
IsWebAssemblyTableWithOffset(SDValue Op)14756d0c7bc1SPaulo Matos static bool IsWebAssemblyTableWithOffset(SDValue Op) {
14766d0c7bc1SPaulo Matos   if (Op->getOpcode() == ISD::ADD && Op->getNumOperands() == 2)
14776d0c7bc1SPaulo Matos     return (Op->getOperand(1).getSimpleValueType() == MVT::i32 &&
14786d0c7bc1SPaulo Matos             IsWebAssemblyTableWithOffset(Op->getOperand(0))) ||
14796d0c7bc1SPaulo Matos            (Op->getOperand(0).getSimpleValueType() == MVT::i32 &&
14806d0c7bc1SPaulo Matos             IsWebAssemblyTableWithOffset(Op->getOperand(1)));
14816d0c7bc1SPaulo Matos 
14826d0c7bc1SPaulo Matos   return IsWebAssemblyTable(Op);
14836d0c7bc1SPaulo Matos }
14846d0c7bc1SPaulo Matos 
14856d0c7bc1SPaulo Matos // Helper for table pattern matching used in LowerStore and LowerLoad
MatchTableForLowering(SelectionDAG & DAG,const SDLoc & DL,const SDValue & Base,GlobalAddressSDNode * & GA,SDValue & Idx) const14866d0c7bc1SPaulo Matos bool WebAssemblyTargetLowering::MatchTableForLowering(SelectionDAG &DAG,
14876d0c7bc1SPaulo Matos                                                       const SDLoc &DL,
14886d0c7bc1SPaulo Matos                                                       const SDValue &Base,
14896d0c7bc1SPaulo Matos                                                       GlobalAddressSDNode *&GA,
14906d0c7bc1SPaulo Matos                                                       SDValue &Idx) const {
14916d0c7bc1SPaulo Matos   // We expect the following graph for a load of the form:
14926d0c7bc1SPaulo Matos   // table[<var> + <constant offset>]
14936d0c7bc1SPaulo Matos   //
14946d0c7bc1SPaulo Matos   // Case 1:
14956d0c7bc1SPaulo Matos   // externref = load t1
14966d0c7bc1SPaulo Matos   // t1: i32 = add t2, i32:<constant offset>
14976d0c7bc1SPaulo Matos   // t2: i32 = add tX, table
14986d0c7bc1SPaulo Matos   //
14996d0c7bc1SPaulo Matos   // This is in some cases simplified to just:
15006d0c7bc1SPaulo Matos   // Case 2:
15016d0c7bc1SPaulo Matos   // externref = load t1
15026d0c7bc1SPaulo Matos   // t1: i32 = add t2, i32:tX
15036d0c7bc1SPaulo Matos   //
15046d0c7bc1SPaulo Matos   // So, unfortunately we need to check for both cases and if we are in the
15056d0c7bc1SPaulo Matos   // first case extract the table GlobalAddressNode and build a new node tY
15066d0c7bc1SPaulo Matos   // that's tY: i32 = add i32:<constant offset>, i32:tX
15076d0c7bc1SPaulo Matos   //
15086d0c7bc1SPaulo Matos   if (IsWebAssemblyTable(Base)) {
15096d0c7bc1SPaulo Matos     GA = cast<GlobalAddressSDNode>(Base);
15106d0c7bc1SPaulo Matos     Idx = DAG.getConstant(0, DL, MVT::i32);
15116d0c7bc1SPaulo Matos   } else {
15126d0c7bc1SPaulo Matos     GA = dyn_cast<GlobalAddressSDNode>(Base->getOperand(0));
15136d0c7bc1SPaulo Matos     if (GA) {
15146d0c7bc1SPaulo Matos       // We are in Case 2 above.
15156d0c7bc1SPaulo Matos       Idx = Base->getOperand(1);
151697ef15adSPaulo Matos       assert(GA->getNumValues() == 1);
15176d0c7bc1SPaulo Matos     } else {
15186d0c7bc1SPaulo Matos       // This might be Case 1 above (or an error)
15196d0c7bc1SPaulo Matos       SDValue V = Base->getOperand(0);
15206d0c7bc1SPaulo Matos       GA = dyn_cast<GlobalAddressSDNode>(V->getOperand(1));
15216d0c7bc1SPaulo Matos 
15226d0c7bc1SPaulo Matos       if (V->getOpcode() != ISD::ADD || V->getNumOperands() != 2 || !GA)
15236d0c7bc1SPaulo Matos         return false;
15246d0c7bc1SPaulo Matos 
15256d0c7bc1SPaulo Matos       SDValue IdxV = DAG.getNode(ISD::ADD, DL, MVT::i32, Base->getOperand(1),
15266d0c7bc1SPaulo Matos                                  V->getOperand(0));
15276d0c7bc1SPaulo Matos       Idx = IdxV;
15286d0c7bc1SPaulo Matos     }
15296d0c7bc1SPaulo Matos   }
15306d0c7bc1SPaulo Matos 
15316d0c7bc1SPaulo Matos   return true;
15326d0c7bc1SPaulo Matos }
15336d0c7bc1SPaulo Matos 
LowerStore(SDValue Op,SelectionDAG & DAG) const1534d7086af2SPaulo Matos SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
1535d7086af2SPaulo Matos                                               SelectionDAG &DAG) const {
1536d7086af2SPaulo Matos   SDLoc DL(Op);
1537d7086af2SPaulo Matos   StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
1538d7086af2SPaulo Matos   const SDValue &Value = SN->getValue();
1539d7086af2SPaulo Matos   const SDValue &Base = SN->getBasePtr();
1540d7086af2SPaulo Matos   const SDValue &Offset = SN->getOffset();
1541d7086af2SPaulo Matos 
15426d0c7bc1SPaulo Matos   if (IsWebAssemblyTableWithOffset(Base)) {
15436d0c7bc1SPaulo Matos     if (!Offset->isUndef())
15446d0c7bc1SPaulo Matos       report_fatal_error(
15456d0c7bc1SPaulo Matos           "unexpected offset when loading from webassembly table", false);
15466d0c7bc1SPaulo Matos 
15476d0c7bc1SPaulo Matos     SDValue Idx;
15486d0c7bc1SPaulo Matos     GlobalAddressSDNode *GA;
15496d0c7bc1SPaulo Matos 
15506d0c7bc1SPaulo Matos     if (!MatchTableForLowering(DAG, DL, Base, GA, Idx))
15516d0c7bc1SPaulo Matos       report_fatal_error("failed pattern matching for lowering table store",
15526d0c7bc1SPaulo Matos                          false);
15536d0c7bc1SPaulo Matos 
15546d0c7bc1SPaulo Matos     SDVTList Tys = DAG.getVTList(MVT::Other);
15556d0c7bc1SPaulo Matos     SDValue TableSetOps[] = {SN->getChain(), SDValue(GA, 0), Idx, Value};
15566d0c7bc1SPaulo Matos     SDValue TableSet =
15576d0c7bc1SPaulo Matos         DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_SET, DL, Tys, TableSetOps,
15586d0c7bc1SPaulo Matos                                 SN->getMemoryVT(), SN->getMemOperand());
15596d0c7bc1SPaulo Matos     return TableSet;
15606d0c7bc1SPaulo Matos   }
15616d0c7bc1SPaulo Matos 
1562d7086af2SPaulo Matos   if (IsWebAssemblyGlobal(Base)) {
1563d7086af2SPaulo Matos     if (!Offset->isUndef())
1564d7086af2SPaulo Matos       report_fatal_error("unexpected offset when storing to webassembly global",
1565d7086af2SPaulo Matos                          false);
1566d7086af2SPaulo Matos 
1567d7086af2SPaulo Matos     SDVTList Tys = DAG.getVTList(MVT::Other);
1568d7086af2SPaulo Matos     SDValue Ops[] = {SN->getChain(), Value, Base};
1569d7086af2SPaulo Matos     return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops,
1570d7086af2SPaulo Matos                                    SN->getMemoryVT(), SN->getMemOperand());
1571d7086af2SPaulo Matos   }
1572d7086af2SPaulo Matos 
157382f92e35SAndy Wingo   if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
157482f92e35SAndy Wingo     if (!Offset->isUndef())
157582f92e35SAndy Wingo       report_fatal_error("unexpected offset when storing to webassembly local",
157682f92e35SAndy Wingo                          false);
157782f92e35SAndy Wingo 
157882f92e35SAndy Wingo     SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
157982f92e35SAndy Wingo     SDVTList Tys = DAG.getVTList(MVT::Other); // The chain.
158082f92e35SAndy Wingo     SDValue Ops[] = {SN->getChain(), Idx, Value};
158182f92e35SAndy Wingo     return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops);
158282f92e35SAndy Wingo   }
158382f92e35SAndy Wingo 
1584d7086af2SPaulo Matos   return Op;
1585d7086af2SPaulo Matos }
1586d7086af2SPaulo Matos 
LowerLoad(SDValue Op,SelectionDAG & DAG) const1587d7086af2SPaulo Matos SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
1588d7086af2SPaulo Matos                                              SelectionDAG &DAG) const {
1589d7086af2SPaulo Matos   SDLoc DL(Op);
1590d7086af2SPaulo Matos   LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
1591d7086af2SPaulo Matos   const SDValue &Base = LN->getBasePtr();
1592d7086af2SPaulo Matos   const SDValue &Offset = LN->getOffset();
1593d7086af2SPaulo Matos 
15946d0c7bc1SPaulo Matos   if (IsWebAssemblyTableWithOffset(Base)) {
15956d0c7bc1SPaulo Matos     if (!Offset->isUndef())
15966d0c7bc1SPaulo Matos       report_fatal_error(
15976d0c7bc1SPaulo Matos           "unexpected offset when loading from webassembly table", false);
15986d0c7bc1SPaulo Matos 
15996d0c7bc1SPaulo Matos     GlobalAddressSDNode *GA;
16006d0c7bc1SPaulo Matos     SDValue Idx;
16016d0c7bc1SPaulo Matos 
16026d0c7bc1SPaulo Matos     if (!MatchTableForLowering(DAG, DL, Base, GA, Idx))
16036d0c7bc1SPaulo Matos       report_fatal_error("failed pattern matching for lowering table load",
16046d0c7bc1SPaulo Matos                          false);
16056d0c7bc1SPaulo Matos 
16066d0c7bc1SPaulo Matos     SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other);
16076d0c7bc1SPaulo Matos     SDValue TableGetOps[] = {LN->getChain(), SDValue(GA, 0), Idx};
16086d0c7bc1SPaulo Matos     SDValue TableGet =
16096d0c7bc1SPaulo Matos         DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_GET, DL, Tys, TableGetOps,
16106d0c7bc1SPaulo Matos                                 LN->getMemoryVT(), LN->getMemOperand());
16116d0c7bc1SPaulo Matos     return TableGet;
16126d0c7bc1SPaulo Matos   }
16136d0c7bc1SPaulo Matos 
1614d7086af2SPaulo Matos   if (IsWebAssemblyGlobal(Base)) {
1615d7086af2SPaulo Matos     if (!Offset->isUndef())
1616d7086af2SPaulo Matos       report_fatal_error(
1617d7086af2SPaulo Matos           "unexpected offset when loading from webassembly global", false);
1618d7086af2SPaulo Matos 
1619d7086af2SPaulo Matos     SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other);
1620d7086af2SPaulo Matos     SDValue Ops[] = {LN->getChain(), Base};
1621d7086af2SPaulo Matos     return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops,
1622d7086af2SPaulo Matos                                    LN->getMemoryVT(), LN->getMemOperand());
1623d7086af2SPaulo Matos   }
1624d7086af2SPaulo Matos 
162582f92e35SAndy Wingo   if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
162682f92e35SAndy Wingo     if (!Offset->isUndef())
162782f92e35SAndy Wingo       report_fatal_error(
162882f92e35SAndy Wingo           "unexpected offset when loading from webassembly local", false);
162982f92e35SAndy Wingo 
163082f92e35SAndy Wingo     SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
163182f92e35SAndy Wingo     EVT LocalVT = LN->getValueType(0);
163282f92e35SAndy Wingo     SDValue LocalGet = DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, LocalVT,
163382f92e35SAndy Wingo                                    {LN->getChain(), Idx});
163482f92e35SAndy Wingo     SDValue Result = DAG.getMergeValues({LocalGet, LN->getChain()}, DL);
163582f92e35SAndy Wingo     assert(Result->getNumValues() == 2 && "Loads must carry a chain!");
163682f92e35SAndy Wingo     return Result;
163782f92e35SAndy Wingo   }
163882f92e35SAndy Wingo 
1639d7086af2SPaulo Matos   return Op;
1640d7086af2SPaulo Matos }
1641d7086af2SPaulo Matos 
LowerCopyToReg(SDValue Op,SelectionDAG & DAG) const1642aadc89c2SDerek Schuff SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
1643aadc89c2SDerek Schuff                                                   SelectionDAG &DAG) const {
1644aadc89c2SDerek Schuff   SDValue Src = Op.getOperand(2);
1645aadc89c2SDerek Schuff   if (isa<FrameIndexSDNode>(Src.getNode())) {
1646aadc89c2SDerek Schuff     // CopyToReg nodes don't support FrameIndex operands. Other targets select
1647aadc89c2SDerek Schuff     // the FI to some LEA-like instruction, but since we don't have that, we
1648aadc89c2SDerek Schuff     // need to insert some kind of instruction that can take an FI operand and
1649aadc89c2SDerek Schuff     // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
16506a87ddacSThomas Lively     // local.copy between Op and its FI operand.
165102c0871aSDan Gohman     SDValue Chain = Op.getOperand(0);
1652aadc89c2SDerek Schuff     SDLoc DL(Op);
1653d6b07348SJim Lin     Register Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
1654aadc89c2SDerek Schuff     EVT VT = Src.getValueType();
1655f208f631SHeejin Ahn     SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
16564fc4e42dSDan Gohman                                                    : WebAssembly::COPY_I64,
1657aadc89c2SDerek Schuff                                     DL, VT, Src),
1658aadc89c2SDerek Schuff                  0);
165902c0871aSDan Gohman     return Op.getNode()->getNumValues() == 1
166002c0871aSDan Gohman                ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
1661f208f631SHeejin Ahn                : DAG.getCopyToReg(Chain, DL, Reg, Copy,
1662f208f631SHeejin Ahn                                   Op.getNumOperands() == 4 ? Op.getOperand(3)
166302c0871aSDan Gohman                                                            : SDValue());
1664aadc89c2SDerek Schuff   }
1665aadc89c2SDerek Schuff   return SDValue();
1666aadc89c2SDerek Schuff }
1667aadc89c2SDerek Schuff 
LowerFrameIndex(SDValue Op,SelectionDAG & DAG) const16689769debfSDerek Schuff SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
16699769debfSDerek Schuff                                                    SelectionDAG &DAG) const {
16709769debfSDerek Schuff   int FI = cast<FrameIndexSDNode>(Op)->getIndex();
16719769debfSDerek Schuff   return DAG.getTargetFrameIndex(FI, Op.getValueType());
16729769debfSDerek Schuff }
16739769debfSDerek Schuff 
LowerRETURNADDR(SDValue Op,SelectionDAG & DAG) const16741a3cbe72SThomas Lively SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op,
16751a3cbe72SThomas Lively                                                    SelectionDAG &DAG) const {
16761a3cbe72SThomas Lively   SDLoc DL(Op);
16771a3cbe72SThomas Lively 
16781a3cbe72SThomas Lively   if (!Subtarget->getTargetTriple().isOSEmscripten()) {
16791a3cbe72SThomas Lively     fail(DL, DAG,
16801a3cbe72SThomas Lively          "Non-Emscripten WebAssembly hasn't implemented "
16811a3cbe72SThomas Lively          "__builtin_return_address");
16821a3cbe72SThomas Lively     return SDValue();
16831a3cbe72SThomas Lively   }
16841a3cbe72SThomas Lively 
16851a3cbe72SThomas Lively   if (verifyReturnAddressArgumentIsConstant(Op, DAG))
16861a3cbe72SThomas Lively     return SDValue();
16871a3cbe72SThomas Lively 
1688aa0b0fbbSHeejin Ahn   unsigned Depth = Op.getConstantOperandVal(0);
168972a41e7bSShiva Chen   MakeLibCallOptions CallOptions;
16901a3cbe72SThomas Lively   return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(),
169172a41e7bSShiva Chen                      {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL)
16921a3cbe72SThomas Lively       .first;
16931a3cbe72SThomas Lively }
16941a3cbe72SThomas Lively 
LowerFRAMEADDR(SDValue Op,SelectionDAG & DAG) const169594c65660SDan Gohman SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
169694c65660SDan Gohman                                                   SelectionDAG &DAG) const {
169794c65660SDan Gohman   // Non-zero depths are not supported by WebAssembly currently. Use the
169894c65660SDan Gohman   // legalizer's default expansion, which is to return 0 (what this function is
169994c65660SDan Gohman   // documented to do).
17001d547bf5SDan Gohman   if (Op.getConstantOperandVal(0) > 0)
170194c65660SDan Gohman     return SDValue();
170294c65660SDan Gohman 
1703941a705bSMatthias Braun   DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
170494c65660SDan Gohman   EVT VT = Op.getValueType();
170505c145d6SDaniel Sanders   Register FP =
170694c65660SDan Gohman       Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
170794c65660SDan Gohman   return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
170894c65660SDan Gohman }
170994c65660SDan Gohman 
1710a083b28aSSam Clegg SDValue
LowerGlobalTLSAddress(SDValue Op,SelectionDAG & DAG) const1711a083b28aSSam Clegg WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op,
1712a083b28aSSam Clegg                                                  SelectionDAG &DAG) const {
1713a083b28aSSam Clegg   SDLoc DL(Op);
1714a083b28aSSam Clegg   const auto *GA = cast<GlobalAddressSDNode>(Op);
1715a083b28aSSam Clegg 
1716a083b28aSSam Clegg   MachineFunction &MF = DAG.getMachineFunction();
1717a083b28aSSam Clegg   if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory())
1718a083b28aSSam Clegg     report_fatal_error("cannot use thread-local storage without bulk memory",
1719a083b28aSSam Clegg                        false);
1720a083b28aSSam Clegg 
1721a083b28aSSam Clegg   const GlobalValue *GV = GA->getGlobal();
1722a083b28aSSam Clegg 
1723*3696a789SAndrew Brown   // Currently only Emscripten supports dynamic linking with threads. Therefore,
1724*3696a789SAndrew Brown   // on other targets, if we have thread-local storage, only the local-exec
1725*3696a789SAndrew Brown   // model is possible.
1726*3696a789SAndrew Brown   auto model = Subtarget->getTargetTriple().isOSEmscripten()
1727*3696a789SAndrew Brown                    ? GV->getThreadLocalMode()
1728*3696a789SAndrew Brown                    : GlobalValue::LocalExecTLSModel;
1729ef8c9135SSam Clegg 
1730ef8c9135SSam Clegg   // Unsupported TLS modes
1731ef8c9135SSam Clegg   assert(model != GlobalValue::NotThreadLocal);
1732ef8c9135SSam Clegg   assert(model != GlobalValue::InitialExecTLSModel);
1733ef8c9135SSam Clegg 
1734ef8c9135SSam Clegg   if (model == GlobalValue::LocalExecTLSModel ||
1735ef8c9135SSam Clegg       model == GlobalValue::LocalDynamicTLSModel ||
1736ef8c9135SSam Clegg       (model == GlobalValue::GeneralDynamicTLSModel &&
1737ef8c9135SSam Clegg        getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV))) {
1738ef8c9135SSam Clegg     // For DSO-local TLS variables we use offset from __tls_base
1739ef8c9135SSam Clegg 
1740ef8c9135SSam Clegg     MVT PtrVT = getPointerTy(DAG.getDataLayout());
1741a083b28aSSam Clegg     auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
1742a083b28aSSam Clegg                                        : WebAssembly::GLOBAL_GET_I32;
1743a083b28aSSam Clegg     const char *BaseName = MF.createExternalSymbolName("__tls_base");
1744a083b28aSSam Clegg 
1745a083b28aSSam Clegg     SDValue BaseAddr(
1746a083b28aSSam Clegg         DAG.getMachineNode(GlobalGet, DL, PtrVT,
1747a083b28aSSam Clegg                            DAG.getTargetExternalSymbol(BaseName, PtrVT)),
1748a083b28aSSam Clegg         0);
1749a083b28aSSam Clegg 
1750a083b28aSSam Clegg     SDValue TLSOffset = DAG.getTargetGlobalAddress(
1751a083b28aSSam Clegg         GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL);
1752c32884c4SSam Clegg     SDValue SymOffset =
1753c32884c4SSam Clegg         DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, TLSOffset);
1754a083b28aSSam Clegg 
1755c32884c4SSam Clegg     return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymOffset);
1756a083b28aSSam Clegg   }
1757a083b28aSSam Clegg 
1758ef8c9135SSam Clegg   assert(model == GlobalValue::GeneralDynamicTLSModel);
1759ef8c9135SSam Clegg 
1760ef8c9135SSam Clegg   EVT VT = Op.getValueType();
1761ef8c9135SSam Clegg   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
1762ef8c9135SSam Clegg                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
1763ef8c9135SSam Clegg                                                 GA->getOffset(),
1764ef8c9135SSam Clegg                                                 WebAssemblyII::MO_GOT_TLS));
1765ef8c9135SSam Clegg }
1766ef8c9135SSam Clegg 
LowerGlobalAddress(SDValue Op,SelectionDAG & DAG) const1767af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
1768af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
1769af111db8SJF Bastien   SDLoc DL(Op);
1770af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
1771af111db8SJF Bastien   EVT VT = Op.getValueType();
177226c6765bSDan Gohman   assert(GA->getTargetFlags() == 0 &&
177326c6765bSDan Gohman          "Unexpected target flags on generic GlobalAddressSDNode");
1774d7086af2SPaulo Matos   if (!WebAssembly::isValidAddressSpace(GA->getAddressSpace()))
1775d7086af2SPaulo Matos     fail(DL, DAG, "Invalid address space for WebAssembly target");
1776492f7529SSam Clegg 
1777ef4c66c1SSam Clegg   unsigned OperandFlags = 0;
1778492f7529SSam Clegg   if (isPositionIndependent()) {
1779492f7529SSam Clegg     const GlobalValue *GV = GA->getGlobal();
1780492f7529SSam Clegg     if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) {
1781492f7529SSam Clegg       MachineFunction &MF = DAG.getMachineFunction();
1782492f7529SSam Clegg       MVT PtrVT = getPointerTy(MF.getDataLayout());
1783492f7529SSam Clegg       const char *BaseName;
17842a7cac93SSam Clegg       if (GV->getValueType()->isFunctionTy()) {
1785492f7529SSam Clegg         BaseName = MF.createExternalSymbolName("__table_base");
17862a7cac93SSam Clegg         OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL;
1787*3696a789SAndrew Brown       } else {
1788492f7529SSam Clegg         BaseName = MF.createExternalSymbolName("__memory_base");
17892a7cac93SSam Clegg         OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL;
17902a7cac93SSam Clegg       }
1791492f7529SSam Clegg       SDValue BaseAddr =
1792492f7529SSam Clegg           DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
1793492f7529SSam Clegg                       DAG.getTargetExternalSymbol(BaseName, PtrVT));
1794492f7529SSam Clegg 
1795492f7529SSam Clegg       SDValue SymAddr = DAG.getNode(
1796c32884c4SSam Clegg           WebAssemblyISD::WrapperREL, DL, VT,
17972a7cac93SSam Clegg           DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
17982a7cac93SSam Clegg                                      OperandFlags));
1799492f7529SSam Clegg 
1800492f7529SSam Clegg       return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
1801492f7529SSam Clegg     }
1802c32884c4SSam Clegg     OperandFlags = WebAssemblyII::MO_GOT;
1803492f7529SSam Clegg   }
1804492f7529SSam Clegg 
1805492f7529SSam Clegg   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
1806492f7529SSam Clegg                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
1807ef4c66c1SSam Clegg                                                 GA->getOffset(), OperandFlags));
1808af111db8SJF Bastien }
1809af111db8SJF Bastien 
1810f208f631SHeejin Ahn SDValue
LowerExternalSymbol(SDValue Op,SelectionDAG & DAG) const1811f208f631SHeejin Ahn WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
1812f208f631SHeejin Ahn                                                SelectionDAG &DAG) const {
18132c8fe6a4SDan Gohman   SDLoc DL(Op);
18142c8fe6a4SDan Gohman   const auto *ES = cast<ExternalSymbolSDNode>(Op);
18152c8fe6a4SDan Gohman   EVT VT = Op.getValueType();
181626c6765bSDan Gohman   assert(ES->getTargetFlags() == 0 &&
181726c6765bSDan Gohman          "Unexpected target flags on generic ExternalSymbolSDNode");
1818ef4c66c1SSam Clegg   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
1819ef4c66c1SSam Clegg                      DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
18202c8fe6a4SDan Gohman }
18212c8fe6a4SDan Gohman 
LowerJumpTable(SDValue Op,SelectionDAG & DAG) const1822950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
1823950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
1824950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
182514026064SDan Gohman   // table operand into a BR_TABLE instruction, rather than ever
1826bb7ce8e4SDan Gohman   // materializing it in a register.
1827950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
1828950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
1829950a13cfSDan Gohman                                 JT->getTargetFlags());
1830950a13cfSDan Gohman }
1831950a13cfSDan Gohman 
LowerBR_JT(SDValue Op,SelectionDAG & DAG) const1832950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
1833950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
1834950a13cfSDan Gohman   SDLoc DL(Op);
1835950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
1836950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
1837950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
1838950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
1839950a13cfSDan Gohman 
1840950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
1841950a13cfSDan Gohman   Ops.push_back(Chain);
1842950a13cfSDan Gohman   Ops.push_back(Index);
1843950a13cfSDan Gohman 
1844950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
1845950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
1846950a13cfSDan Gohman 
184714026064SDan Gohman   // Add an operand for each case.
1848f208f631SHeejin Ahn   for (auto MBB : MBBs)
1849f208f631SHeejin Ahn     Ops.push_back(DAG.getBasicBlock(MBB));
185014026064SDan Gohman 
18518df30d98SThomas Lively   // Add the first MBB as a dummy default target for now. This will be replaced
18528df30d98SThomas Lively   // with the proper default target (and the preceding range check eliminated)
18538df30d98SThomas Lively   // if possible by WebAssemblyFixBrTableDefaults.
18548df30d98SThomas Lively   Ops.push_back(DAG.getBasicBlock(*MBBs.begin()));
185514026064SDan Gohman   return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
1856950a13cfSDan Gohman }
1857950a13cfSDan Gohman 
LowerVASTART(SDValue Op,SelectionDAG & DAG) const185835bfb24cSDan Gohman SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
185935bfb24cSDan Gohman                                                 SelectionDAG &DAG) const {
186035bfb24cSDan Gohman   SDLoc DL(Op);
186135bfb24cSDan Gohman   EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
186235bfb24cSDan Gohman 
186327501e20SDerek Schuff   auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
186435bfb24cSDan Gohman   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
186527501e20SDerek Schuff 
186627501e20SDerek Schuff   SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
186727501e20SDerek Schuff                                     MFI->getVarargBufferVreg(), PtrVT);
186827501e20SDerek Schuff   return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
1869c193a689SCraig Topper                       MachinePointerInfo(SV));
187035bfb24cSDan Gohman }
187135bfb24cSDan Gohman 
LowerIntrinsic(SDValue Op,SelectionDAG & DAG) const1872d6f48786SHeejin Ahn SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
18735ef4d5f9SHeejin Ahn                                                   SelectionDAG &DAG) const {
1874d6f48786SHeejin Ahn   MachineFunction &MF = DAG.getMachineFunction();
1875d6f48786SHeejin Ahn   unsigned IntNo;
1876d6f48786SHeejin Ahn   switch (Op.getOpcode()) {
1877d6f48786SHeejin Ahn   case ISD::INTRINSIC_VOID:
1878d6f48786SHeejin Ahn   case ISD::INTRINSIC_W_CHAIN:
1879aa0b0fbbSHeejin Ahn     IntNo = Op.getConstantOperandVal(1);
1880d6f48786SHeejin Ahn     break;
1881d6f48786SHeejin Ahn   case ISD::INTRINSIC_WO_CHAIN:
1882aa0b0fbbSHeejin Ahn     IntNo = Op.getConstantOperandVal(0);
1883d6f48786SHeejin Ahn     break;
1884d6f48786SHeejin Ahn   default:
1885d6f48786SHeejin Ahn     llvm_unreachable("Invalid intrinsic");
1886d6f48786SHeejin Ahn   }
18875ef4d5f9SHeejin Ahn   SDLoc DL(Op);
1888d6f48786SHeejin Ahn 
18895ef4d5f9SHeejin Ahn   switch (IntNo) {
18905ef4d5f9SHeejin Ahn   default:
189118c56a07SHeejin Ahn     return SDValue(); // Don't custom lower most intrinsics.
18925d461c96SThomas Lively 
189324faf859SHeejin Ahn   case Intrinsic::wasm_lsda: {
18949261ee32SHeejin Ahn     auto PtrVT = getPointerTy(MF.getDataLayout());
18959261ee32SHeejin Ahn     const char *SymName = MF.createExternalSymbolName(
18969261ee32SHeejin Ahn         "GCC_except_table" + std::to_string(MF.getFunctionNumber()));
18979261ee32SHeejin Ahn     if (isPositionIndependent()) {
18989261ee32SHeejin Ahn       SDValue Node = DAG.getTargetExternalSymbol(
18999261ee32SHeejin Ahn           SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL);
19009261ee32SHeejin Ahn       const char *BaseName = MF.createExternalSymbolName("__memory_base");
19019261ee32SHeejin Ahn       SDValue BaseAddr =
19029261ee32SHeejin Ahn           DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
19039261ee32SHeejin Ahn                       DAG.getTargetExternalSymbol(BaseName, PtrVT));
19049261ee32SHeejin Ahn       SDValue SymAddr =
19059261ee32SHeejin Ahn           DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node);
19069261ee32SHeejin Ahn       return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr);
19079261ee32SHeejin Ahn     }
19089261ee32SHeejin Ahn     SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT);
19099261ee32SHeejin Ahn     return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node);
191024faf859SHeejin Ahn   }
1911da419bdbSHeejin Ahn 
19128e3e56f2SThomas Lively   case Intrinsic::wasm_shuffle: {
19138e3e56f2SThomas Lively     // Drop in-chain and replace undefs, but otherwise pass through unchanged
19148e3e56f2SThomas Lively     SDValue Ops[18];
19158e3e56f2SThomas Lively     size_t OpIdx = 0;
19168e3e56f2SThomas Lively     Ops[OpIdx++] = Op.getOperand(1);
19178e3e56f2SThomas Lively     Ops[OpIdx++] = Op.getOperand(2);
19188e3e56f2SThomas Lively     while (OpIdx < 18) {
19198e3e56f2SThomas Lively       const SDValue &MaskIdx = Op.getOperand(OpIdx + 1);
19208e3e56f2SThomas Lively       if (MaskIdx.isUndef() ||
19218e3e56f2SThomas Lively           cast<ConstantSDNode>(MaskIdx.getNode())->getZExtValue() >= 32) {
19228e3e56f2SThomas Lively         Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32);
19238e3e56f2SThomas Lively       } else {
19248e3e56f2SThomas Lively         Ops[OpIdx++] = MaskIdx;
19258e3e56f2SThomas Lively       }
19268e3e56f2SThomas Lively     }
19278e3e56f2SThomas Lively     return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
19288e3e56f2SThomas Lively   }
1929da419bdbSHeejin Ahn   }
1930da419bdbSHeejin Ahn }
1931da419bdbSHeejin Ahn 
1932da419bdbSHeejin Ahn SDValue
LowerSIGN_EXTEND_INREG(SDValue Op,SelectionDAG & DAG) const193364a39a1cSThomas Lively WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
193464a39a1cSThomas Lively                                                   SelectionDAG &DAG) const {
19353d9ca00eSThomas Lively   SDLoc DL(Op);
193664a39a1cSThomas Lively   // If sign extension operations are disabled, allow sext_inreg only if operand
19370906dca4SThomas Lively   // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign
19380906dca4SThomas Lively   // extension operations, but allowing sext_inreg in this context lets us have
19390906dca4SThomas Lively   // simple patterns to select extract_lane_s instructions. Expanding sext_inreg
19400906dca4SThomas Lively   // everywhere would be simpler in this file, but would necessitate large and
19410906dca4SThomas Lively   // brittle patterns to undo the expansion and select extract_lane_s
19420906dca4SThomas Lively   // instructions.
194364a39a1cSThomas Lively   assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
19440906dca4SThomas Lively   if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT)
19450906dca4SThomas Lively     return SDValue();
19460906dca4SThomas Lively 
19473d9ca00eSThomas Lively   const SDValue &Extract = Op.getOperand(0);
19483d9ca00eSThomas Lively   MVT VecT = Extract.getOperand(0).getSimpleValueType();
19490906dca4SThomas Lively   if (VecT.getVectorElementType().getSizeInBits() > 32)
19500906dca4SThomas Lively     return SDValue();
195125af2126SThomas Lively   MVT ExtractedLaneT =
195225af2126SThomas Lively       cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT();
19533d9ca00eSThomas Lively   MVT ExtractedVecT =
19543d9ca00eSThomas Lively       MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits());
19553d9ca00eSThomas Lively   if (ExtractedVecT == VecT)
195664a39a1cSThomas Lively     return Op;
19570906dca4SThomas Lively 
19583d9ca00eSThomas Lively   // Bitcast vector to appropriate type to ensure ISel pattern coverage
195925af2126SThomas Lively   const SDNode *Index = Extract.getOperand(1).getNode();
196025af2126SThomas Lively   if (!isa<ConstantSDNode>(Index))
196125af2126SThomas Lively     return SDValue();
196225af2126SThomas Lively   unsigned IndexVal = cast<ConstantSDNode>(Index)->getZExtValue();
19633d9ca00eSThomas Lively   unsigned Scale =
19643d9ca00eSThomas Lively       ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements();
19653d9ca00eSThomas Lively   assert(Scale > 1);
19663d9ca00eSThomas Lively   SDValue NewIndex =
196725af2126SThomas Lively       DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0));
19683d9ca00eSThomas Lively   SDValue NewExtract = DAG.getNode(
19693d9ca00eSThomas Lively       ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(),
19703d9ca00eSThomas Lively       DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex);
19710906dca4SThomas Lively   return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract,
19720906dca4SThomas Lively                      Op.getOperand(1));
197364a39a1cSThomas Lively }
197464a39a1cSThomas Lively 
LowerConvertLow(SDValue Op,SelectionDAG & DAG)1975b311a040SThomas Lively static SDValue LowerConvertLow(SDValue Op, SelectionDAG &DAG) {
1976fd0557dbSThomas Lively   SDLoc DL(Op);
1977b311a040SThomas Lively   if (Op.getValueType() != MVT::v2f64)
1978b311a040SThomas Lively     return SDValue();
1979b311a040SThomas Lively 
1980b311a040SThomas Lively   auto GetConvertedLane = [](SDValue Op, unsigned &Opcode, SDValue &SrcVec,
1981b311a040SThomas Lively                              unsigned &Index) -> bool {
1982b311a040SThomas Lively     switch (Op.getOpcode()) {
1983b311a040SThomas Lively     case ISD::SINT_TO_FP:
1984b311a040SThomas Lively       Opcode = WebAssemblyISD::CONVERT_LOW_S;
1985b311a040SThomas Lively       break;
1986b311a040SThomas Lively     case ISD::UINT_TO_FP:
1987b311a040SThomas Lively       Opcode = WebAssemblyISD::CONVERT_LOW_U;
1988b311a040SThomas Lively       break;
1989b311a040SThomas Lively     case ISD::FP_EXTEND:
1990b311a040SThomas Lively       Opcode = WebAssemblyISD::PROMOTE_LOW;
1991b311a040SThomas Lively       break;
1992b311a040SThomas Lively     default:
1993b311a040SThomas Lively       return false;
1994b311a040SThomas Lively     }
1995b311a040SThomas Lively 
1996b311a040SThomas Lively     auto ExtractVector = Op.getOperand(0);
1997b311a040SThomas Lively     if (ExtractVector.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
1998b311a040SThomas Lively       return false;
1999b311a040SThomas Lively 
2000b311a040SThomas Lively     if (!isa<ConstantSDNode>(ExtractVector.getOperand(1).getNode()))
2001b311a040SThomas Lively       return false;
2002b311a040SThomas Lively 
2003b311a040SThomas Lively     SrcVec = ExtractVector.getOperand(0);
2004b311a040SThomas Lively     Index = ExtractVector.getConstantOperandVal(1);
2005b311a040SThomas Lively     return true;
2006b311a040SThomas Lively   };
2007b311a040SThomas Lively 
2008b311a040SThomas Lively   unsigned LHSOpcode, RHSOpcode, LHSIndex, RHSIndex;
2009b311a040SThomas Lively   SDValue LHSSrcVec, RHSSrcVec;
2010b311a040SThomas Lively   if (!GetConvertedLane(Op.getOperand(0), LHSOpcode, LHSSrcVec, LHSIndex) ||
2011b311a040SThomas Lively       !GetConvertedLane(Op.getOperand(1), RHSOpcode, RHSSrcVec, RHSIndex))
2012b311a040SThomas Lively     return SDValue();
2013b311a040SThomas Lively 
2014fd0557dbSThomas Lively   if (LHSOpcode != RHSOpcode)
2015b311a040SThomas Lively     return SDValue();
2016b311a040SThomas Lively 
2017b311a040SThomas Lively   MVT ExpectedSrcVT;
2018b311a040SThomas Lively   switch (LHSOpcode) {
2019b311a040SThomas Lively   case WebAssemblyISD::CONVERT_LOW_S:
2020b311a040SThomas Lively   case WebAssemblyISD::CONVERT_LOW_U:
2021b311a040SThomas Lively     ExpectedSrcVT = MVT::v4i32;
2022b311a040SThomas Lively     break;
2023b311a040SThomas Lively   case WebAssemblyISD::PROMOTE_LOW:
2024b311a040SThomas Lively     ExpectedSrcVT = MVT::v4f32;
2025b311a040SThomas Lively     break;
2026b311a040SThomas Lively   }
2027b311a040SThomas Lively   if (LHSSrcVec.getValueType() != ExpectedSrcVT)
2028b311a040SThomas Lively     return SDValue();
2029b311a040SThomas Lively 
2030fd0557dbSThomas Lively   auto Src = LHSSrcVec;
2031fd0557dbSThomas Lively   if (LHSIndex != 0 || RHSIndex != 1 || LHSSrcVec != RHSSrcVec) {
2032fd0557dbSThomas Lively     // Shuffle the source vector so that the converted lanes are the low lanes.
2033be6c49e7SThomas Lively     Src = DAG.getVectorShuffle(
2034be6c49e7SThomas Lively         ExpectedSrcVT, DL, LHSSrcVec, RHSSrcVec,
2035be6c49e7SThomas Lively         {static_cast<int>(LHSIndex), static_cast<int>(RHSIndex) + 4, -1, -1});
2036fd0557dbSThomas Lively   }
2037fd0557dbSThomas Lively   return DAG.getNode(LHSOpcode, DL, MVT::v2f64, Src);
2038b311a040SThomas Lively }
2039b311a040SThomas Lively 
LowerBUILD_VECTOR(SDValue Op,SelectionDAG & DAG) const2040079816efSThomas Lively SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
2041079816efSThomas Lively                                                      SelectionDAG &DAG) const {
2042b311a040SThomas Lively   if (auto ConvertLow = LowerConvertLow(Op, DAG))
2043b311a040SThomas Lively     return ConvertLow;
2044b311a040SThomas Lively 
2045079816efSThomas Lively   SDLoc DL(Op);
2046079816efSThomas Lively   const EVT VecT = Op.getValueType();
2047079816efSThomas Lively   const EVT LaneT = Op.getOperand(0).getValueType();
2048079816efSThomas Lively   const size_t Lanes = Op.getNumOperands();
2049c702d4bfSThomas Lively   bool CanSwizzle = VecT == MVT::v16i8;
2050d5b7a4e2SThomas Lively 
2051d5b7a4e2SThomas Lively   // BUILD_VECTORs are lowered to the instruction that initializes the highest
2052d5b7a4e2SThomas Lively   // possible number of lanes at once followed by a sequence of replace_lane
2053d5b7a4e2SThomas Lively   // instructions to individually initialize any remaining lanes.
2054d5b7a4e2SThomas Lively 
2055d5b7a4e2SThomas Lively   // TODO: Tune this. For example, lanewise swizzling is very expensive, so
2056d5b7a4e2SThomas Lively   // swizzled lanes should be given greater weight.
2057d5b7a4e2SThomas Lively 
2058f30c429dSThomas Lively   // TODO: Investigate looping rather than always extracting/replacing specific
2059f30c429dSThomas Lively   // lanes to fill gaps.
2060d5b7a4e2SThomas Lively 
2061079816efSThomas Lively   auto IsConstant = [](const SDValue &V) {
2062079816efSThomas Lively     return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
2063079816efSThomas Lively   };
2064079816efSThomas Lively 
2065d5b7a4e2SThomas Lively   // Returns the source vector and index vector pair if they exist. Checks for:
2066d5b7a4e2SThomas Lively   //   (extract_vector_elt
2067d5b7a4e2SThomas Lively   //     $src,
2068d5b7a4e2SThomas Lively   //     (sign_extend_inreg (extract_vector_elt $indices, $i))
2069d5b7a4e2SThomas Lively   //   )
2070d5b7a4e2SThomas Lively   auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) {
2071d5b7a4e2SThomas Lively     auto Bail = std::make_pair(SDValue(), SDValue());
2072d5b7a4e2SThomas Lively     if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2073d5b7a4e2SThomas Lively       return Bail;
2074d5b7a4e2SThomas Lively     const SDValue &SwizzleSrc = Lane->getOperand(0);
2075d5b7a4e2SThomas Lively     const SDValue &IndexExt = Lane->getOperand(1);
2076d5b7a4e2SThomas Lively     if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG)
2077d5b7a4e2SThomas Lively       return Bail;
2078d5b7a4e2SThomas Lively     const SDValue &Index = IndexExt->getOperand(0);
2079d5b7a4e2SThomas Lively     if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2080d5b7a4e2SThomas Lively       return Bail;
2081d5b7a4e2SThomas Lively     const SDValue &SwizzleIndices = Index->getOperand(0);
2082d5b7a4e2SThomas Lively     if (SwizzleSrc.getValueType() != MVT::v16i8 ||
2083d5b7a4e2SThomas Lively         SwizzleIndices.getValueType() != MVT::v16i8 ||
2084d5b7a4e2SThomas Lively         Index->getOperand(1)->getOpcode() != ISD::Constant ||
2085d5b7a4e2SThomas Lively         Index->getConstantOperandVal(1) != I)
2086d5b7a4e2SThomas Lively       return Bail;
2087d5b7a4e2SThomas Lively     return std::make_pair(SwizzleSrc, SwizzleIndices);
2088d5b7a4e2SThomas Lively   };
2089d5b7a4e2SThomas Lively 
2090f30c429dSThomas Lively   // If the lane is extracted from another vector at a constant index, return
2091f30c429dSThomas Lively   // that vector. The source vector must not have more lanes than the dest
2092f30c429dSThomas Lively   // because the shufflevector indices are in terms of the destination lanes and
2093f30c429dSThomas Lively   // would not be able to address the smaller individual source lanes.
2094f30c429dSThomas Lively   auto GetShuffleSrc = [&](const SDValue &Lane) {
2095f30c429dSThomas Lively     if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2096f30c429dSThomas Lively       return SDValue();
2097f30c429dSThomas Lively     if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode()))
2098f30c429dSThomas Lively       return SDValue();
2099f30c429dSThomas Lively     if (Lane->getOperand(0).getValueType().getVectorNumElements() >
2100f30c429dSThomas Lively         VecT.getVectorNumElements())
2101f30c429dSThomas Lively       return SDValue();
2102f30c429dSThomas Lively     return Lane->getOperand(0);
2103f30c429dSThomas Lively   };
2104f30c429dSThomas Lively 
2105d5b7a4e2SThomas Lively   using ValueEntry = std::pair<SDValue, size_t>;
2106d5b7a4e2SThomas Lively   SmallVector<ValueEntry, 16> SplatValueCounts;
2107d5b7a4e2SThomas Lively 
2108d5b7a4e2SThomas Lively   using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>;
2109d5b7a4e2SThomas Lively   SmallVector<SwizzleEntry, 16> SwizzleCounts;
2110d5b7a4e2SThomas Lively 
2111f30c429dSThomas Lively   using ShuffleEntry = std::pair<SDValue, size_t>;
2112f30c429dSThomas Lively   SmallVector<ShuffleEntry, 16> ShuffleCounts;
2113f30c429dSThomas Lively 
2114d5b7a4e2SThomas Lively   auto AddCount = [](auto &Counts, const auto &Val) {
2115b934160aSKazu Hirata     auto CountIt =
2116b934160aSKazu Hirata         llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; });
2117d5b7a4e2SThomas Lively     if (CountIt == Counts.end()) {
2118d5b7a4e2SThomas Lively       Counts.emplace_back(Val, 1);
2119079816efSThomas Lively     } else {
2120079816efSThomas Lively       CountIt->second++;
2121079816efSThomas Lively     }
2122d5b7a4e2SThomas Lively   };
2123079816efSThomas Lively 
2124d5b7a4e2SThomas Lively   auto GetMostCommon = [](auto &Counts) {
2125d5b7a4e2SThomas Lively     auto CommonIt =
2126e0039b8dSKazu Hirata         std::max_element(Counts.begin(), Counts.end(), llvm::less_second());
2127d5b7a4e2SThomas Lively     assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
2128d5b7a4e2SThomas Lively     return *CommonIt;
2129d5b7a4e2SThomas Lively   };
2130d5b7a4e2SThomas Lively 
2131d5b7a4e2SThomas Lively   size_t NumConstantLanes = 0;
2132d5b7a4e2SThomas Lively 
2133d5b7a4e2SThomas Lively   // Count eligible lanes for each type of vector creation op
2134d5b7a4e2SThomas Lively   for (size_t I = 0; I < Lanes; ++I) {
2135d5b7a4e2SThomas Lively     const SDValue &Lane = Op->getOperand(I);
2136d5b7a4e2SThomas Lively     if (Lane.isUndef())
2137d5b7a4e2SThomas Lively       continue;
2138d5b7a4e2SThomas Lively 
2139d5b7a4e2SThomas Lively     AddCount(SplatValueCounts, Lane);
2140d5b7a4e2SThomas Lively 
2141f30c429dSThomas Lively     if (IsConstant(Lane))
2142d5b7a4e2SThomas Lively       NumConstantLanes++;
2143f30c429dSThomas Lively     if (auto ShuffleSrc = GetShuffleSrc(Lane))
2144f30c429dSThomas Lively       AddCount(ShuffleCounts, ShuffleSrc);
2145f30c429dSThomas Lively     if (CanSwizzle) {
2146d5b7a4e2SThomas Lively       auto SwizzleSrcs = GetSwizzleSrcs(I, Lane);
2147d5b7a4e2SThomas Lively       if (SwizzleSrcs.first)
2148d5b7a4e2SThomas Lively         AddCount(SwizzleCounts, SwizzleSrcs);
2149d5b7a4e2SThomas Lively     }
2150d5b7a4e2SThomas Lively   }
2151d5b7a4e2SThomas Lively 
2152d5b7a4e2SThomas Lively   SDValue SplatValue;
2153d5b7a4e2SThomas Lively   size_t NumSplatLanes;
2154d5b7a4e2SThomas Lively   std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts);
2155d5b7a4e2SThomas Lively 
2156d5b7a4e2SThomas Lively   SDValue SwizzleSrc;
2157d5b7a4e2SThomas Lively   SDValue SwizzleIndices;
2158d5b7a4e2SThomas Lively   size_t NumSwizzleLanes = 0;
2159d5b7a4e2SThomas Lively   if (SwizzleCounts.size())
2160d5b7a4e2SThomas Lively     std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices),
2161d5b7a4e2SThomas Lively                           NumSwizzleLanes) = GetMostCommon(SwizzleCounts);
2162d5b7a4e2SThomas Lively 
2163f30c429dSThomas Lively   // Shuffles can draw from up to two vectors, so find the two most common
2164f30c429dSThomas Lively   // sources.
2165f30c429dSThomas Lively   SDValue ShuffleSrc1, ShuffleSrc2;
2166f30c429dSThomas Lively   size_t NumShuffleLanes = 0;
2167f30c429dSThomas Lively   if (ShuffleCounts.size()) {
2168f30c429dSThomas Lively     std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts);
21698568ca78SKazu Hirata     llvm::erase_if(ShuffleCounts,
21708568ca78SKazu Hirata                    [&](const auto &Pair) { return Pair.first == ShuffleSrc1; });
2171f30c429dSThomas Lively   }
2172f30c429dSThomas Lively   if (ShuffleCounts.size()) {
2173f30c429dSThomas Lively     size_t AdditionalShuffleLanes;
2174f30c429dSThomas Lively     std::tie(ShuffleSrc2, AdditionalShuffleLanes) =
2175f30c429dSThomas Lively         GetMostCommon(ShuffleCounts);
2176f30c429dSThomas Lively     NumShuffleLanes += AdditionalShuffleLanes;
2177f30c429dSThomas Lively   }
2178f30c429dSThomas Lively 
2179d5b7a4e2SThomas Lively   // Predicate returning true if the lane is properly initialized by the
2180d5b7a4e2SThomas Lively   // original instruction
2181d5b7a4e2SThomas Lively   std::function<bool(size_t, const SDValue &)> IsLaneConstructed;
2182d5b7a4e2SThomas Lively   SDValue Result;
2183f30c429dSThomas Lively   // Prefer swizzles over shuffles over vector consts over splats
2184f30c429dSThomas Lively   if (NumSwizzleLanes >= NumShuffleLanes &&
2185f30c429dSThomas Lively       NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) {
2186d5b7a4e2SThomas Lively     Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc,
2187d5b7a4e2SThomas Lively                          SwizzleIndices);
2188d5b7a4e2SThomas Lively     auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices);
2189d5b7a4e2SThomas Lively     IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) {
2190d5b7a4e2SThomas Lively       return Swizzled == GetSwizzleSrcs(I, Lane);
2191d5b7a4e2SThomas Lively     };
2192f30c429dSThomas Lively   } else if (NumShuffleLanes >= NumConstantLanes &&
2193f30c429dSThomas Lively              NumShuffleLanes >= NumSplatLanes) {
2194f30c429dSThomas Lively     size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8;
2195f30c429dSThomas Lively     size_t DestLaneCount = VecT.getVectorNumElements();
2196f30c429dSThomas Lively     size_t Scale1 = 1;
2197f30c429dSThomas Lively     size_t Scale2 = 1;
2198f30c429dSThomas Lively     SDValue Src1 = ShuffleSrc1;
2199f30c429dSThomas Lively     SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT);
2200f30c429dSThomas Lively     if (Src1.getValueType() != VecT) {
2201f30c429dSThomas Lively       size_t LaneSize =
2202f30c429dSThomas Lively           Src1.getValueType().getVectorElementType().getFixedSizeInBits() / 8;
2203f30c429dSThomas Lively       assert(LaneSize > DestLaneSize);
2204f30c429dSThomas Lively       Scale1 = LaneSize / DestLaneSize;
2205f30c429dSThomas Lively       Src1 = DAG.getBitcast(VecT, Src1);
2206f30c429dSThomas Lively     }
2207f30c429dSThomas Lively     if (Src2.getValueType() != VecT) {
2208f30c429dSThomas Lively       size_t LaneSize =
2209f30c429dSThomas Lively           Src2.getValueType().getVectorElementType().getFixedSizeInBits() / 8;
2210f30c429dSThomas Lively       assert(LaneSize > DestLaneSize);
2211f30c429dSThomas Lively       Scale2 = LaneSize / DestLaneSize;
2212f30c429dSThomas Lively       Src2 = DAG.getBitcast(VecT, Src2);
2213f30c429dSThomas Lively     }
2214f30c429dSThomas Lively 
2215f30c429dSThomas Lively     int Mask[16];
2216f30c429dSThomas Lively     assert(DestLaneCount <= 16);
2217f30c429dSThomas Lively     for (size_t I = 0; I < DestLaneCount; ++I) {
2218f30c429dSThomas Lively       const SDValue &Lane = Op->getOperand(I);
2219f30c429dSThomas Lively       SDValue Src = GetShuffleSrc(Lane);
2220f30c429dSThomas Lively       if (Src == ShuffleSrc1) {
2221f30c429dSThomas Lively         Mask[I] = Lane->getConstantOperandVal(1) * Scale1;
2222f30c429dSThomas Lively       } else if (Src && Src == ShuffleSrc2) {
2223f30c429dSThomas Lively         Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2;
2224f30c429dSThomas Lively       } else {
2225f30c429dSThomas Lively         Mask[I] = -1;
2226f30c429dSThomas Lively       }
2227f30c429dSThomas Lively     }
2228f30c429dSThomas Lively     ArrayRef<int> MaskRef(Mask, DestLaneCount);
2229f30c429dSThomas Lively     Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef);
2230f30c429dSThomas Lively     IsLaneConstructed = [&](size_t, const SDValue &Lane) {
2231f30c429dSThomas Lively       auto Src = GetShuffleSrc(Lane);
2232f30c429dSThomas Lively       return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2);
2233f30c429dSThomas Lively     };
22348638c897SThomas Lively   } else if (NumConstantLanes >= NumSplatLanes) {
2235079816efSThomas Lively     SmallVector<SDValue, 16> ConstLanes;
2236079816efSThomas Lively     for (const SDValue &Lane : Op->op_values()) {
2237079816efSThomas Lively       if (IsConstant(Lane)) {
2238ca541aa3SThomas Lively         // Values may need to be fixed so that they will sign extend to be
2239ca541aa3SThomas Lively         // within the expected range during ISel. Check whether the value is in
2240ca541aa3SThomas Lively         // bounds based on the lane bit width and if it is out of bounds, lop
2241ca541aa3SThomas Lively         // off the extra bits and subtract 2^n to reflect giving the high bit
2242ca541aa3SThomas Lively         // value -2^(n-1) rather than +2^(n-1). Skip the i64 case because it
2243ca541aa3SThomas Lively         // cannot possibly be out of range.
2244ca541aa3SThomas Lively         auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode());
2245ca541aa3SThomas Lively         int64_t Val = Const ? Const->getSExtValue() : 0;
2246ca541aa3SThomas Lively         uint64_t LaneBits = 128 / Lanes;
2247977eeb0cSThomas Lively         assert((LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) &&
2248ca541aa3SThomas Lively                "Unexpected out of bounds negative value");
2249977eeb0cSThomas Lively         if (Const && LaneBits != 64 && Val > (1ll << (LaneBits - 1)) - 1) {
2250977eeb0cSThomas Lively           auto NewVal = ((uint64_t)Val % (1ll << LaneBits)) - (1ll << LaneBits);
2251ca541aa3SThomas Lively           ConstLanes.push_back(DAG.getConstant(NewVal, SDLoc(Lane), LaneT));
2252ca541aa3SThomas Lively         } else {
2253079816efSThomas Lively           ConstLanes.push_back(Lane);
2254ca541aa3SThomas Lively         }
2255079816efSThomas Lively       } else if (LaneT.isFloatingPoint()) {
2256079816efSThomas Lively         ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
2257079816efSThomas Lively       } else {
2258079816efSThomas Lively         ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
2259079816efSThomas Lively       }
2260079816efSThomas Lively     }
2261d5b7a4e2SThomas Lively     Result = DAG.getBuildVector(VecT, DL, ConstLanes);
226272c628e8SThomas Lively     IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) {
2263d5b7a4e2SThomas Lively       return IsConstant(Lane);
2264d5b7a4e2SThomas Lively     };
226572c628e8SThomas Lively   } else {
2266d5b7a4e2SThomas Lively     // Use a splat, but possibly a load_splat
226799d3dd28SThomas Lively     LoadSDNode *SplattedLoad;
2268c702d4bfSThomas Lively     if ((SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) &&
226999d3dd28SThomas Lively         SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) {
22703479fd25SThomas Lively       Result = DAG.getMemIntrinsicNode(
22713479fd25SThomas Lively           WebAssemblyISD::LOAD_SPLAT, DL, DAG.getVTList(VecT),
22723479fd25SThomas Lively           {SplattedLoad->getChain(), SplattedLoad->getBasePtr(),
22733479fd25SThomas Lively            SplattedLoad->getOffset()},
22743479fd25SThomas Lively           SplattedLoad->getMemoryVT(), SplattedLoad->getMemOperand());
227599d3dd28SThomas Lively     } else {
227699d3dd28SThomas Lively       Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
227799d3dd28SThomas Lively     }
227872c628e8SThomas Lively     IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) {
2279d5b7a4e2SThomas Lively       return Lane == SplatValue;
2280d5b7a4e2SThomas Lively     };
2281d5b7a4e2SThomas Lively   }
2282d5b7a4e2SThomas Lively 
228372c628e8SThomas Lively   assert(Result);
228472c628e8SThomas Lively   assert(IsLaneConstructed);
228572c628e8SThomas Lively 
2286d5b7a4e2SThomas Lively   // Add replace_lane instructions for any unhandled values
2287079816efSThomas Lively   for (size_t I = 0; I < Lanes; ++I) {
2288079816efSThomas Lively     const SDValue &Lane = Op->getOperand(I);
2289d5b7a4e2SThomas Lively     if (!Lane.isUndef() && !IsLaneConstructed(I, Lane))
2290079816efSThomas Lively       Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
2291079816efSThomas Lively                            DAG.getConstant(I, DL, MVT::i32));
2292079816efSThomas Lively   }
2293d5b7a4e2SThomas Lively 
2294079816efSThomas Lively   return Result;
2295079816efSThomas Lively }
2296079816efSThomas Lively 
229764a39a1cSThomas Lively SDValue
LowerVECTOR_SHUFFLE(SDValue Op,SelectionDAG & DAG) const2298a0d25815SThomas Lively WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
2299a0d25815SThomas Lively                                                SelectionDAG &DAG) const {
2300a0d25815SThomas Lively   SDLoc DL(Op);
2301a0d25815SThomas Lively   ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
2302a0d25815SThomas Lively   MVT VecType = Op.getOperand(0).getSimpleValueType();
2303a0d25815SThomas Lively   assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
2304a0d25815SThomas Lively   size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
2305a0d25815SThomas Lively 
2306a0d25815SThomas Lively   // Space for two vector args and sixteen mask indices
2307a0d25815SThomas Lively   SDValue Ops[18];
2308a0d25815SThomas Lively   size_t OpIdx = 0;
2309a0d25815SThomas Lively   Ops[OpIdx++] = Op.getOperand(0);
2310a0d25815SThomas Lively   Ops[OpIdx++] = Op.getOperand(1);
2311a0d25815SThomas Lively 
2312a0d25815SThomas Lively   // Expand mask indices to byte indices and materialize them as operands
231318c56a07SHeejin Ahn   for (int M : Mask) {
2314a0d25815SThomas Lively     for (size_t J = 0; J < LaneBytes; ++J) {
231511a332d0SThomas Lively       // Lower undefs (represented by -1 in mask) to zero
231618c56a07SHeejin Ahn       uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J;
231711a332d0SThomas Lively       Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
2318a0d25815SThomas Lively     }
2319a0d25815SThomas Lively   }
2320a0d25815SThomas Lively 
2321ed951347SThomas Lively   return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2322a0d25815SThomas Lively }
2323a0d25815SThomas Lively 
LowerSETCC(SDValue Op,SelectionDAG & DAG) const2324ecb7daf6SThomas Lively SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op,
2325ecb7daf6SThomas Lively                                               SelectionDAG &DAG) const {
2326ecb7daf6SThomas Lively   SDLoc DL(Op);
232745783d0eSThomas Lively   // The legalizer does not know how to expand the unsupported comparison modes
232845783d0eSThomas Lively   // of i64x2 vectors, so we manually unroll them here.
2329ecb7daf6SThomas Lively   assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64);
2330ecb7daf6SThomas Lively   SmallVector<SDValue, 2> LHS, RHS;
2331ecb7daf6SThomas Lively   DAG.ExtractVectorElements(Op->getOperand(0), LHS);
2332ecb7daf6SThomas Lively   DAG.ExtractVectorElements(Op->getOperand(1), RHS);
2333ecb7daf6SThomas Lively   const SDValue &CC = Op->getOperand(2);
2334ecb7daf6SThomas Lively   auto MakeLane = [&](unsigned I) {
2335ecb7daf6SThomas Lively     return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I],
2336ecb7daf6SThomas Lively                        DAG.getConstant(uint64_t(-1), DL, MVT::i64),
2337ecb7daf6SThomas Lively                        DAG.getConstant(uint64_t(0), DL, MVT::i64), CC);
2338ecb7daf6SThomas Lively   };
2339ecb7daf6SThomas Lively   return DAG.getBuildVector(Op->getValueType(0), DL,
2340ecb7daf6SThomas Lively                             {MakeLane(0), MakeLane(1)});
2341ecb7daf6SThomas Lively }
2342ecb7daf6SThomas Lively 
2343fb84fd7cSThomas Lively SDValue
LowerAccessVectorElement(SDValue Op,SelectionDAG & DAG) const2344fb84fd7cSThomas Lively WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
2345fb84fd7cSThomas Lively                                                     SelectionDAG &DAG) const {
2346fb84fd7cSThomas Lively   // Allow constant lane indices, expand variable lane indices
2347fb84fd7cSThomas Lively   SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
2348fb84fd7cSThomas Lively   if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef())
2349fb84fd7cSThomas Lively     return Op;
2350fb84fd7cSThomas Lively   else
2351fb84fd7cSThomas Lively     // Perform default expansion
2352fb84fd7cSThomas Lively     return SDValue();
2353fb84fd7cSThomas Lively }
2354fb84fd7cSThomas Lively 
unrollVectorShift(SDValue Op,SelectionDAG & DAG)235518c56a07SHeejin Ahn static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) {
23566bf2b400SThomas Lively   EVT LaneT = Op.getSimpleValueType().getVectorElementType();
23576bf2b400SThomas Lively   // 32-bit and 64-bit unrolled shifts will have proper semantics
23586bf2b400SThomas Lively   if (LaneT.bitsGE(MVT::i32))
23596bf2b400SThomas Lively     return DAG.UnrollVectorOp(Op.getNode());
23606bf2b400SThomas Lively   // Otherwise mask the shift value to get proper semantics from 32-bit shift
23616bf2b400SThomas Lively   SDLoc DL(Op);
23624e589e6cSThomas Lively   size_t NumLanes = Op.getSimpleValueType().getVectorNumElements();
23634e589e6cSThomas Lively   SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32);
23644e589e6cSThomas Lively   unsigned ShiftOpcode = Op.getOpcode();
23654e589e6cSThomas Lively   SmallVector<SDValue, 16> ShiftedElements;
23664e589e6cSThomas Lively   DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32);
23674e589e6cSThomas Lively   SmallVector<SDValue, 16> ShiftElements;
23684e589e6cSThomas Lively   DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32);
23694e589e6cSThomas Lively   SmallVector<SDValue, 16> UnrolledOps;
23704e589e6cSThomas Lively   for (size_t i = 0; i < NumLanes; ++i) {
23714e589e6cSThomas Lively     SDValue MaskedShiftValue =
23724e589e6cSThomas Lively         DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask);
23734e589e6cSThomas Lively     SDValue ShiftedValue = ShiftedElements[i];
23744e589e6cSThomas Lively     if (ShiftOpcode == ISD::SRA)
23754e589e6cSThomas Lively       ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32,
23764e589e6cSThomas Lively                                  ShiftedValue, DAG.getValueType(LaneT));
23774e589e6cSThomas Lively     UnrolledOps.push_back(
23784e589e6cSThomas Lively         DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue));
23794e589e6cSThomas Lively   }
23804e589e6cSThomas Lively   return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps);
23816bf2b400SThomas Lively }
23826bf2b400SThomas Lively 
LowerShift(SDValue Op,SelectionDAG & DAG) const238355735d52SThomas Lively SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
238455735d52SThomas Lively                                               SelectionDAG &DAG) const {
238555735d52SThomas Lively   SDLoc DL(Op);
2386b2382c8bSThomas Lively 
2387b2382c8bSThomas Lively   // Only manually lower vector shifts
2388b2382c8bSThomas Lively   assert(Op.getSimpleValueType().isVector());
2389b2382c8bSThomas Lively 
2390043eaa9aSThomas Lively   auto ShiftVal = DAG.getSplatValue(Op.getOperand(1));
2391043eaa9aSThomas Lively   if (!ShiftVal)
239218c56a07SHeejin Ahn     return unrollVectorShift(Op, DAG);
2393b2382c8bSThomas Lively 
2394043eaa9aSThomas Lively   // Use anyext because none of the high bits can affect the shift
2395043eaa9aSThomas Lively   ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32);
2396b2382c8bSThomas Lively 
239755735d52SThomas Lively   unsigned Opcode;
239855735d52SThomas Lively   switch (Op.getOpcode()) {
239955735d52SThomas Lively   case ISD::SHL:
240055735d52SThomas Lively     Opcode = WebAssemblyISD::VEC_SHL;
240155735d52SThomas Lively     break;
240255735d52SThomas Lively   case ISD::SRA:
240355735d52SThomas Lively     Opcode = WebAssemblyISD::VEC_SHR_S;
240455735d52SThomas Lively     break;
240555735d52SThomas Lively   case ISD::SRL:
240655735d52SThomas Lively     Opcode = WebAssemblyISD::VEC_SHR_U;
240755735d52SThomas Lively     break;
240855735d52SThomas Lively   default:
240955735d52SThomas Lively     llvm_unreachable("unexpected opcode");
241055735d52SThomas Lively   }
24110d7286a6SThomas Lively 
2412043eaa9aSThomas Lively   return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal);
241355735d52SThomas Lively }
241455735d52SThomas Lively 
LowerFP_TO_INT_SAT(SDValue Op,SelectionDAG & DAG) const24155c729750SThomas Lively SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op,
24165c729750SThomas Lively                                                       SelectionDAG &DAG) const {
24175c729750SThomas Lively   SDLoc DL(Op);
24185c729750SThomas Lively   EVT ResT = Op.getValueType();
24193067520bSCraig Topper   EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
24205c729750SThomas Lively 
24213067520bSCraig Topper   if ((ResT == MVT::i32 || ResT == MVT::i64) &&
24223067520bSCraig Topper       (SatVT == MVT::i32 || SatVT == MVT::i64))
24235c729750SThomas Lively     return Op;
24245c729750SThomas Lively 
24253067520bSCraig Topper   if (ResT == MVT::v4i32 && SatVT == MVT::i32)
24265c729750SThomas Lively     return Op;
24275c729750SThomas Lively 
24285c729750SThomas Lively   return SDValue();
24295c729750SThomas Lively }
24305c729750SThomas Lively 
243110e730a2SDan Gohman //===----------------------------------------------------------------------===//
243240af4810SThomas Lively //   Custom DAG combine hooks
243310e730a2SDan Gohman //===----------------------------------------------------------------------===//
243440af4810SThomas Lively static SDValue
performVECTOR_SHUFFLECombine(SDNode * N,TargetLowering::DAGCombinerInfo & DCI)243540af4810SThomas Lively performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
243640af4810SThomas Lively   auto &DAG = DCI.DAG;
243740af4810SThomas Lively   auto Shuffle = cast<ShuffleVectorSDNode>(N);
243840af4810SThomas Lively 
243940af4810SThomas Lively   // Hoist vector bitcasts that don't change the number of lanes out of unary
244040af4810SThomas Lively   // shuffles, where they are less likely to get in the way of other combines.
244140af4810SThomas Lively   // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) ->
24428a43d41aSThomas Lively   //  (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask))))
244340af4810SThomas Lively   SDValue Bitcast = N->getOperand(0);
244440af4810SThomas Lively   if (Bitcast.getOpcode() != ISD::BITCAST)
244540af4810SThomas Lively     return SDValue();
244640af4810SThomas Lively   if (!N->getOperand(1).isUndef())
244740af4810SThomas Lively     return SDValue();
244840af4810SThomas Lively   SDValue CastOp = Bitcast.getOperand(0);
244940af4810SThomas Lively   MVT SrcType = CastOp.getSimpleValueType();
245040af4810SThomas Lively   MVT DstType = Bitcast.getSimpleValueType();
24518a43d41aSThomas Lively   if (!SrcType.is128BitVector() ||
24528a43d41aSThomas Lively       SrcType.getVectorNumElements() != DstType.getVectorNumElements())
245340af4810SThomas Lively     return SDValue();
245440af4810SThomas Lively   SDValue NewShuffle = DAG.getVectorShuffle(
245540af4810SThomas Lively       SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask());
245640af4810SThomas Lively   return DAG.getBitcast(DstType, NewShuffle);
245740af4810SThomas Lively }
245840af4810SThomas Lively 
2459f5764a86SThomas Lively static SDValue
performVectorExtendCombine(SDNode * N,TargetLowering::DAGCombinerInfo & DCI)2460f5764a86SThomas Lively performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
246111bb7eefSThomas Lively   auto &DAG = DCI.DAG;
246211bb7eefSThomas Lively   assert(N->getOpcode() == ISD::SIGN_EXTEND ||
246311bb7eefSThomas Lively          N->getOpcode() == ISD::ZERO_EXTEND);
246411bb7eefSThomas Lively 
246511bb7eefSThomas Lively   // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if
246611bb7eefSThomas Lively   // possible before the extract_subvector can be expanded.
246711bb7eefSThomas Lively   auto Extract = N->getOperand(0);
246811bb7eefSThomas Lively   if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR)
246911bb7eefSThomas Lively     return SDValue();
247011bb7eefSThomas Lively   auto Source = Extract.getOperand(0);
247111bb7eefSThomas Lively   auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1));
247211bb7eefSThomas Lively   if (IndexNode == nullptr)
247311bb7eefSThomas Lively     return SDValue();
247411bb7eefSThomas Lively   auto Index = IndexNode->getZExtValue();
247511bb7eefSThomas Lively 
24766a18cc23SThomas Lively   // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the
24776a18cc23SThomas Lively   // extracted subvector is the low or high half of its source.
247811bb7eefSThomas Lively   EVT ResVT = N->getValueType(0);
247911bb7eefSThomas Lively   if (ResVT == MVT::v8i16) {
248011bb7eefSThomas Lively     if (Extract.getValueType() != MVT::v8i8 ||
248111bb7eefSThomas Lively         Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8))
248211bb7eefSThomas Lively       return SDValue();
248311bb7eefSThomas Lively   } else if (ResVT == MVT::v4i32) {
248411bb7eefSThomas Lively     if (Extract.getValueType() != MVT::v4i16 ||
248511bb7eefSThomas Lively         Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4))
248611bb7eefSThomas Lively       return SDValue();
24876a18cc23SThomas Lively   } else if (ResVT == MVT::v2i64) {
24886a18cc23SThomas Lively     if (Extract.getValueType() != MVT::v2i32 ||
24896a18cc23SThomas Lively         Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2))
24906a18cc23SThomas Lively       return SDValue();
249111bb7eefSThomas Lively   } else {
249211bb7eefSThomas Lively     return SDValue();
249311bb7eefSThomas Lively   }
249411bb7eefSThomas Lively 
249511bb7eefSThomas Lively   bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND;
249611bb7eefSThomas Lively   bool IsLow = Index == 0;
249711bb7eefSThomas Lively 
2498f5764a86SThomas Lively   unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S
2499f5764a86SThomas Lively                                 : WebAssemblyISD::EXTEND_HIGH_S)
2500f5764a86SThomas Lively                        : (IsLow ? WebAssemblyISD::EXTEND_LOW_U
2501f5764a86SThomas Lively                                 : WebAssemblyISD::EXTEND_HIGH_U);
250211bb7eefSThomas Lively 
250311bb7eefSThomas Lively   return DAG.getNode(Op, SDLoc(N), ResVT, Source);
250411bb7eefSThomas Lively }
250511bb7eefSThomas Lively 
2506af7925b4SThomas Lively static SDValue
performVectorTruncZeroCombine(SDNode * N,TargetLowering::DAGCombinerInfo & DCI)2507cbabfc63SThomas Lively performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
25085c729750SThomas Lively   auto &DAG = DCI.DAG;
25095c729750SThomas Lively 
2510cbabfc63SThomas Lively   auto GetWasmConversionOp = [](unsigned Op) {
2511cbabfc63SThomas Lively     switch (Op) {
2512cbabfc63SThomas Lively     case ISD::FP_TO_SINT_SAT:
2513cbabfc63SThomas Lively       return WebAssemblyISD::TRUNC_SAT_ZERO_S;
2514cbabfc63SThomas Lively     case ISD::FP_TO_UINT_SAT:
2515cbabfc63SThomas Lively       return WebAssemblyISD::TRUNC_SAT_ZERO_U;
2516cbabfc63SThomas Lively     case ISD::FP_ROUND:
2517cbabfc63SThomas Lively       return WebAssemblyISD::DEMOTE_ZERO;
2518cbabfc63SThomas Lively     }
2519cbabfc63SThomas Lively     llvm_unreachable("unexpected op");
2520cbabfc63SThomas Lively   };
2521cbabfc63SThomas Lively 
2522cbabfc63SThomas Lively   auto IsZeroSplat = [](SDValue SplatVal) {
2523cbabfc63SThomas Lively     auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode());
2524cbabfc63SThomas Lively     APInt SplatValue, SplatUndef;
2525cbabfc63SThomas Lively     unsigned SplatBitSize;
2526cbabfc63SThomas Lively     bool HasAnyUndefs;
2527cbabfc63SThomas Lively     return Splat &&
2528cbabfc63SThomas Lively            Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
2529cbabfc63SThomas Lively                                   HasAnyUndefs) &&
2530cbabfc63SThomas Lively            SplatValue == 0;
2531cbabfc63SThomas Lively   };
2532cbabfc63SThomas Lively 
2533cbabfc63SThomas Lively   if (N->getOpcode() == ISD::CONCAT_VECTORS) {
25345c729750SThomas Lively     // Combine this:
25355c729750SThomas Lively     //
25365c729750SThomas Lively     //   (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0)))
25375c729750SThomas Lively     //
25385c729750SThomas Lively     // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
2539cbabfc63SThomas Lively     //
2540cbabfc63SThomas Lively     // Or this:
2541cbabfc63SThomas Lively     //
2542cbabfc63SThomas Lively     //   (concat_vectors (v2f32 (fp_round (v2f64 $x))), (v2f32 (splat 0)))
2543cbabfc63SThomas Lively     //
2544cbabfc63SThomas Lively     // into (f32x4.demote_zero_f64x2 $x).
2545cbabfc63SThomas Lively     EVT ResVT;
2546cbabfc63SThomas Lively     EVT ExpectedConversionType;
2547cbabfc63SThomas Lively     auto Conversion = N->getOperand(0);
2548cbabfc63SThomas Lively     auto ConversionOp = Conversion.getOpcode();
2549cbabfc63SThomas Lively     switch (ConversionOp) {
2550cbabfc63SThomas Lively     case ISD::FP_TO_SINT_SAT:
2551cbabfc63SThomas Lively     case ISD::FP_TO_UINT_SAT:
2552cbabfc63SThomas Lively       ResVT = MVT::v4i32;
2553cbabfc63SThomas Lively       ExpectedConversionType = MVT::v2i32;
2554cbabfc63SThomas Lively       break;
2555cbabfc63SThomas Lively     case ISD::FP_ROUND:
2556cbabfc63SThomas Lively       ResVT = MVT::v4f32;
2557cbabfc63SThomas Lively       ExpectedConversionType = MVT::v2f32;
2558cbabfc63SThomas Lively       break;
2559cbabfc63SThomas Lively     default:
2560cbabfc63SThomas Lively       return SDValue();
2561cbabfc63SThomas Lively     }
2562cbabfc63SThomas Lively 
2563cbabfc63SThomas Lively     if (N->getValueType(0) != ResVT)
25645c729750SThomas Lively       return SDValue();
25655c729750SThomas Lively 
2566cbabfc63SThomas Lively     if (Conversion.getValueType() != ExpectedConversionType)
25675c729750SThomas Lively       return SDValue();
25685c729750SThomas Lively 
2569cbabfc63SThomas Lively     auto Source = Conversion.getOperand(0);
25705c729750SThomas Lively     if (Source.getValueType() != MVT::v2f64)
25715c729750SThomas Lively       return SDValue();
25725c729750SThomas Lively 
2573cbabfc63SThomas Lively     if (!IsZeroSplat(N->getOperand(1)) ||
2574cbabfc63SThomas Lively         N->getOperand(1).getValueType() != ExpectedConversionType)
25755c729750SThomas Lively       return SDValue();
25765c729750SThomas Lively 
2577cbabfc63SThomas Lively     unsigned Op = GetWasmConversionOp(ConversionOp);
2578cbabfc63SThomas Lively     return DAG.getNode(Op, SDLoc(N), ResVT, Source);
2579cbabfc63SThomas Lively   }
25805c729750SThomas Lively 
2581cbabfc63SThomas Lively   // Combine this:
2582cbabfc63SThomas Lively   //
2583cbabfc63SThomas Lively   //   (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32)
2584cbabfc63SThomas Lively   //
2585cbabfc63SThomas Lively   // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
2586cbabfc63SThomas Lively   //
2587cbabfc63SThomas Lively   // Or this:
2588cbabfc63SThomas Lively   //
2589cbabfc63SThomas Lively   //   (v4f32 (fp_round (concat_vectors $x, (v2f64 (splat 0)))))
2590cbabfc63SThomas Lively   //
2591cbabfc63SThomas Lively   // into (f32x4.demote_zero_f64x2 $x).
2592cbabfc63SThomas Lively   EVT ResVT;
2593cbabfc63SThomas Lively   auto ConversionOp = N->getOpcode();
2594cbabfc63SThomas Lively   switch (ConversionOp) {
2595cbabfc63SThomas Lively   case ISD::FP_TO_SINT_SAT:
2596cbabfc63SThomas Lively   case ISD::FP_TO_UINT_SAT:
2597cbabfc63SThomas Lively     ResVT = MVT::v4i32;
2598cbabfc63SThomas Lively     break;
2599cbabfc63SThomas Lively   case ISD::FP_ROUND:
2600cbabfc63SThomas Lively     ResVT = MVT::v4f32;
2601cbabfc63SThomas Lively     break;
2602cbabfc63SThomas Lively   default:
2603cbabfc63SThomas Lively     llvm_unreachable("unexpected op");
2604cbabfc63SThomas Lively   }
2605cbabfc63SThomas Lively 
2606cbabfc63SThomas Lively   if (N->getValueType(0) != ResVT)
2607cbabfc63SThomas Lively     return SDValue();
2608cbabfc63SThomas Lively 
2609cbabfc63SThomas Lively   auto Concat = N->getOperand(0);
2610cbabfc63SThomas Lively   if (Concat.getValueType() != MVT::v4f64)
2611cbabfc63SThomas Lively     return SDValue();
2612cbabfc63SThomas Lively 
2613cbabfc63SThomas Lively   auto Source = Concat.getOperand(0);
2614cbabfc63SThomas Lively   if (Source.getValueType() != MVT::v2f64)
2615cbabfc63SThomas Lively     return SDValue();
2616cbabfc63SThomas Lively 
2617cbabfc63SThomas Lively   if (!IsZeroSplat(Concat.getOperand(1)) ||
2618cbabfc63SThomas Lively       Concat.getOperand(1).getValueType() != MVT::v2f64)
2619cbabfc63SThomas Lively     return SDValue();
2620cbabfc63SThomas Lively 
2621cbabfc63SThomas Lively   unsigned Op = GetWasmConversionOp(ConversionOp);
26225c729750SThomas Lively   return DAG.getNode(Op, SDLoc(N), ResVT, Source);
26235c729750SThomas Lively }
26245c729750SThomas Lively 
26252a4a229dSJing Bao // Helper to extract VectorWidth bits from Vec, starting from IdxVal.
extractSubVector(SDValue Vec,unsigned IdxVal,SelectionDAG & DAG,const SDLoc & DL,unsigned VectorWidth)26262a4a229dSJing Bao static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG,
26272a4a229dSJing Bao                                 const SDLoc &DL, unsigned VectorWidth) {
26282a4a229dSJing Bao   EVT VT = Vec.getValueType();
26292a4a229dSJing Bao   EVT ElVT = VT.getVectorElementType();
26302a4a229dSJing Bao   unsigned Factor = VT.getSizeInBits() / VectorWidth;
26312a4a229dSJing Bao   EVT ResultVT = EVT::getVectorVT(*DAG.getContext(), ElVT,
26322a4a229dSJing Bao                                   VT.getVectorNumElements() / Factor);
26332a4a229dSJing Bao 
26342a4a229dSJing Bao   // Extract the relevant VectorWidth bits.  Generate an EXTRACT_SUBVECTOR
26352a4a229dSJing Bao   unsigned ElemsPerChunk = VectorWidth / ElVT.getSizeInBits();
26362a4a229dSJing Bao   assert(isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2");
26372a4a229dSJing Bao 
26382a4a229dSJing Bao   // This is the index of the first element of the VectorWidth-bit chunk
26392a4a229dSJing Bao   // we want. Since ElemsPerChunk is a power of 2 just need to clear bits.
26402a4a229dSJing Bao   IdxVal &= ~(ElemsPerChunk - 1);
26412a4a229dSJing Bao 
26422a4a229dSJing Bao   // If the input is a buildvector just emit a smaller one.
26432a4a229dSJing Bao   if (Vec.getOpcode() == ISD::BUILD_VECTOR)
26442a4a229dSJing Bao     return DAG.getBuildVector(ResultVT, DL,
26452a4a229dSJing Bao                               Vec->ops().slice(IdxVal, ElemsPerChunk));
26462a4a229dSJing Bao 
26472a4a229dSJing Bao   SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, DL);
26482a4a229dSJing Bao   return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResultVT, Vec, VecIdx);
26492a4a229dSJing Bao }
26502a4a229dSJing Bao 
26512a4a229dSJing Bao // Helper to recursively truncate vector elements in half with NARROW_U. DstVT
26522a4a229dSJing Bao // is the expected destination value type after recursion. In is the initial
26532a4a229dSJing Bao // input. Note that the input should have enough leading zero bits to prevent
26542a4a229dSJing Bao // NARROW_U from saturating results.
truncateVectorWithNARROW(EVT DstVT,SDValue In,const SDLoc & DL,SelectionDAG & DAG)26552a4a229dSJing Bao static SDValue truncateVectorWithNARROW(EVT DstVT, SDValue In, const SDLoc &DL,
26562a4a229dSJing Bao                                         SelectionDAG &DAG) {
26572a4a229dSJing Bao   EVT SrcVT = In.getValueType();
26582a4a229dSJing Bao 
26592a4a229dSJing Bao   // No truncation required, we might get here due to recursive calls.
26602a4a229dSJing Bao   if (SrcVT == DstVT)
26612a4a229dSJing Bao     return In;
26622a4a229dSJing Bao 
26632a4a229dSJing Bao   unsigned SrcSizeInBits = SrcVT.getSizeInBits();
26642a4a229dSJing Bao   unsigned NumElems = SrcVT.getVectorNumElements();
26652a4a229dSJing Bao   if (!isPowerOf2_32(NumElems))
26662a4a229dSJing Bao     return SDValue();
26672a4a229dSJing Bao   assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation");
26682a4a229dSJing Bao   assert(SrcSizeInBits > DstVT.getSizeInBits() && "Illegal truncation");
26692a4a229dSJing Bao 
26702a4a229dSJing Bao   LLVMContext &Ctx = *DAG.getContext();
26712a4a229dSJing Bao   EVT PackedSVT = EVT::getIntegerVT(Ctx, SrcVT.getScalarSizeInBits() / 2);
26722a4a229dSJing Bao 
26732a4a229dSJing Bao   // Narrow to the largest type possible:
26742a4a229dSJing Bao   // vXi64/vXi32 -> i16x8.narrow_i32x4_u and vXi16 -> i8x16.narrow_i16x8_u.
26752a4a229dSJing Bao   EVT InVT = MVT::i16, OutVT = MVT::i8;
26762a4a229dSJing Bao   if (SrcVT.getScalarSizeInBits() > 16) {
26772a4a229dSJing Bao     InVT = MVT::i32;
26782a4a229dSJing Bao     OutVT = MVT::i16;
26792a4a229dSJing Bao   }
26802a4a229dSJing Bao   unsigned SubSizeInBits = SrcSizeInBits / 2;
26812a4a229dSJing Bao   InVT = EVT::getVectorVT(Ctx, InVT, SubSizeInBits / InVT.getSizeInBits());
26822a4a229dSJing Bao   OutVT = EVT::getVectorVT(Ctx, OutVT, SubSizeInBits / OutVT.getSizeInBits());
26832a4a229dSJing Bao 
26842a4a229dSJing Bao   // Split lower/upper subvectors.
26852a4a229dSJing Bao   SDValue Lo = extractSubVector(In, 0, DAG, DL, SubSizeInBits);
26862a4a229dSJing Bao   SDValue Hi = extractSubVector(In, NumElems / 2, DAG, DL, SubSizeInBits);
26872a4a229dSJing Bao 
26882a4a229dSJing Bao   // 256bit -> 128bit truncate - Narrow lower/upper 128-bit subvectors.
26892a4a229dSJing Bao   if (SrcVT.is256BitVector() && DstVT.is128BitVector()) {
26902a4a229dSJing Bao     Lo = DAG.getBitcast(InVT, Lo);
26912a4a229dSJing Bao     Hi = DAG.getBitcast(InVT, Hi);
26922a4a229dSJing Bao     SDValue Res = DAG.getNode(WebAssemblyISD::NARROW_U, DL, OutVT, Lo, Hi);
26932a4a229dSJing Bao     return DAG.getBitcast(DstVT, Res);
26942a4a229dSJing Bao   }
26952a4a229dSJing Bao 
26962a4a229dSJing Bao   // Recursively narrow lower/upper subvectors, concat result and narrow again.
26972a4a229dSJing Bao   EVT PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems / 2);
26982a4a229dSJing Bao   Lo = truncateVectorWithNARROW(PackedVT, Lo, DL, DAG);
26992a4a229dSJing Bao   Hi = truncateVectorWithNARROW(PackedVT, Hi, DL, DAG);
27002a4a229dSJing Bao 
27012a4a229dSJing Bao   PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems);
27022a4a229dSJing Bao   SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi);
27032a4a229dSJing Bao   return truncateVectorWithNARROW(DstVT, Res, DL, DAG);
27042a4a229dSJing Bao }
27052a4a229dSJing Bao 
performTruncateCombine(SDNode * N,TargetLowering::DAGCombinerInfo & DCI)27062a4a229dSJing Bao static SDValue performTruncateCombine(SDNode *N,
27072a4a229dSJing Bao                                       TargetLowering::DAGCombinerInfo &DCI) {
27082a4a229dSJing Bao   auto &DAG = DCI.DAG;
27092a4a229dSJing Bao 
27102a4a229dSJing Bao   SDValue In = N->getOperand(0);
27112a4a229dSJing Bao   EVT InVT = In.getValueType();
27122a4a229dSJing Bao   if (!InVT.isSimple())
27132a4a229dSJing Bao     return SDValue();
27142a4a229dSJing Bao 
27152a4a229dSJing Bao   EVT OutVT = N->getValueType(0);
27162a4a229dSJing Bao   if (!OutVT.isVector())
27172a4a229dSJing Bao     return SDValue();
27182a4a229dSJing Bao 
27192a4a229dSJing Bao   EVT OutSVT = OutVT.getVectorElementType();
27202a4a229dSJing Bao   EVT InSVT = InVT.getVectorElementType();
27212a4a229dSJing Bao   // Currently only cover truncate to v16i8 or v8i16.
27222a4a229dSJing Bao   if (!((InSVT == MVT::i16 || InSVT == MVT::i32 || InSVT == MVT::i64) &&
27232a4a229dSJing Bao         (OutSVT == MVT::i8 || OutSVT == MVT::i16) && OutVT.is128BitVector()))
27242a4a229dSJing Bao     return SDValue();
27252a4a229dSJing Bao 
27262a4a229dSJing Bao   SDLoc DL(N);
27272a4a229dSJing Bao   APInt Mask = APInt::getLowBitsSet(InVT.getScalarSizeInBits(),
27282a4a229dSJing Bao                                     OutVT.getScalarSizeInBits());
27292a4a229dSJing Bao   In = DAG.getNode(ISD::AND, DL, InVT, In, DAG.getConstant(Mask, DL, InVT));
27302a4a229dSJing Bao   return truncateVectorWithNARROW(OutVT, In, DL, DAG);
27312a4a229dSJing Bao }
27322a4a229dSJing Bao 
273340af4810SThomas Lively SDValue
PerformDAGCombine(SDNode * N,DAGCombinerInfo & DCI) const273440af4810SThomas Lively WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N,
273540af4810SThomas Lively                                              DAGCombinerInfo &DCI) const {
273640af4810SThomas Lively   switch (N->getOpcode()) {
273740af4810SThomas Lively   default:
273840af4810SThomas Lively     return SDValue();
273940af4810SThomas Lively   case ISD::VECTOR_SHUFFLE:
274040af4810SThomas Lively     return performVECTOR_SHUFFLECombine(N, DCI);
274111bb7eefSThomas Lively   case ISD::SIGN_EXTEND:
274211bb7eefSThomas Lively   case ISD::ZERO_EXTEND:
2743f5764a86SThomas Lively     return performVectorExtendCombine(N, DCI);
2744cbabfc63SThomas Lively   case ISD::FP_TO_SINT_SAT:
2745cbabfc63SThomas Lively   case ISD::FP_TO_UINT_SAT:
2746cbabfc63SThomas Lively   case ISD::FP_ROUND:
27475c729750SThomas Lively   case ISD::CONCAT_VECTORS:
2748cbabfc63SThomas Lively     return performVectorTruncZeroCombine(N, DCI);
27492a4a229dSJing Bao   case ISD::TRUNCATE:
27502a4a229dSJing Bao     return performTruncateCombine(N, DCI);
275140af4810SThomas Lively   }
275240af4810SThomas Lively }
2753