1 //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file implements the WebAssemblyTargetLowering class. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "WebAssemblyISelLowering.h" 15 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 16 #include "Utils/WebAssemblyTypeUtilities.h" 17 #include "Utils/WebAssemblyUtilities.h" 18 #include "WebAssemblyMachineFunctionInfo.h" 19 #include "WebAssemblySubtarget.h" 20 #include "WebAssemblyTargetMachine.h" 21 #include "llvm/CodeGen/CallingConvLower.h" 22 #include "llvm/CodeGen/MachineInstrBuilder.h" 23 #include "llvm/CodeGen/MachineJumpTableInfo.h" 24 #include "llvm/CodeGen/MachineModuleInfo.h" 25 #include "llvm/CodeGen/MachineRegisterInfo.h" 26 #include "llvm/CodeGen/SelectionDAG.h" 27 #include "llvm/CodeGen/SelectionDAGNodes.h" 28 #include "llvm/CodeGen/WasmEHFuncInfo.h" 29 #include "llvm/IR/DiagnosticInfo.h" 30 #include "llvm/IR/DiagnosticPrinter.h" 31 #include "llvm/IR/Function.h" 32 #include "llvm/IR/Intrinsics.h" 33 #include "llvm/IR/IntrinsicsWebAssembly.h" 34 #include "llvm/Support/Debug.h" 35 #include "llvm/Support/ErrorHandling.h" 36 #include "llvm/Support/KnownBits.h" 37 #include "llvm/Support/MathExtras.h" 38 #include "llvm/Support/raw_ostream.h" 39 #include "llvm/Target/TargetOptions.h" 40 using namespace llvm; 41 42 #define DEBUG_TYPE "wasm-lower" 43 44 WebAssemblyTargetLowering::WebAssemblyTargetLowering( 45 const TargetMachine &TM, const WebAssemblySubtarget &STI) 46 : TargetLowering(TM), Subtarget(&STI) { 47 auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; 48 49 // Booleans always contain 0 or 1. 50 setBooleanContents(ZeroOrOneBooleanContent); 51 // Except in SIMD vectors 52 setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); 53 // We don't know the microarchitecture here, so just reduce register pressure. 54 setSchedulingPreference(Sched::RegPressure); 55 // Tell ISel that we have a stack pointer. 56 setStackPointerRegisterToSaveRestore( 57 Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); 58 // Set up the register classes. 59 addRegisterClass(MVT::i32, &WebAssembly::I32RegClass); 60 addRegisterClass(MVT::i64, &WebAssembly::I64RegClass); 61 addRegisterClass(MVT::f32, &WebAssembly::F32RegClass); 62 addRegisterClass(MVT::f64, &WebAssembly::F64RegClass); 63 if (Subtarget->hasSIMD128()) { 64 addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass); 65 addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass); 66 addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass); 67 addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass); 68 addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); 69 addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); 70 } 71 if (Subtarget->hasReferenceTypes()) { 72 addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass); 73 addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass); 74 } 75 // Compute derived properties from the register classes. 76 computeRegisterProperties(Subtarget->getRegisterInfo()); 77 78 // Transform loads and stores to pointers in address space 1 to loads and 79 // stores to WebAssembly global variables, outside linear memory. 80 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) { 81 setOperationAction(ISD::LOAD, T, Custom); 82 setOperationAction(ISD::STORE, T, Custom); 83 } 84 if (Subtarget->hasSIMD128()) { 85 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 86 MVT::v2f64}) { 87 setOperationAction(ISD::LOAD, T, Custom); 88 setOperationAction(ISD::STORE, T, Custom); 89 } 90 } 91 if (Subtarget->hasReferenceTypes()) { 92 for (auto T : {MVT::externref, MVT::funcref}) { 93 setOperationAction(ISD::LOAD, T, Custom); 94 setOperationAction(ISD::STORE, T, Custom); 95 } 96 } 97 98 setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); 99 setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom); 100 setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); 101 setOperationAction(ISD::JumpTable, MVTPtr, Custom); 102 setOperationAction(ISD::BlockAddress, MVTPtr, Custom); 103 setOperationAction(ISD::BRIND, MVT::Other, Custom); 104 105 // Take the default expansion for va_arg, va_copy, and va_end. There is no 106 // default action for va_start, so we do that custom. 107 setOperationAction(ISD::VASTART, MVT::Other, Custom); 108 setOperationAction(ISD::VAARG, MVT::Other, Expand); 109 setOperationAction(ISD::VACOPY, MVT::Other, Expand); 110 setOperationAction(ISD::VAEND, MVT::Other, Expand); 111 112 for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) { 113 // Don't expand the floating-point types to constant pools. 114 setOperationAction(ISD::ConstantFP, T, Legal); 115 // Expand floating-point comparisons. 116 for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, 117 ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) 118 setCondCodeAction(CC, T, Expand); 119 // Expand floating-point library function operators. 120 for (auto Op : 121 {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA}) 122 setOperationAction(Op, T, Expand); 123 // Note supported floating-point library function operators that otherwise 124 // default to expand. 125 for (auto Op : 126 {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT}) 127 setOperationAction(Op, T, Legal); 128 // Support minimum and maximum, which otherwise default to expand. 129 setOperationAction(ISD::FMINIMUM, T, Legal); 130 setOperationAction(ISD::FMAXIMUM, T, Legal); 131 // WebAssembly currently has no builtin f16 support. 132 setOperationAction(ISD::FP16_TO_FP, T, Expand); 133 setOperationAction(ISD::FP_TO_FP16, T, Expand); 134 setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand); 135 setTruncStoreAction(T, MVT::f16, Expand); 136 } 137 138 // Expand unavailable integer operations. 139 for (auto Op : 140 {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU, 141 ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS, 142 ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) { 143 for (auto T : {MVT::i32, MVT::i64}) 144 setOperationAction(Op, T, Expand); 145 if (Subtarget->hasSIMD128()) 146 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 147 setOperationAction(Op, T, Expand); 148 } 149 150 if (Subtarget->hasNontrappingFPToInt()) 151 for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) 152 for (auto T : {MVT::i32, MVT::i64}) 153 setOperationAction(Op, T, Custom); 154 155 // SIMD-specific configuration 156 if (Subtarget->hasSIMD128()) { 157 // Hoist bitcasts out of shuffles 158 setTargetDAGCombine(ISD::VECTOR_SHUFFLE); 159 160 // Combine extends of extract_subvectors into widening ops 161 setTargetDAGCombine(ISD::SIGN_EXTEND); 162 setTargetDAGCombine(ISD::ZERO_EXTEND); 163 164 // Combine int_to_fp or fp_extend of extract_vectors and vice versa into 165 // conversions ops 166 setTargetDAGCombine(ISD::SINT_TO_FP); 167 setTargetDAGCombine(ISD::UINT_TO_FP); 168 setTargetDAGCombine(ISD::FP_EXTEND); 169 setTargetDAGCombine(ISD::EXTRACT_SUBVECTOR); 170 171 // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa 172 // into conversion ops 173 setTargetDAGCombine(ISD::FP_TO_SINT_SAT); 174 setTargetDAGCombine(ISD::FP_TO_UINT_SAT); 175 setTargetDAGCombine(ISD::FP_ROUND); 176 setTargetDAGCombine(ISD::CONCAT_VECTORS); 177 178 // Support saturating add for i8x16 and i16x8 179 for (auto Op : {ISD::SADDSAT, ISD::UADDSAT}) 180 for (auto T : {MVT::v16i8, MVT::v8i16}) 181 setOperationAction(Op, T, Legal); 182 183 // Support integer abs 184 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 185 setOperationAction(ISD::ABS, T, Legal); 186 187 // Custom lower BUILD_VECTORs to minimize number of replace_lanes 188 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 189 MVT::v2f64}) 190 setOperationAction(ISD::BUILD_VECTOR, T, Custom); 191 192 // We have custom shuffle lowering to expose the shuffle mask 193 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 194 MVT::v2f64}) 195 setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom); 196 197 // Custom lowering since wasm shifts must have a scalar shift amount 198 for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) 199 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 200 setOperationAction(Op, T, Custom); 201 202 // Custom lower lane accesses to expand out variable indices 203 for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT}) 204 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 205 MVT::v2f64}) 206 setOperationAction(Op, T, Custom); 207 208 // There is no i8x16.mul instruction 209 setOperationAction(ISD::MUL, MVT::v16i8, Expand); 210 211 // There is no vector conditional select instruction 212 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, 213 MVT::v2f64}) 214 setOperationAction(ISD::SELECT_CC, T, Expand); 215 216 // Expand integer operations supported for scalars but not SIMD 217 for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP, ISD::SDIV, ISD::UDIV, 218 ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR}) 219 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) 220 setOperationAction(Op, T, Expand); 221 222 // But we do have integer min and max operations 223 for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) 224 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) 225 setOperationAction(Op, T, Legal); 226 227 // And we have popcnt for i8x16 228 setOperationAction(ISD::CTPOP, MVT::v16i8, Legal); 229 230 // Expand float operations supported for scalars but not SIMD 231 for (auto Op : {ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10, 232 ISD::FEXP, ISD::FEXP2, ISD::FRINT}) 233 for (auto T : {MVT::v4f32, MVT::v2f64}) 234 setOperationAction(Op, T, Expand); 235 236 // Unsigned comparison operations are unavailable for i64x2 vectors. 237 for (auto CC : {ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE}) 238 setCondCodeAction(CC, MVT::v2i64, Custom); 239 240 // 64x2 conversions are not in the spec 241 for (auto Op : 242 {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT}) 243 for (auto T : {MVT::v2i64, MVT::v2f64}) 244 setOperationAction(Op, T, Expand); 245 246 // But saturating fp_to_int converstions are 247 for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) 248 setOperationAction(Op, MVT::v4i32, Custom); 249 } 250 251 // As a special case, these operators use the type to mean the type to 252 // sign-extend from. 253 setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 254 if (!Subtarget->hasSignExt()) { 255 // Sign extends are legal only when extending a vector extract 256 auto Action = Subtarget->hasSIMD128() ? Custom : Expand; 257 for (auto T : {MVT::i8, MVT::i16, MVT::i32}) 258 setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action); 259 } 260 for (auto T : MVT::integer_fixedlen_vector_valuetypes()) 261 setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); 262 263 // Dynamic stack allocation: use the default expansion. 264 setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 265 setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 266 setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); 267 268 setOperationAction(ISD::FrameIndex, MVT::i32, Custom); 269 setOperationAction(ISD::FrameIndex, MVT::i64, Custom); 270 setOperationAction(ISD::CopyToReg, MVT::Other, Custom); 271 272 // Expand these forms; we pattern-match the forms that we can handle in isel. 273 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) 274 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) 275 setOperationAction(Op, T, Expand); 276 277 // We have custom switch handling. 278 setOperationAction(ISD::BR_JT, MVT::Other, Custom); 279 280 // WebAssembly doesn't have: 281 // - Floating-point extending loads. 282 // - Floating-point truncating stores. 283 // - i1 extending loads. 284 // - truncating SIMD stores and most extending loads 285 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 286 setTruncStoreAction(MVT::f64, MVT::f32, Expand); 287 for (auto T : MVT::integer_valuetypes()) 288 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 289 setLoadExtAction(Ext, T, MVT::i1, Promote); 290 if (Subtarget->hasSIMD128()) { 291 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, 292 MVT::v2f64}) { 293 for (auto MemT : MVT::fixedlen_vector_valuetypes()) { 294 if (MVT(T) != MemT) { 295 setTruncStoreAction(T, MemT, Expand); 296 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 297 setLoadExtAction(Ext, T, MemT, Expand); 298 } 299 } 300 } 301 // But some vector extending loads are legal 302 for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) { 303 setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal); 304 setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal); 305 setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal); 306 } 307 // And some truncating stores are legal as well 308 setTruncStoreAction(MVT::v8i16, MVT::v8i8, Legal); 309 setTruncStoreAction(MVT::v4i32, MVT::v4i16, Legal); 310 } 311 312 // Don't do anything clever with build_pairs 313 setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand); 314 315 // Trap lowers to wasm unreachable 316 setOperationAction(ISD::TRAP, MVT::Other, Legal); 317 setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); 318 319 // Exception handling intrinsics 320 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); 321 setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 322 setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); 323 324 setMaxAtomicSizeInBitsSupported(64); 325 326 // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is 327 // consistent with the f64 and f128 names. 328 setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2"); 329 setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2"); 330 331 // Define the emscripten name for return address helper. 332 // TODO: when implementing other Wasm backends, make this generic or only do 333 // this on emscripten depending on what they end up doing. 334 setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address"); 335 336 // Always convert switches to br_tables unless there is only one case, which 337 // is equivalent to a simple branch. This reduces code size for wasm, and we 338 // defer possible jump table optimizations to the VM. 339 setMinimumJumpTableEntries(2); 340 } 341 342 TargetLowering::AtomicExpansionKind 343 WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { 344 // We have wasm instructions for these 345 switch (AI->getOperation()) { 346 case AtomicRMWInst::Add: 347 case AtomicRMWInst::Sub: 348 case AtomicRMWInst::And: 349 case AtomicRMWInst::Or: 350 case AtomicRMWInst::Xor: 351 case AtomicRMWInst::Xchg: 352 return AtomicExpansionKind::None; 353 default: 354 break; 355 } 356 return AtomicExpansionKind::CmpXChg; 357 } 358 359 bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const { 360 // Implementation copied from X86TargetLowering. 361 unsigned Opc = VecOp.getOpcode(); 362 363 // Assume target opcodes can't be scalarized. 364 // TODO - do we have any exceptions? 365 if (Opc >= ISD::BUILTIN_OP_END) 366 return false; 367 368 // If the vector op is not supported, try to convert to scalar. 369 EVT VecVT = VecOp.getValueType(); 370 if (!isOperationLegalOrCustomOrPromote(Opc, VecVT)) 371 return true; 372 373 // If the vector op is supported, but the scalar op is not, the transform may 374 // not be worthwhile. 375 EVT ScalarVT = VecVT.getScalarType(); 376 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT); 377 } 378 379 FastISel *WebAssemblyTargetLowering::createFastISel( 380 FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const { 381 return WebAssembly::createFastISel(FuncInfo, LibInfo); 382 } 383 384 MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, 385 EVT VT) const { 386 unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1); 387 if (BitWidth > 1 && BitWidth < 8) 388 BitWidth = 8; 389 390 if (BitWidth > 64) { 391 // The shift will be lowered to a libcall, and compiler-rt libcalls expect 392 // the count to be an i32. 393 BitWidth = 32; 394 assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) && 395 "32-bit shift counts ought to be enough for anyone"); 396 } 397 398 MVT Result = MVT::getIntegerVT(BitWidth); 399 assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE && 400 "Unable to represent scalar shift amount type"); 401 return Result; 402 } 403 404 // Lower an fp-to-int conversion operator from the LLVM opcode, which has an 405 // undefined result on invalid/overflow, to the WebAssembly opcode, which 406 // traps on invalid/overflow. 407 static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL, 408 MachineBasicBlock *BB, 409 const TargetInstrInfo &TII, 410 bool IsUnsigned, bool Int64, 411 bool Float64, unsigned LoweredOpcode) { 412 MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); 413 414 Register OutReg = MI.getOperand(0).getReg(); 415 Register InReg = MI.getOperand(1).getReg(); 416 417 unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32; 418 unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32; 419 unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32; 420 unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32; 421 unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; 422 unsigned Eqz = WebAssembly::EQZ_I32; 423 unsigned And = WebAssembly::AND_I32; 424 int64_t Limit = Int64 ? INT64_MIN : INT32_MIN; 425 int64_t Substitute = IsUnsigned ? 0 : Limit; 426 double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit; 427 auto &Context = BB->getParent()->getFunction().getContext(); 428 Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context); 429 430 const BasicBlock *LLVMBB = BB->getBasicBlock(); 431 MachineFunction *F = BB->getParent(); 432 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB); 433 MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB); 434 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB); 435 436 MachineFunction::iterator It = ++BB->getIterator(); 437 F->insert(It, FalseMBB); 438 F->insert(It, TrueMBB); 439 F->insert(It, DoneMBB); 440 441 // Transfer the remainder of BB and its successor edges to DoneMBB. 442 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end()); 443 DoneMBB->transferSuccessorsAndUpdatePHIs(BB); 444 445 BB->addSuccessor(TrueMBB); 446 BB->addSuccessor(FalseMBB); 447 TrueMBB->addSuccessor(DoneMBB); 448 FalseMBB->addSuccessor(DoneMBB); 449 450 unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg; 451 Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 452 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 453 CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 454 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 455 FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 456 TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 457 458 MI.eraseFromParent(); 459 // For signed numbers, we can do a single comparison to determine whether 460 // fabs(x) is within range. 461 if (IsUnsigned) { 462 Tmp0 = InReg; 463 } else { 464 BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg); 465 } 466 BuildMI(BB, DL, TII.get(FConst), Tmp1) 467 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal))); 468 BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1); 469 470 // For unsigned numbers, we have to do a separate comparison with zero. 471 if (IsUnsigned) { 472 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 473 Register SecondCmpReg = 474 MRI.createVirtualRegister(&WebAssembly::I32RegClass); 475 Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 476 BuildMI(BB, DL, TII.get(FConst), Tmp1) 477 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0))); 478 BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1); 479 BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg); 480 CmpReg = AndReg; 481 } 482 483 BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg); 484 485 // Create the CFG diamond to select between doing the conversion or using 486 // the substitute value. 487 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg); 488 BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg); 489 BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB); 490 BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute); 491 BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg) 492 .addReg(FalseReg) 493 .addMBB(FalseMBB) 494 .addReg(TrueReg) 495 .addMBB(TrueMBB); 496 497 return DoneMBB; 498 } 499 500 static MachineBasicBlock * 501 LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, 502 const WebAssemblySubtarget *Subtarget, 503 const TargetInstrInfo &TII) { 504 MachineInstr &CallParams = *CallResults.getPrevNode(); 505 assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS); 506 assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS || 507 CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS); 508 509 bool IsIndirect = CallParams.getOperand(0).isReg(); 510 bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS; 511 512 bool IsFuncrefCall = false; 513 if (IsIndirect) { 514 Register Reg = CallParams.getOperand(0).getReg(); 515 const MachineFunction *MF = BB->getParent(); 516 const MachineRegisterInfo &MRI = MF->getRegInfo(); 517 const TargetRegisterClass *TRC = MRI.getRegClass(Reg); 518 IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass); 519 assert(!IsFuncrefCall || Subtarget->hasReferenceTypes()); 520 } 521 522 unsigned CallOp; 523 if (IsIndirect && IsRetCall) { 524 CallOp = WebAssembly::RET_CALL_INDIRECT; 525 } else if (IsIndirect) { 526 CallOp = WebAssembly::CALL_INDIRECT; 527 } else if (IsRetCall) { 528 CallOp = WebAssembly::RET_CALL; 529 } else { 530 CallOp = WebAssembly::CALL; 531 } 532 533 MachineFunction &MF = *BB->getParent(); 534 const MCInstrDesc &MCID = TII.get(CallOp); 535 MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL)); 536 537 // See if we must truncate the function pointer. 538 // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers 539 // as 64-bit for uniformity with other pointer types. 540 // See also: WebAssemblyFastISel::selectCall 541 if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) { 542 Register Reg32 = 543 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); 544 auto &FnPtr = CallParams.getOperand(0); 545 BuildMI(*BB, CallResults.getIterator(), DL, 546 TII.get(WebAssembly::I32_WRAP_I64), Reg32) 547 .addReg(FnPtr.getReg()); 548 FnPtr.setReg(Reg32); 549 } 550 551 // Move the function pointer to the end of the arguments for indirect calls 552 if (IsIndirect) { 553 auto FnPtr = CallParams.getOperand(0); 554 CallParams.RemoveOperand(0); 555 CallParams.addOperand(FnPtr); 556 } 557 558 for (auto Def : CallResults.defs()) 559 MIB.add(Def); 560 561 if (IsIndirect) { 562 // Placeholder for the type index. 563 MIB.addImm(0); 564 // The table into which this call_indirect indexes. 565 MCSymbolWasm *Table = IsFuncrefCall 566 ? WebAssembly::getOrCreateFuncrefCallTableSymbol( 567 MF.getContext(), Subtarget) 568 : WebAssembly::getOrCreateFunctionTableSymbol( 569 MF.getContext(), Subtarget); 570 if (Subtarget->hasReferenceTypes()) { 571 MIB.addSym(Table); 572 } else { 573 // For the MVP there is at most one table whose number is 0, but we can't 574 // write a table symbol or issue relocations. Instead we just ensure the 575 // table is live and write a zero. 576 Table->setNoStrip(); 577 MIB.addImm(0); 578 } 579 } 580 581 for (auto Use : CallParams.uses()) 582 MIB.add(Use); 583 584 BB->insert(CallResults.getIterator(), MIB); 585 CallParams.eraseFromParent(); 586 CallResults.eraseFromParent(); 587 588 // If this is a funcref call, to avoid hidden GC roots, we need to clear the 589 // table slot with ref.null upon call_indirect return. 590 // 591 // This generates the following code, which comes right after a call_indirect 592 // of a funcref: 593 // 594 // i32.const 0 595 // ref.null func 596 // table.set __funcref_call_table 597 if (IsIndirect && IsFuncrefCall) { 598 MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( 599 MF.getContext(), Subtarget); 600 Register RegZero = 601 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); 602 MachineInstr *Const0 = 603 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0); 604 BB->insertAfter(MIB.getInstr()->getIterator(), Const0); 605 606 Register RegFuncref = 607 MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass); 608 MachineInstr *RefNull = 609 BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref) 610 .addImm(static_cast<int32_t>(WebAssembly::HeapType::Funcref)); 611 BB->insertAfter(Const0->getIterator(), RefNull); 612 613 MachineInstr *TableSet = 614 BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF)) 615 .addSym(Table) 616 .addReg(RegZero) 617 .addReg(RegFuncref); 618 BB->insertAfter(RefNull->getIterator(), TableSet); 619 } 620 621 return BB; 622 } 623 624 MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter( 625 MachineInstr &MI, MachineBasicBlock *BB) const { 626 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 627 DebugLoc DL = MI.getDebugLoc(); 628 629 switch (MI.getOpcode()) { 630 default: 631 llvm_unreachable("Unexpected instr type to insert"); 632 case WebAssembly::FP_TO_SINT_I32_F32: 633 return LowerFPToInt(MI, DL, BB, TII, false, false, false, 634 WebAssembly::I32_TRUNC_S_F32); 635 case WebAssembly::FP_TO_UINT_I32_F32: 636 return LowerFPToInt(MI, DL, BB, TII, true, false, false, 637 WebAssembly::I32_TRUNC_U_F32); 638 case WebAssembly::FP_TO_SINT_I64_F32: 639 return LowerFPToInt(MI, DL, BB, TII, false, true, false, 640 WebAssembly::I64_TRUNC_S_F32); 641 case WebAssembly::FP_TO_UINT_I64_F32: 642 return LowerFPToInt(MI, DL, BB, TII, true, true, false, 643 WebAssembly::I64_TRUNC_U_F32); 644 case WebAssembly::FP_TO_SINT_I32_F64: 645 return LowerFPToInt(MI, DL, BB, TII, false, false, true, 646 WebAssembly::I32_TRUNC_S_F64); 647 case WebAssembly::FP_TO_UINT_I32_F64: 648 return LowerFPToInt(MI, DL, BB, TII, true, false, true, 649 WebAssembly::I32_TRUNC_U_F64); 650 case WebAssembly::FP_TO_SINT_I64_F64: 651 return LowerFPToInt(MI, DL, BB, TII, false, true, true, 652 WebAssembly::I64_TRUNC_S_F64); 653 case WebAssembly::FP_TO_UINT_I64_F64: 654 return LowerFPToInt(MI, DL, BB, TII, true, true, true, 655 WebAssembly::I64_TRUNC_U_F64); 656 case WebAssembly::CALL_RESULTS: 657 case WebAssembly::RET_CALL_RESULTS: 658 return LowerCallResults(MI, DL, BB, Subtarget, TII); 659 } 660 } 661 662 const char * 663 WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const { 664 switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { 665 case WebAssemblyISD::FIRST_NUMBER: 666 case WebAssemblyISD::FIRST_MEM_OPCODE: 667 break; 668 #define HANDLE_NODETYPE(NODE) \ 669 case WebAssemblyISD::NODE: \ 670 return "WebAssemblyISD::" #NODE; 671 #define HANDLE_MEM_NODETYPE(NODE) HANDLE_NODETYPE(NODE) 672 #include "WebAssemblyISD.def" 673 #undef HANDLE_MEM_NODETYPE 674 #undef HANDLE_NODETYPE 675 } 676 return nullptr; 677 } 678 679 std::pair<unsigned, const TargetRegisterClass *> 680 WebAssemblyTargetLowering::getRegForInlineAsmConstraint( 681 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 682 // First, see if this is a constraint that directly corresponds to a 683 // WebAssembly register class. 684 if (Constraint.size() == 1) { 685 switch (Constraint[0]) { 686 case 'r': 687 assert(VT != MVT::iPTR && "Pointer MVT not expected here"); 688 if (Subtarget->hasSIMD128() && VT.isVector()) { 689 if (VT.getSizeInBits() == 128) 690 return std::make_pair(0U, &WebAssembly::V128RegClass); 691 } 692 if (VT.isInteger() && !VT.isVector()) { 693 if (VT.getSizeInBits() <= 32) 694 return std::make_pair(0U, &WebAssembly::I32RegClass); 695 if (VT.getSizeInBits() <= 64) 696 return std::make_pair(0U, &WebAssembly::I64RegClass); 697 } 698 if (VT.isFloatingPoint() && !VT.isVector()) { 699 switch (VT.getSizeInBits()) { 700 case 32: 701 return std::make_pair(0U, &WebAssembly::F32RegClass); 702 case 64: 703 return std::make_pair(0U, &WebAssembly::F64RegClass); 704 default: 705 break; 706 } 707 } 708 break; 709 default: 710 break; 711 } 712 } 713 714 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 715 } 716 717 bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const { 718 // Assume ctz is a relatively cheap operation. 719 return true; 720 } 721 722 bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const { 723 // Assume clz is a relatively cheap operation. 724 return true; 725 } 726 727 bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, 728 const AddrMode &AM, 729 Type *Ty, unsigned AS, 730 Instruction *I) const { 731 // WebAssembly offsets are added as unsigned without wrapping. The 732 // isLegalAddressingMode gives us no way to determine if wrapping could be 733 // happening, so we approximate this by accepting only non-negative offsets. 734 if (AM.BaseOffs < 0) 735 return false; 736 737 // WebAssembly has no scale register operands. 738 if (AM.Scale != 0) 739 return false; 740 741 // Everything else is legal. 742 return true; 743 } 744 745 bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( 746 EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/, 747 MachineMemOperand::Flags /*Flags*/, bool *Fast) const { 748 // WebAssembly supports unaligned accesses, though it should be declared 749 // with the p2align attribute on loads and stores which do so, and there 750 // may be a performance impact. We tell LLVM they're "fast" because 751 // for the kinds of things that LLVM uses this for (merging adjacent stores 752 // of constants, etc.), WebAssembly implementations will either want the 753 // unaligned access or they'll split anyway. 754 if (Fast) 755 *Fast = true; 756 return true; 757 } 758 759 bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, 760 AttributeList Attr) const { 761 // The current thinking is that wasm engines will perform this optimization, 762 // so we can save on code size. 763 return true; 764 } 765 766 bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { 767 EVT ExtT = ExtVal.getValueType(); 768 EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0); 769 return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) || 770 (ExtT == MVT::v4i32 && MemT == MVT::v4i16) || 771 (ExtT == MVT::v2i64 && MemT == MVT::v2i32); 772 } 773 774 EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL, 775 LLVMContext &C, 776 EVT VT) const { 777 if (VT.isVector()) 778 return VT.changeVectorElementTypeToInteger(); 779 780 // So far, all branch instructions in Wasm take an I32 condition. 781 // The default TargetLowering::getSetCCResultType returns the pointer size, 782 // which would be useful to reduce instruction counts when testing 783 // against 64-bit pointers/values if at some point Wasm supports that. 784 return EVT::getIntegerVT(C, 32); 785 } 786 787 bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, 788 const CallInst &I, 789 MachineFunction &MF, 790 unsigned Intrinsic) const { 791 switch (Intrinsic) { 792 case Intrinsic::wasm_memory_atomic_notify: 793 Info.opc = ISD::INTRINSIC_W_CHAIN; 794 Info.memVT = MVT::i32; 795 Info.ptrVal = I.getArgOperand(0); 796 Info.offset = 0; 797 Info.align = Align(4); 798 // atomic.notify instruction does not really load the memory specified with 799 // this argument, but MachineMemOperand should either be load or store, so 800 // we set this to a load. 801 // FIXME Volatile isn't really correct, but currently all LLVM atomic 802 // instructions are treated as volatiles in the backend, so we should be 803 // consistent. The same applies for wasm_atomic_wait intrinsics too. 804 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 805 return true; 806 case Intrinsic::wasm_memory_atomic_wait32: 807 Info.opc = ISD::INTRINSIC_W_CHAIN; 808 Info.memVT = MVT::i32; 809 Info.ptrVal = I.getArgOperand(0); 810 Info.offset = 0; 811 Info.align = Align(4); 812 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 813 return true; 814 case Intrinsic::wasm_memory_atomic_wait64: 815 Info.opc = ISD::INTRINSIC_W_CHAIN; 816 Info.memVT = MVT::i64; 817 Info.ptrVal = I.getArgOperand(0); 818 Info.offset = 0; 819 Info.align = Align(8); 820 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 821 return true; 822 default: 823 return false; 824 } 825 } 826 827 void WebAssemblyTargetLowering::computeKnownBitsForTargetNode( 828 const SDValue Op, KnownBits &Known, const APInt &DemandedElts, 829 const SelectionDAG &DAG, unsigned Depth) const { 830 switch (Op.getOpcode()) { 831 default: 832 break; 833 case ISD::INTRINSIC_WO_CHAIN: { 834 unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 835 switch (IntNo) { 836 default: 837 break; 838 case Intrinsic::wasm_bitmask: { 839 unsigned BitWidth = Known.getBitWidth(); 840 EVT VT = Op.getOperand(1).getSimpleValueType(); 841 unsigned PossibleBits = VT.getVectorNumElements(); 842 APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits); 843 Known.Zero |= ZeroMask; 844 break; 845 } 846 } 847 } 848 } 849 } 850 851 //===----------------------------------------------------------------------===// 852 // WebAssembly Lowering private implementation. 853 //===----------------------------------------------------------------------===// 854 855 //===----------------------------------------------------------------------===// 856 // Lowering Code 857 //===----------------------------------------------------------------------===// 858 859 static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) { 860 MachineFunction &MF = DAG.getMachineFunction(); 861 DAG.getContext()->diagnose( 862 DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc())); 863 } 864 865 // Test whether the given calling convention is supported. 866 static bool callingConvSupported(CallingConv::ID CallConv) { 867 // We currently support the language-independent target-independent 868 // conventions. We don't yet have a way to annotate calls with properties like 869 // "cold", and we don't have any call-clobbered registers, so these are mostly 870 // all handled the same. 871 return CallConv == CallingConv::C || CallConv == CallingConv::Fast || 872 CallConv == CallingConv::Cold || 873 CallConv == CallingConv::PreserveMost || 874 CallConv == CallingConv::PreserveAll || 875 CallConv == CallingConv::CXX_FAST_TLS || 876 CallConv == CallingConv::WASM_EmscriptenInvoke || 877 CallConv == CallingConv::Swift; 878 } 879 880 SDValue 881 WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, 882 SmallVectorImpl<SDValue> &InVals) const { 883 SelectionDAG &DAG = CLI.DAG; 884 SDLoc DL = CLI.DL; 885 SDValue Chain = CLI.Chain; 886 SDValue Callee = CLI.Callee; 887 MachineFunction &MF = DAG.getMachineFunction(); 888 auto Layout = MF.getDataLayout(); 889 890 CallingConv::ID CallConv = CLI.CallConv; 891 if (!callingConvSupported(CallConv)) 892 fail(DL, DAG, 893 "WebAssembly doesn't support language-specific or target-specific " 894 "calling conventions yet"); 895 if (CLI.IsPatchPoint) 896 fail(DL, DAG, "WebAssembly doesn't support patch point yet"); 897 898 if (CLI.IsTailCall) { 899 auto NoTail = [&](const char *Msg) { 900 if (CLI.CB && CLI.CB->isMustTailCall()) 901 fail(DL, DAG, Msg); 902 CLI.IsTailCall = false; 903 }; 904 905 if (!Subtarget->hasTailCall()) 906 NoTail("WebAssembly 'tail-call' feature not enabled"); 907 908 // Varargs calls cannot be tail calls because the buffer is on the stack 909 if (CLI.IsVarArg) 910 NoTail("WebAssembly does not support varargs tail calls"); 911 912 // Do not tail call unless caller and callee return types match 913 const Function &F = MF.getFunction(); 914 const TargetMachine &TM = getTargetMachine(); 915 Type *RetTy = F.getReturnType(); 916 SmallVector<MVT, 4> CallerRetTys; 917 SmallVector<MVT, 4> CalleeRetTys; 918 computeLegalValueVTs(F, TM, RetTy, CallerRetTys); 919 computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys); 920 bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() && 921 std::equal(CallerRetTys.begin(), CallerRetTys.end(), 922 CalleeRetTys.begin()); 923 if (!TypesMatch) 924 NoTail("WebAssembly tail call requires caller and callee return types to " 925 "match"); 926 927 // If pointers to local stack values are passed, we cannot tail call 928 if (CLI.CB) { 929 for (auto &Arg : CLI.CB->args()) { 930 Value *Val = Arg.get(); 931 // Trace the value back through pointer operations 932 while (true) { 933 Value *Src = Val->stripPointerCastsAndAliases(); 934 if (auto *GEP = dyn_cast<GetElementPtrInst>(Src)) 935 Src = GEP->getPointerOperand(); 936 if (Val == Src) 937 break; 938 Val = Src; 939 } 940 if (isa<AllocaInst>(Val)) { 941 NoTail( 942 "WebAssembly does not support tail calling with stack arguments"); 943 break; 944 } 945 } 946 } 947 } 948 949 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 950 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 951 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 952 953 // The generic code may have added an sret argument. If we're lowering an 954 // invoke function, the ABI requires that the function pointer be the first 955 // argument, so we may have to swap the arguments. 956 if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 && 957 Outs[0].Flags.isSRet()) { 958 std::swap(Outs[0], Outs[1]); 959 std::swap(OutVals[0], OutVals[1]); 960 } 961 962 bool HasSwiftSelfArg = false; 963 bool HasSwiftErrorArg = false; 964 unsigned NumFixedArgs = 0; 965 for (unsigned I = 0; I < Outs.size(); ++I) { 966 const ISD::OutputArg &Out = Outs[I]; 967 SDValue &OutVal = OutVals[I]; 968 HasSwiftSelfArg |= Out.Flags.isSwiftSelf(); 969 HasSwiftErrorArg |= Out.Flags.isSwiftError(); 970 if (Out.Flags.isNest()) 971 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 972 if (Out.Flags.isInAlloca()) 973 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 974 if (Out.Flags.isInConsecutiveRegs()) 975 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 976 if (Out.Flags.isInConsecutiveRegsLast()) 977 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 978 if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) { 979 auto &MFI = MF.getFrameInfo(); 980 int FI = MFI.CreateStackObject(Out.Flags.getByValSize(), 981 Out.Flags.getNonZeroByValAlign(), 982 /*isSS=*/false); 983 SDValue SizeNode = 984 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32); 985 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 986 Chain = DAG.getMemcpy( 987 Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getNonZeroByValAlign(), 988 /*isVolatile*/ false, /*AlwaysInline=*/false, 989 /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); 990 OutVal = FINode; 991 } 992 // Count the number of fixed args *after* legalization. 993 NumFixedArgs += Out.IsFixed; 994 } 995 996 bool IsVarArg = CLI.IsVarArg; 997 auto PtrVT = getPointerTy(Layout); 998 999 // For swiftcc, emit additional swiftself and swifterror arguments 1000 // if there aren't. These additional arguments are also added for callee 1001 // signature They are necessary to match callee and caller signature for 1002 // indirect call. 1003 if (CallConv == CallingConv::Swift) { 1004 if (!HasSwiftSelfArg) { 1005 NumFixedArgs++; 1006 ISD::OutputArg Arg; 1007 Arg.Flags.setSwiftSelf(); 1008 CLI.Outs.push_back(Arg); 1009 SDValue ArgVal = DAG.getUNDEF(PtrVT); 1010 CLI.OutVals.push_back(ArgVal); 1011 } 1012 if (!HasSwiftErrorArg) { 1013 NumFixedArgs++; 1014 ISD::OutputArg Arg; 1015 Arg.Flags.setSwiftError(); 1016 CLI.Outs.push_back(Arg); 1017 SDValue ArgVal = DAG.getUNDEF(PtrVT); 1018 CLI.OutVals.push_back(ArgVal); 1019 } 1020 } 1021 1022 // Analyze operands of the call, assigning locations to each operand. 1023 SmallVector<CCValAssign, 16> ArgLocs; 1024 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 1025 1026 if (IsVarArg) { 1027 // Outgoing non-fixed arguments are placed in a buffer. First 1028 // compute their offsets and the total amount of buffer space needed. 1029 for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) { 1030 const ISD::OutputArg &Out = Outs[I]; 1031 SDValue &Arg = OutVals[I]; 1032 EVT VT = Arg.getValueType(); 1033 assert(VT != MVT::iPTR && "Legalized args should be concrete"); 1034 Type *Ty = VT.getTypeForEVT(*DAG.getContext()); 1035 Align Alignment = 1036 std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty)); 1037 unsigned Offset = 1038 CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment); 1039 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), 1040 Offset, VT.getSimpleVT(), 1041 CCValAssign::Full)); 1042 } 1043 } 1044 1045 unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); 1046 1047 SDValue FINode; 1048 if (IsVarArg && NumBytes) { 1049 // For non-fixed arguments, next emit stores to store the argument values 1050 // to the stack buffer at the offsets computed above. 1051 int FI = MF.getFrameInfo().CreateStackObject(NumBytes, 1052 Layout.getStackAlignment(), 1053 /*isSS=*/false); 1054 unsigned ValNo = 0; 1055 SmallVector<SDValue, 8> Chains; 1056 for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) { 1057 assert(ArgLocs[ValNo].getValNo() == ValNo && 1058 "ArgLocs should remain in order and only hold varargs args"); 1059 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); 1060 FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 1061 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode, 1062 DAG.getConstant(Offset, DL, PtrVT)); 1063 Chains.push_back( 1064 DAG.getStore(Chain, DL, Arg, Add, 1065 MachinePointerInfo::getFixedStack(MF, FI, Offset))); 1066 } 1067 if (!Chains.empty()) 1068 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); 1069 } else if (IsVarArg) { 1070 FINode = DAG.getIntPtrConstant(0, DL); 1071 } 1072 1073 if (Callee->getOpcode() == ISD::GlobalAddress) { 1074 // If the callee is a GlobalAddress node (quite common, every direct call 1075 // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress 1076 // doesn't at MO_GOT which is not needed for direct calls. 1077 GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee); 1078 Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL, 1079 getPointerTy(DAG.getDataLayout()), 1080 GA->getOffset()); 1081 Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL, 1082 getPointerTy(DAG.getDataLayout()), Callee); 1083 } 1084 1085 // Compute the operands for the CALLn node. 1086 SmallVector<SDValue, 16> Ops; 1087 Ops.push_back(Chain); 1088 Ops.push_back(Callee); 1089 1090 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs 1091 // isn't reliable. 1092 Ops.append(OutVals.begin(), 1093 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); 1094 // Add a pointer to the vararg buffer. 1095 if (IsVarArg) 1096 Ops.push_back(FINode); 1097 1098 SmallVector<EVT, 8> InTys; 1099 for (const auto &In : Ins) { 1100 assert(!In.Flags.isByVal() && "byval is not valid for return values"); 1101 assert(!In.Flags.isNest() && "nest is not valid for return values"); 1102 if (In.Flags.isInAlloca()) 1103 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values"); 1104 if (In.Flags.isInConsecutiveRegs()) 1105 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values"); 1106 if (In.Flags.isInConsecutiveRegsLast()) 1107 fail(DL, DAG, 1108 "WebAssembly hasn't implemented cons regs last return values"); 1109 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in 1110 // registers. 1111 InTys.push_back(In.VT); 1112 } 1113 1114 // Lastly, if this is a call to a funcref we need to add an instruction 1115 // table.set to the chain and transform the call. 1116 if (CLI.CB && isFuncrefType(CLI.CB->getCalledOperand()->getType())) { 1117 // In the absence of function references proposal where a funcref call is 1118 // lowered to call_ref, using reference types we generate a table.set to set 1119 // the funcref to a special table used solely for this purpose, followed by 1120 // a call_indirect. Here we just generate the table set, and return the 1121 // SDValue of the table.set so that LowerCall can finalize the lowering by 1122 // generating the call_indirect. 1123 SDValue Chain = Ops[0]; 1124 1125 MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( 1126 MF.getContext(), Subtarget); 1127 SDValue Sym = DAG.getMCSymbol(Table, PtrVT); 1128 SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32); 1129 SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee}; 1130 SDValue TableSet = DAG.getMemIntrinsicNode( 1131 WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps, 1132 MVT::funcref, 1133 // Machine Mem Operand args 1134 MachinePointerInfo(WasmAddressSpace::FUNCREF), 1135 CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()), 1136 MachineMemOperand::MOStore); 1137 1138 Ops[0] = TableSet; // The new chain is the TableSet itself 1139 } 1140 1141 if (CLI.IsTailCall) { 1142 // ret_calls do not return values to the current frame 1143 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 1144 return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops); 1145 } 1146 1147 InTys.push_back(MVT::Other); 1148 SDVTList InTyList = DAG.getVTList(InTys); 1149 SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops); 1150 1151 for (size_t I = 0; I < Ins.size(); ++I) 1152 InVals.push_back(Res.getValue(I)); 1153 1154 // Return the chain 1155 return Res.getValue(Ins.size()); 1156 } 1157 1158 bool WebAssemblyTargetLowering::CanLowerReturn( 1159 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/, 1160 const SmallVectorImpl<ISD::OutputArg> &Outs, 1161 LLVMContext & /*Context*/) const { 1162 // WebAssembly can only handle returning tuples with multivalue enabled 1163 return Subtarget->hasMultivalue() || Outs.size() <= 1; 1164 } 1165 1166 SDValue WebAssemblyTargetLowering::LowerReturn( 1167 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, 1168 const SmallVectorImpl<ISD::OutputArg> &Outs, 1169 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 1170 SelectionDAG &DAG) const { 1171 assert((Subtarget->hasMultivalue() || Outs.size() <= 1) && 1172 "MVP WebAssembly can only return up to one value"); 1173 if (!callingConvSupported(CallConv)) 1174 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 1175 1176 SmallVector<SDValue, 4> RetOps(1, Chain); 1177 RetOps.append(OutVals.begin(), OutVals.end()); 1178 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); 1179 1180 // Record the number and types of the return values. 1181 for (const ISD::OutputArg &Out : Outs) { 1182 assert(!Out.Flags.isByVal() && "byval is not valid for return values"); 1183 assert(!Out.Flags.isNest() && "nest is not valid for return values"); 1184 assert(Out.IsFixed && "non-fixed return value is not valid"); 1185 if (Out.Flags.isInAlloca()) 1186 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results"); 1187 if (Out.Flags.isInConsecutiveRegs()) 1188 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results"); 1189 if (Out.Flags.isInConsecutiveRegsLast()) 1190 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results"); 1191 } 1192 1193 return Chain; 1194 } 1195 1196 SDValue WebAssemblyTargetLowering::LowerFormalArguments( 1197 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 1198 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 1199 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 1200 if (!callingConvSupported(CallConv)) 1201 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 1202 1203 MachineFunction &MF = DAG.getMachineFunction(); 1204 auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); 1205 1206 // Set up the incoming ARGUMENTS value, which serves to represent the liveness 1207 // of the incoming values before they're represented by virtual registers. 1208 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); 1209 1210 bool HasSwiftErrorArg = false; 1211 bool HasSwiftSelfArg = false; 1212 for (const ISD::InputArg &In : Ins) { 1213 HasSwiftSelfArg |= In.Flags.isSwiftSelf(); 1214 HasSwiftErrorArg |= In.Flags.isSwiftError(); 1215 if (In.Flags.isInAlloca()) 1216 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 1217 if (In.Flags.isNest()) 1218 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 1219 if (In.Flags.isInConsecutiveRegs()) 1220 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 1221 if (In.Flags.isInConsecutiveRegsLast()) 1222 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 1223 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in 1224 // registers. 1225 InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, 1226 DAG.getTargetConstant(InVals.size(), 1227 DL, MVT::i32)) 1228 : DAG.getUNDEF(In.VT)); 1229 1230 // Record the number and types of arguments. 1231 MFI->addParam(In.VT); 1232 } 1233 1234 // For swiftcc, emit additional swiftself and swifterror arguments 1235 // if there aren't. These additional arguments are also added for callee 1236 // signature They are necessary to match callee and caller signature for 1237 // indirect call. 1238 auto PtrVT = getPointerTy(MF.getDataLayout()); 1239 if (CallConv == CallingConv::Swift) { 1240 if (!HasSwiftSelfArg) { 1241 MFI->addParam(PtrVT); 1242 } 1243 if (!HasSwiftErrorArg) { 1244 MFI->addParam(PtrVT); 1245 } 1246 } 1247 // Varargs are copied into a buffer allocated by the caller, and a pointer to 1248 // the buffer is passed as an argument. 1249 if (IsVarArg) { 1250 MVT PtrVT = getPointerTy(MF.getDataLayout()); 1251 Register VarargVreg = 1252 MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT)); 1253 MFI->setVarargBufferVreg(VarargVreg); 1254 Chain = DAG.getCopyToReg( 1255 Chain, DL, VarargVreg, 1256 DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT, 1257 DAG.getTargetConstant(Ins.size(), DL, MVT::i32))); 1258 MFI->addParam(PtrVT); 1259 } 1260 1261 // Record the number and types of arguments and results. 1262 SmallVector<MVT, 4> Params; 1263 SmallVector<MVT, 4> Results; 1264 computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(), 1265 MF.getFunction(), DAG.getTarget(), Params, Results); 1266 for (MVT VT : Results) 1267 MFI->addResult(VT); 1268 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify 1269 // the param logic here with ComputeSignatureVTs 1270 assert(MFI->getParams().size() == Params.size() && 1271 std::equal(MFI->getParams().begin(), MFI->getParams().end(), 1272 Params.begin())); 1273 1274 return Chain; 1275 } 1276 1277 void WebAssemblyTargetLowering::ReplaceNodeResults( 1278 SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 1279 switch (N->getOpcode()) { 1280 case ISD::SIGN_EXTEND_INREG: 1281 // Do not add any results, signifying that N should not be custom lowered 1282 // after all. This happens because simd128 turns on custom lowering for 1283 // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an 1284 // illegal type. 1285 break; 1286 default: 1287 llvm_unreachable( 1288 "ReplaceNodeResults not implemented for this op for WebAssembly!"); 1289 } 1290 } 1291 1292 //===----------------------------------------------------------------------===// 1293 // Custom lowering hooks. 1294 //===----------------------------------------------------------------------===// 1295 1296 SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, 1297 SelectionDAG &DAG) const { 1298 SDLoc DL(Op); 1299 switch (Op.getOpcode()) { 1300 default: 1301 llvm_unreachable("unimplemented operation lowering"); 1302 return SDValue(); 1303 case ISD::FrameIndex: 1304 return LowerFrameIndex(Op, DAG); 1305 case ISD::GlobalAddress: 1306 return LowerGlobalAddress(Op, DAG); 1307 case ISD::GlobalTLSAddress: 1308 return LowerGlobalTLSAddress(Op, DAG); 1309 case ISD::ExternalSymbol: 1310 return LowerExternalSymbol(Op, DAG); 1311 case ISD::JumpTable: 1312 return LowerJumpTable(Op, DAG); 1313 case ISD::BR_JT: 1314 return LowerBR_JT(Op, DAG); 1315 case ISD::VASTART: 1316 return LowerVASTART(Op, DAG); 1317 case ISD::BlockAddress: 1318 case ISD::BRIND: 1319 fail(DL, DAG, "WebAssembly hasn't implemented computed gotos"); 1320 return SDValue(); 1321 case ISD::RETURNADDR: 1322 return LowerRETURNADDR(Op, DAG); 1323 case ISD::FRAMEADDR: 1324 return LowerFRAMEADDR(Op, DAG); 1325 case ISD::CopyToReg: 1326 return LowerCopyToReg(Op, DAG); 1327 case ISD::EXTRACT_VECTOR_ELT: 1328 case ISD::INSERT_VECTOR_ELT: 1329 return LowerAccessVectorElement(Op, DAG); 1330 case ISD::INTRINSIC_VOID: 1331 case ISD::INTRINSIC_WO_CHAIN: 1332 case ISD::INTRINSIC_W_CHAIN: 1333 return LowerIntrinsic(Op, DAG); 1334 case ISD::SIGN_EXTEND_INREG: 1335 return LowerSIGN_EXTEND_INREG(Op, DAG); 1336 case ISD::BUILD_VECTOR: 1337 return LowerBUILD_VECTOR(Op, DAG); 1338 case ISD::VECTOR_SHUFFLE: 1339 return LowerVECTOR_SHUFFLE(Op, DAG); 1340 case ISD::SETCC: 1341 return LowerSETCC(Op, DAG); 1342 case ISD::SHL: 1343 case ISD::SRA: 1344 case ISD::SRL: 1345 return LowerShift(Op, DAG); 1346 case ISD::FP_TO_SINT_SAT: 1347 case ISD::FP_TO_UINT_SAT: 1348 return LowerFP_TO_INT_SAT(Op, DAG); 1349 case ISD::LOAD: 1350 return LowerLoad(Op, DAG); 1351 case ISD::STORE: 1352 return LowerStore(Op, DAG); 1353 } 1354 } 1355 1356 static bool IsWebAssemblyGlobal(SDValue Op) { 1357 if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op)) 1358 return WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace()); 1359 1360 return false; 1361 } 1362 1363 static Optional<unsigned> IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG) { 1364 const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op); 1365 if (!FI) 1366 return None; 1367 1368 auto &MF = DAG.getMachineFunction(); 1369 return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex()); 1370 } 1371 1372 bool WebAssemblyTargetLowering::isFuncrefType(const Type *Ty) { 1373 return isa<PointerType>(Ty) && 1374 Ty->getPointerAddressSpace() == WasmAddressSpace::FUNCREF; 1375 } 1376 1377 bool WebAssemblyTargetLowering::isExternrefType(const Type *Ty) { 1378 return isa<PointerType>(Ty) && 1379 Ty->getPointerAddressSpace() == WasmAddressSpace::EXTERNREF; 1380 } 1381 1382 SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, 1383 SelectionDAG &DAG) const { 1384 SDLoc DL(Op); 1385 StoreSDNode *SN = cast<StoreSDNode>(Op.getNode()); 1386 const SDValue &Value = SN->getValue(); 1387 const SDValue &Base = SN->getBasePtr(); 1388 const SDValue &Offset = SN->getOffset(); 1389 1390 if (IsWebAssemblyGlobal(Base)) { 1391 if (!Offset->isUndef()) 1392 report_fatal_error("unexpected offset when storing to webassembly global", 1393 false); 1394 1395 SDVTList Tys = DAG.getVTList(MVT::Other); 1396 SDValue Ops[] = {SN->getChain(), Value, Base}; 1397 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops, 1398 SN->getMemoryVT(), SN->getMemOperand()); 1399 } 1400 1401 if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { 1402 if (!Offset->isUndef()) 1403 report_fatal_error("unexpected offset when storing to webassembly local", 1404 false); 1405 1406 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); 1407 SDVTList Tys = DAG.getVTList(MVT::Other); // The chain. 1408 SDValue Ops[] = {SN->getChain(), Idx, Value}; 1409 return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops); 1410 } 1411 1412 return Op; 1413 } 1414 1415 SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op, 1416 SelectionDAG &DAG) const { 1417 SDLoc DL(Op); 1418 LoadSDNode *LN = cast<LoadSDNode>(Op.getNode()); 1419 const SDValue &Base = LN->getBasePtr(); 1420 const SDValue &Offset = LN->getOffset(); 1421 1422 if (IsWebAssemblyGlobal(Base)) { 1423 if (!Offset->isUndef()) 1424 report_fatal_error( 1425 "unexpected offset when loading from webassembly global", false); 1426 1427 SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); 1428 SDValue Ops[] = {LN->getChain(), Base}; 1429 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops, 1430 LN->getMemoryVT(), LN->getMemOperand()); 1431 } 1432 1433 if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { 1434 if (!Offset->isUndef()) 1435 report_fatal_error( 1436 "unexpected offset when loading from webassembly local", false); 1437 1438 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); 1439 EVT LocalVT = LN->getValueType(0); 1440 SDValue LocalGet = DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, LocalVT, 1441 {LN->getChain(), Idx}); 1442 SDValue Result = DAG.getMergeValues({LocalGet, LN->getChain()}, DL); 1443 assert(Result->getNumValues() == 2 && "Loads must carry a chain!"); 1444 return Result; 1445 } 1446 1447 return Op; 1448 } 1449 1450 SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op, 1451 SelectionDAG &DAG) const { 1452 SDValue Src = Op.getOperand(2); 1453 if (isa<FrameIndexSDNode>(Src.getNode())) { 1454 // CopyToReg nodes don't support FrameIndex operands. Other targets select 1455 // the FI to some LEA-like instruction, but since we don't have that, we 1456 // need to insert some kind of instruction that can take an FI operand and 1457 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy 1458 // local.copy between Op and its FI operand. 1459 SDValue Chain = Op.getOperand(0); 1460 SDLoc DL(Op); 1461 unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg(); 1462 EVT VT = Src.getValueType(); 1463 SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32 1464 : WebAssembly::COPY_I64, 1465 DL, VT, Src), 1466 0); 1467 return Op.getNode()->getNumValues() == 1 1468 ? DAG.getCopyToReg(Chain, DL, Reg, Copy) 1469 : DAG.getCopyToReg(Chain, DL, Reg, Copy, 1470 Op.getNumOperands() == 4 ? Op.getOperand(3) 1471 : SDValue()); 1472 } 1473 return SDValue(); 1474 } 1475 1476 SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, 1477 SelectionDAG &DAG) const { 1478 int FI = cast<FrameIndexSDNode>(Op)->getIndex(); 1479 return DAG.getTargetFrameIndex(FI, Op.getValueType()); 1480 } 1481 1482 SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op, 1483 SelectionDAG &DAG) const { 1484 SDLoc DL(Op); 1485 1486 if (!Subtarget->getTargetTriple().isOSEmscripten()) { 1487 fail(DL, DAG, 1488 "Non-Emscripten WebAssembly hasn't implemented " 1489 "__builtin_return_address"); 1490 return SDValue(); 1491 } 1492 1493 if (verifyReturnAddressArgumentIsConstant(Op, DAG)) 1494 return SDValue(); 1495 1496 unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 1497 MakeLibCallOptions CallOptions; 1498 return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(), 1499 {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL) 1500 .first; 1501 } 1502 1503 SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op, 1504 SelectionDAG &DAG) const { 1505 // Non-zero depths are not supported by WebAssembly currently. Use the 1506 // legalizer's default expansion, which is to return 0 (what this function is 1507 // documented to do). 1508 if (Op.getConstantOperandVal(0) > 0) 1509 return SDValue(); 1510 1511 DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true); 1512 EVT VT = Op.getValueType(); 1513 Register FP = 1514 Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); 1515 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT); 1516 } 1517 1518 SDValue 1519 WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, 1520 SelectionDAG &DAG) const { 1521 SDLoc DL(Op); 1522 const auto *GA = cast<GlobalAddressSDNode>(Op); 1523 MVT PtrVT = getPointerTy(DAG.getDataLayout()); 1524 1525 MachineFunction &MF = DAG.getMachineFunction(); 1526 if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory()) 1527 report_fatal_error("cannot use thread-local storage without bulk memory", 1528 false); 1529 1530 const GlobalValue *GV = GA->getGlobal(); 1531 1532 // Currently Emscripten does not support dynamic linking with threads. 1533 // Therefore, if we have thread-local storage, only the local-exec model 1534 // is possible. 1535 // TODO: remove this and implement proper TLS models once Emscripten 1536 // supports dynamic linking with threads. 1537 if (GV->getThreadLocalMode() != GlobalValue::LocalExecTLSModel && 1538 !Subtarget->getTargetTriple().isOSEmscripten()) { 1539 report_fatal_error("only -ftls-model=local-exec is supported for now on " 1540 "non-Emscripten OSes: variable " + 1541 GV->getName(), 1542 false); 1543 } 1544 1545 auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 1546 : WebAssembly::GLOBAL_GET_I32; 1547 const char *BaseName = MF.createExternalSymbolName("__tls_base"); 1548 1549 SDValue BaseAddr( 1550 DAG.getMachineNode(GlobalGet, DL, PtrVT, 1551 DAG.getTargetExternalSymbol(BaseName, PtrVT)), 1552 0); 1553 1554 SDValue TLSOffset = DAG.getTargetGlobalAddress( 1555 GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL); 1556 SDValue SymAddr = DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, TLSOffset); 1557 1558 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr); 1559 } 1560 1561 SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, 1562 SelectionDAG &DAG) const { 1563 SDLoc DL(Op); 1564 const auto *GA = cast<GlobalAddressSDNode>(Op); 1565 EVT VT = Op.getValueType(); 1566 assert(GA->getTargetFlags() == 0 && 1567 "Unexpected target flags on generic GlobalAddressSDNode"); 1568 if (!WebAssembly::isValidAddressSpace(GA->getAddressSpace())) 1569 fail(DL, DAG, "Invalid address space for WebAssembly target"); 1570 1571 unsigned OperandFlags = 0; 1572 if (isPositionIndependent()) { 1573 const GlobalValue *GV = GA->getGlobal(); 1574 if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) { 1575 MachineFunction &MF = DAG.getMachineFunction(); 1576 MVT PtrVT = getPointerTy(MF.getDataLayout()); 1577 const char *BaseName; 1578 if (GV->getValueType()->isFunctionTy()) { 1579 BaseName = MF.createExternalSymbolName("__table_base"); 1580 OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL; 1581 } 1582 else { 1583 BaseName = MF.createExternalSymbolName("__memory_base"); 1584 OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL; 1585 } 1586 SDValue BaseAddr = 1587 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, 1588 DAG.getTargetExternalSymbol(BaseName, PtrVT)); 1589 1590 SDValue SymAddr = DAG.getNode( 1591 WebAssemblyISD::WrapperPIC, DL, VT, 1592 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(), 1593 OperandFlags)); 1594 1595 return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr); 1596 } else { 1597 OperandFlags = WebAssemblyII::MO_GOT; 1598 } 1599 } 1600 1601 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 1602 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, 1603 GA->getOffset(), OperandFlags)); 1604 } 1605 1606 SDValue 1607 WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op, 1608 SelectionDAG &DAG) const { 1609 SDLoc DL(Op); 1610 const auto *ES = cast<ExternalSymbolSDNode>(Op); 1611 EVT VT = Op.getValueType(); 1612 assert(ES->getTargetFlags() == 0 && 1613 "Unexpected target flags on generic ExternalSymbolSDNode"); 1614 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 1615 DAG.getTargetExternalSymbol(ES->getSymbol(), VT)); 1616 } 1617 1618 SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op, 1619 SelectionDAG &DAG) const { 1620 // There's no need for a Wrapper node because we always incorporate a jump 1621 // table operand into a BR_TABLE instruction, rather than ever 1622 // materializing it in a register. 1623 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); 1624 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(), 1625 JT->getTargetFlags()); 1626 } 1627 1628 SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, 1629 SelectionDAG &DAG) const { 1630 SDLoc DL(Op); 1631 SDValue Chain = Op.getOperand(0); 1632 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1)); 1633 SDValue Index = Op.getOperand(2); 1634 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags"); 1635 1636 SmallVector<SDValue, 8> Ops; 1637 Ops.push_back(Chain); 1638 Ops.push_back(Index); 1639 1640 MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo(); 1641 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; 1642 1643 // Add an operand for each case. 1644 for (auto MBB : MBBs) 1645 Ops.push_back(DAG.getBasicBlock(MBB)); 1646 1647 // Add the first MBB as a dummy default target for now. This will be replaced 1648 // with the proper default target (and the preceding range check eliminated) 1649 // if possible by WebAssemblyFixBrTableDefaults. 1650 Ops.push_back(DAG.getBasicBlock(*MBBs.begin())); 1651 return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops); 1652 } 1653 1654 SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, 1655 SelectionDAG &DAG) const { 1656 SDLoc DL(Op); 1657 EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); 1658 1659 auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>(); 1660 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 1661 1662 SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL, 1663 MFI->getVarargBufferVreg(), PtrVT); 1664 return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1), 1665 MachinePointerInfo(SV)); 1666 } 1667 1668 static SDValue getCppExceptionSymNode(SDValue Op, unsigned TagIndex, 1669 SelectionDAG &DAG) { 1670 // We only support C++ exceptions for now 1671 int Tag = 1672 cast<ConstantSDNode>(Op.getOperand(TagIndex).getNode())->getZExtValue(); 1673 if (Tag != WebAssembly::CPP_EXCEPTION) 1674 llvm_unreachable("Invalid tag: We only support C++ exceptions for now"); 1675 auto &MF = DAG.getMachineFunction(); 1676 const auto &TLI = DAG.getTargetLoweringInfo(); 1677 MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); 1678 const char *SymName = MF.createExternalSymbolName("__cpp_exception"); 1679 return DAG.getNode(WebAssemblyISD::Wrapper, SDLoc(Op), PtrVT, 1680 DAG.getTargetExternalSymbol(SymName, PtrVT)); 1681 } 1682 1683 SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, 1684 SelectionDAG &DAG) const { 1685 MachineFunction &MF = DAG.getMachineFunction(); 1686 unsigned IntNo; 1687 switch (Op.getOpcode()) { 1688 case ISD::INTRINSIC_VOID: 1689 case ISD::INTRINSIC_W_CHAIN: 1690 IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); 1691 break; 1692 case ISD::INTRINSIC_WO_CHAIN: 1693 IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 1694 break; 1695 default: 1696 llvm_unreachable("Invalid intrinsic"); 1697 } 1698 SDLoc DL(Op); 1699 1700 switch (IntNo) { 1701 default: 1702 return SDValue(); // Don't custom lower most intrinsics. 1703 1704 case Intrinsic::wasm_lsda: { 1705 EVT VT = Op.getValueType(); 1706 const TargetLowering &TLI = DAG.getTargetLoweringInfo(); 1707 MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); 1708 auto &Context = MF.getMMI().getContext(); 1709 MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") + 1710 Twine(MF.getFunctionNumber())); 1711 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 1712 DAG.getMCSymbol(S, PtrVT)); 1713 } 1714 1715 case Intrinsic::wasm_throw: { 1716 SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); 1717 return DAG.getNode(WebAssemblyISD::THROW, DL, 1718 MVT::Other, // outchain type 1719 { 1720 Op.getOperand(0), // inchain 1721 SymNode, // exception symbol 1722 Op.getOperand(3) // thrown value 1723 }); 1724 } 1725 1726 case Intrinsic::wasm_catch: { 1727 SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); 1728 return DAG.getNode(WebAssemblyISD::CATCH, DL, 1729 { 1730 MVT::i32, // outchain type 1731 MVT::Other // return value 1732 }, 1733 { 1734 Op.getOperand(0), // inchain 1735 SymNode // exception symbol 1736 }); 1737 } 1738 1739 case Intrinsic::wasm_shuffle: { 1740 // Drop in-chain and replace undefs, but otherwise pass through unchanged 1741 SDValue Ops[18]; 1742 size_t OpIdx = 0; 1743 Ops[OpIdx++] = Op.getOperand(1); 1744 Ops[OpIdx++] = Op.getOperand(2); 1745 while (OpIdx < 18) { 1746 const SDValue &MaskIdx = Op.getOperand(OpIdx + 1); 1747 if (MaskIdx.isUndef() || 1748 cast<ConstantSDNode>(MaskIdx.getNode())->getZExtValue() >= 32) { 1749 Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32); 1750 } else { 1751 Ops[OpIdx++] = MaskIdx; 1752 } 1753 } 1754 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); 1755 } 1756 } 1757 } 1758 1759 SDValue 1760 WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op, 1761 SelectionDAG &DAG) const { 1762 SDLoc DL(Op); 1763 // If sign extension operations are disabled, allow sext_inreg only if operand 1764 // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign 1765 // extension operations, but allowing sext_inreg in this context lets us have 1766 // simple patterns to select extract_lane_s instructions. Expanding sext_inreg 1767 // everywhere would be simpler in this file, but would necessitate large and 1768 // brittle patterns to undo the expansion and select extract_lane_s 1769 // instructions. 1770 assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128()); 1771 if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT) 1772 return SDValue(); 1773 1774 const SDValue &Extract = Op.getOperand(0); 1775 MVT VecT = Extract.getOperand(0).getSimpleValueType(); 1776 if (VecT.getVectorElementType().getSizeInBits() > 32) 1777 return SDValue(); 1778 MVT ExtractedLaneT = 1779 cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT(); 1780 MVT ExtractedVecT = 1781 MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits()); 1782 if (ExtractedVecT == VecT) 1783 return Op; 1784 1785 // Bitcast vector to appropriate type to ensure ISel pattern coverage 1786 const SDNode *Index = Extract.getOperand(1).getNode(); 1787 if (!isa<ConstantSDNode>(Index)) 1788 return SDValue(); 1789 unsigned IndexVal = cast<ConstantSDNode>(Index)->getZExtValue(); 1790 unsigned Scale = 1791 ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements(); 1792 assert(Scale > 1); 1793 SDValue NewIndex = 1794 DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0)); 1795 SDValue NewExtract = DAG.getNode( 1796 ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(), 1797 DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex); 1798 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract, 1799 Op.getOperand(1)); 1800 } 1801 1802 SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op, 1803 SelectionDAG &DAG) const { 1804 SDLoc DL(Op); 1805 const EVT VecT = Op.getValueType(); 1806 const EVT LaneT = Op.getOperand(0).getValueType(); 1807 const size_t Lanes = Op.getNumOperands(); 1808 bool CanSwizzle = VecT == MVT::v16i8; 1809 1810 // BUILD_VECTORs are lowered to the instruction that initializes the highest 1811 // possible number of lanes at once followed by a sequence of replace_lane 1812 // instructions to individually initialize any remaining lanes. 1813 1814 // TODO: Tune this. For example, lanewise swizzling is very expensive, so 1815 // swizzled lanes should be given greater weight. 1816 1817 // TODO: Investigate looping rather than always extracting/replacing specific 1818 // lanes to fill gaps. 1819 1820 auto IsConstant = [](const SDValue &V) { 1821 return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP; 1822 }; 1823 1824 // Returns the source vector and index vector pair if they exist. Checks for: 1825 // (extract_vector_elt 1826 // $src, 1827 // (sign_extend_inreg (extract_vector_elt $indices, $i)) 1828 // ) 1829 auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) { 1830 auto Bail = std::make_pair(SDValue(), SDValue()); 1831 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 1832 return Bail; 1833 const SDValue &SwizzleSrc = Lane->getOperand(0); 1834 const SDValue &IndexExt = Lane->getOperand(1); 1835 if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG) 1836 return Bail; 1837 const SDValue &Index = IndexExt->getOperand(0); 1838 if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 1839 return Bail; 1840 const SDValue &SwizzleIndices = Index->getOperand(0); 1841 if (SwizzleSrc.getValueType() != MVT::v16i8 || 1842 SwizzleIndices.getValueType() != MVT::v16i8 || 1843 Index->getOperand(1)->getOpcode() != ISD::Constant || 1844 Index->getConstantOperandVal(1) != I) 1845 return Bail; 1846 return std::make_pair(SwizzleSrc, SwizzleIndices); 1847 }; 1848 1849 // If the lane is extracted from another vector at a constant index, return 1850 // that vector. The source vector must not have more lanes than the dest 1851 // because the shufflevector indices are in terms of the destination lanes and 1852 // would not be able to address the smaller individual source lanes. 1853 auto GetShuffleSrc = [&](const SDValue &Lane) { 1854 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) 1855 return SDValue(); 1856 if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode())) 1857 return SDValue(); 1858 if (Lane->getOperand(0).getValueType().getVectorNumElements() > 1859 VecT.getVectorNumElements()) 1860 return SDValue(); 1861 return Lane->getOperand(0); 1862 }; 1863 1864 using ValueEntry = std::pair<SDValue, size_t>; 1865 SmallVector<ValueEntry, 16> SplatValueCounts; 1866 1867 using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>; 1868 SmallVector<SwizzleEntry, 16> SwizzleCounts; 1869 1870 using ShuffleEntry = std::pair<SDValue, size_t>; 1871 SmallVector<ShuffleEntry, 16> ShuffleCounts; 1872 1873 auto AddCount = [](auto &Counts, const auto &Val) { 1874 auto CountIt = 1875 llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; }); 1876 if (CountIt == Counts.end()) { 1877 Counts.emplace_back(Val, 1); 1878 } else { 1879 CountIt->second++; 1880 } 1881 }; 1882 1883 auto GetMostCommon = [](auto &Counts) { 1884 auto CommonIt = 1885 std::max_element(Counts.begin(), Counts.end(), 1886 [](auto A, auto B) { return A.second < B.second; }); 1887 assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector"); 1888 return *CommonIt; 1889 }; 1890 1891 size_t NumConstantLanes = 0; 1892 1893 // Count eligible lanes for each type of vector creation op 1894 for (size_t I = 0; I < Lanes; ++I) { 1895 const SDValue &Lane = Op->getOperand(I); 1896 if (Lane.isUndef()) 1897 continue; 1898 1899 AddCount(SplatValueCounts, Lane); 1900 1901 if (IsConstant(Lane)) 1902 NumConstantLanes++; 1903 if (auto ShuffleSrc = GetShuffleSrc(Lane)) 1904 AddCount(ShuffleCounts, ShuffleSrc); 1905 if (CanSwizzle) { 1906 auto SwizzleSrcs = GetSwizzleSrcs(I, Lane); 1907 if (SwizzleSrcs.first) 1908 AddCount(SwizzleCounts, SwizzleSrcs); 1909 } 1910 } 1911 1912 SDValue SplatValue; 1913 size_t NumSplatLanes; 1914 std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts); 1915 1916 SDValue SwizzleSrc; 1917 SDValue SwizzleIndices; 1918 size_t NumSwizzleLanes = 0; 1919 if (SwizzleCounts.size()) 1920 std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices), 1921 NumSwizzleLanes) = GetMostCommon(SwizzleCounts); 1922 1923 // Shuffles can draw from up to two vectors, so find the two most common 1924 // sources. 1925 SDValue ShuffleSrc1, ShuffleSrc2; 1926 size_t NumShuffleLanes = 0; 1927 if (ShuffleCounts.size()) { 1928 std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts); 1929 ShuffleCounts.erase(std::remove_if(ShuffleCounts.begin(), 1930 ShuffleCounts.end(), 1931 [&](const auto &Pair) { 1932 return Pair.first == ShuffleSrc1; 1933 }), 1934 ShuffleCounts.end()); 1935 } 1936 if (ShuffleCounts.size()) { 1937 size_t AdditionalShuffleLanes; 1938 std::tie(ShuffleSrc2, AdditionalShuffleLanes) = 1939 GetMostCommon(ShuffleCounts); 1940 NumShuffleLanes += AdditionalShuffleLanes; 1941 } 1942 1943 // Predicate returning true if the lane is properly initialized by the 1944 // original instruction 1945 std::function<bool(size_t, const SDValue &)> IsLaneConstructed; 1946 SDValue Result; 1947 // Prefer swizzles over shuffles over vector consts over splats 1948 if (NumSwizzleLanes >= NumShuffleLanes && 1949 NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) { 1950 Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc, 1951 SwizzleIndices); 1952 auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices); 1953 IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) { 1954 return Swizzled == GetSwizzleSrcs(I, Lane); 1955 }; 1956 } else if (NumShuffleLanes >= NumConstantLanes && 1957 NumShuffleLanes >= NumSplatLanes) { 1958 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8; 1959 size_t DestLaneCount = VecT.getVectorNumElements(); 1960 size_t Scale1 = 1; 1961 size_t Scale2 = 1; 1962 SDValue Src1 = ShuffleSrc1; 1963 SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT); 1964 if (Src1.getValueType() != VecT) { 1965 size_t LaneSize = 1966 Src1.getValueType().getVectorElementType().getFixedSizeInBits() / 8; 1967 assert(LaneSize > DestLaneSize); 1968 Scale1 = LaneSize / DestLaneSize; 1969 Src1 = DAG.getBitcast(VecT, Src1); 1970 } 1971 if (Src2.getValueType() != VecT) { 1972 size_t LaneSize = 1973 Src2.getValueType().getVectorElementType().getFixedSizeInBits() / 8; 1974 assert(LaneSize > DestLaneSize); 1975 Scale2 = LaneSize / DestLaneSize; 1976 Src2 = DAG.getBitcast(VecT, Src2); 1977 } 1978 1979 int Mask[16]; 1980 assert(DestLaneCount <= 16); 1981 for (size_t I = 0; I < DestLaneCount; ++I) { 1982 const SDValue &Lane = Op->getOperand(I); 1983 SDValue Src = GetShuffleSrc(Lane); 1984 if (Src == ShuffleSrc1) { 1985 Mask[I] = Lane->getConstantOperandVal(1) * Scale1; 1986 } else if (Src && Src == ShuffleSrc2) { 1987 Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2; 1988 } else { 1989 Mask[I] = -1; 1990 } 1991 } 1992 ArrayRef<int> MaskRef(Mask, DestLaneCount); 1993 Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef); 1994 IsLaneConstructed = [&](size_t, const SDValue &Lane) { 1995 auto Src = GetShuffleSrc(Lane); 1996 return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2); 1997 }; 1998 } else if (NumConstantLanes >= NumSplatLanes) { 1999 SmallVector<SDValue, 16> ConstLanes; 2000 for (const SDValue &Lane : Op->op_values()) { 2001 if (IsConstant(Lane)) { 2002 ConstLanes.push_back(Lane); 2003 } else if (LaneT.isFloatingPoint()) { 2004 ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT)); 2005 } else { 2006 ConstLanes.push_back(DAG.getConstant(0, DL, LaneT)); 2007 } 2008 } 2009 Result = DAG.getBuildVector(VecT, DL, ConstLanes); 2010 IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) { 2011 return IsConstant(Lane); 2012 }; 2013 } else { 2014 // Use a splat, but possibly a load_splat 2015 LoadSDNode *SplattedLoad; 2016 if ((SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) && 2017 SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) { 2018 Result = DAG.getMemIntrinsicNode( 2019 WebAssemblyISD::LOAD_SPLAT, DL, DAG.getVTList(VecT), 2020 {SplattedLoad->getChain(), SplattedLoad->getBasePtr(), 2021 SplattedLoad->getOffset()}, 2022 SplattedLoad->getMemoryVT(), SplattedLoad->getMemOperand()); 2023 } else { 2024 Result = DAG.getSplatBuildVector(VecT, DL, SplatValue); 2025 } 2026 IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) { 2027 return Lane == SplatValue; 2028 }; 2029 } 2030 2031 assert(Result); 2032 assert(IsLaneConstructed); 2033 2034 // Add replace_lane instructions for any unhandled values 2035 for (size_t I = 0; I < Lanes; ++I) { 2036 const SDValue &Lane = Op->getOperand(I); 2037 if (!Lane.isUndef() && !IsLaneConstructed(I, Lane)) 2038 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane, 2039 DAG.getConstant(I, DL, MVT::i32)); 2040 } 2041 2042 return Result; 2043 } 2044 2045 SDValue 2046 WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, 2047 SelectionDAG &DAG) const { 2048 SDLoc DL(Op); 2049 ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask(); 2050 MVT VecType = Op.getOperand(0).getSimpleValueType(); 2051 assert(VecType.is128BitVector() && "Unexpected shuffle vector type"); 2052 size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8; 2053 2054 // Space for two vector args and sixteen mask indices 2055 SDValue Ops[18]; 2056 size_t OpIdx = 0; 2057 Ops[OpIdx++] = Op.getOperand(0); 2058 Ops[OpIdx++] = Op.getOperand(1); 2059 2060 // Expand mask indices to byte indices and materialize them as operands 2061 for (int M : Mask) { 2062 for (size_t J = 0; J < LaneBytes; ++J) { 2063 // Lower undefs (represented by -1 in mask) to zero 2064 uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J; 2065 Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32); 2066 } 2067 } 2068 2069 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); 2070 } 2071 2072 SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op, 2073 SelectionDAG &DAG) const { 2074 SDLoc DL(Op); 2075 // The legalizer does not know how to expand the unsupported comparison modes 2076 // of i64x2 vectors, so we manually unroll them here. 2077 assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64); 2078 SmallVector<SDValue, 2> LHS, RHS; 2079 DAG.ExtractVectorElements(Op->getOperand(0), LHS); 2080 DAG.ExtractVectorElements(Op->getOperand(1), RHS); 2081 const SDValue &CC = Op->getOperand(2); 2082 auto MakeLane = [&](unsigned I) { 2083 return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I], 2084 DAG.getConstant(uint64_t(-1), DL, MVT::i64), 2085 DAG.getConstant(uint64_t(0), DL, MVT::i64), CC); 2086 }; 2087 return DAG.getBuildVector(Op->getValueType(0), DL, 2088 {MakeLane(0), MakeLane(1)}); 2089 } 2090 2091 SDValue 2092 WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op, 2093 SelectionDAG &DAG) const { 2094 // Allow constant lane indices, expand variable lane indices 2095 SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode(); 2096 if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef()) 2097 return Op; 2098 else 2099 // Perform default expansion 2100 return SDValue(); 2101 } 2102 2103 static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) { 2104 EVT LaneT = Op.getSimpleValueType().getVectorElementType(); 2105 // 32-bit and 64-bit unrolled shifts will have proper semantics 2106 if (LaneT.bitsGE(MVT::i32)) 2107 return DAG.UnrollVectorOp(Op.getNode()); 2108 // Otherwise mask the shift value to get proper semantics from 32-bit shift 2109 SDLoc DL(Op); 2110 size_t NumLanes = Op.getSimpleValueType().getVectorNumElements(); 2111 SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32); 2112 unsigned ShiftOpcode = Op.getOpcode(); 2113 SmallVector<SDValue, 16> ShiftedElements; 2114 DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32); 2115 SmallVector<SDValue, 16> ShiftElements; 2116 DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32); 2117 SmallVector<SDValue, 16> UnrolledOps; 2118 for (size_t i = 0; i < NumLanes; ++i) { 2119 SDValue MaskedShiftValue = 2120 DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask); 2121 SDValue ShiftedValue = ShiftedElements[i]; 2122 if (ShiftOpcode == ISD::SRA) 2123 ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32, 2124 ShiftedValue, DAG.getValueType(LaneT)); 2125 UnrolledOps.push_back( 2126 DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue)); 2127 } 2128 return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps); 2129 } 2130 2131 SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, 2132 SelectionDAG &DAG) const { 2133 SDLoc DL(Op); 2134 2135 // Only manually lower vector shifts 2136 assert(Op.getSimpleValueType().isVector()); 2137 2138 auto ShiftVal = DAG.getSplatValue(Op.getOperand(1)); 2139 if (!ShiftVal) 2140 return unrollVectorShift(Op, DAG); 2141 2142 // Use anyext because none of the high bits can affect the shift 2143 ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32); 2144 2145 unsigned Opcode; 2146 switch (Op.getOpcode()) { 2147 case ISD::SHL: 2148 Opcode = WebAssemblyISD::VEC_SHL; 2149 break; 2150 case ISD::SRA: 2151 Opcode = WebAssemblyISD::VEC_SHR_S; 2152 break; 2153 case ISD::SRL: 2154 Opcode = WebAssemblyISD::VEC_SHR_U; 2155 break; 2156 default: 2157 llvm_unreachable("unexpected opcode"); 2158 } 2159 2160 return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal); 2161 } 2162 2163 SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op, 2164 SelectionDAG &DAG) const { 2165 SDLoc DL(Op); 2166 EVT ResT = Op.getValueType(); 2167 EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT(); 2168 2169 if ((ResT == MVT::i32 || ResT == MVT::i64) && 2170 (SatVT == MVT::i32 || SatVT == MVT::i64)) 2171 return Op; 2172 2173 if (ResT == MVT::v4i32 && SatVT == MVT::i32) 2174 return Op; 2175 2176 return SDValue(); 2177 } 2178 2179 //===----------------------------------------------------------------------===// 2180 // Custom DAG combine hooks 2181 //===----------------------------------------------------------------------===// 2182 static SDValue 2183 performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { 2184 auto &DAG = DCI.DAG; 2185 auto Shuffle = cast<ShuffleVectorSDNode>(N); 2186 2187 // Hoist vector bitcasts that don't change the number of lanes out of unary 2188 // shuffles, where they are less likely to get in the way of other combines. 2189 // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) -> 2190 // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask)))) 2191 SDValue Bitcast = N->getOperand(0); 2192 if (Bitcast.getOpcode() != ISD::BITCAST) 2193 return SDValue(); 2194 if (!N->getOperand(1).isUndef()) 2195 return SDValue(); 2196 SDValue CastOp = Bitcast.getOperand(0); 2197 MVT SrcType = CastOp.getSimpleValueType(); 2198 MVT DstType = Bitcast.getSimpleValueType(); 2199 if (!SrcType.is128BitVector() || 2200 SrcType.getVectorNumElements() != DstType.getVectorNumElements()) 2201 return SDValue(); 2202 SDValue NewShuffle = DAG.getVectorShuffle( 2203 SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask()); 2204 return DAG.getBitcast(DstType, NewShuffle); 2205 } 2206 2207 static SDValue 2208 performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { 2209 auto &DAG = DCI.DAG; 2210 assert(N->getOpcode() == ISD::SIGN_EXTEND || 2211 N->getOpcode() == ISD::ZERO_EXTEND); 2212 2213 // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if 2214 // possible before the extract_subvector can be expanded. 2215 auto Extract = N->getOperand(0); 2216 if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) 2217 return SDValue(); 2218 auto Source = Extract.getOperand(0); 2219 auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1)); 2220 if (IndexNode == nullptr) 2221 return SDValue(); 2222 auto Index = IndexNode->getZExtValue(); 2223 2224 // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the 2225 // extracted subvector is the low or high half of its source. 2226 EVT ResVT = N->getValueType(0); 2227 if (ResVT == MVT::v8i16) { 2228 if (Extract.getValueType() != MVT::v8i8 || 2229 Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8)) 2230 return SDValue(); 2231 } else if (ResVT == MVT::v4i32) { 2232 if (Extract.getValueType() != MVT::v4i16 || 2233 Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4)) 2234 return SDValue(); 2235 } else if (ResVT == MVT::v2i64) { 2236 if (Extract.getValueType() != MVT::v2i32 || 2237 Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2)) 2238 return SDValue(); 2239 } else { 2240 return SDValue(); 2241 } 2242 2243 bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND; 2244 bool IsLow = Index == 0; 2245 2246 unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S 2247 : WebAssemblyISD::EXTEND_HIGH_S) 2248 : (IsLow ? WebAssemblyISD::EXTEND_LOW_U 2249 : WebAssemblyISD::EXTEND_HIGH_U); 2250 2251 return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2252 } 2253 2254 static SDValue 2255 performVectorConvertLowCombine(SDNode *N, 2256 TargetLowering::DAGCombinerInfo &DCI) { 2257 auto &DAG = DCI.DAG; 2258 2259 EVT ResVT = N->getValueType(0); 2260 if (ResVT != MVT::v2f64) 2261 return SDValue(); 2262 2263 auto GetWasmConversionOp = [](unsigned Op) { 2264 switch (Op) { 2265 case ISD::SINT_TO_FP: 2266 return WebAssemblyISD::CONVERT_LOW_S; 2267 case ISD::UINT_TO_FP: 2268 return WebAssemblyISD::CONVERT_LOW_U; 2269 case ISD::FP_EXTEND: 2270 return WebAssemblyISD::PROMOTE_LOW; 2271 } 2272 llvm_unreachable("unexpected op"); 2273 }; 2274 2275 if (N->getOpcode() == ISD::EXTRACT_SUBVECTOR) { 2276 // Combine this: 2277 // 2278 // (v2f64 (extract_subvector 2279 // (v4f64 ({s,u}int_to_fp (v4i32 $x))), 0)) 2280 // 2281 // into (f64x2.convert_low_i32x4_{s,u} $x). 2282 // 2283 // Or this: 2284 // 2285 // (v2f64 (extract_subvector 2286 // (v4f64 (fp_extend (v4f32 $x))), 0)) 2287 // 2288 // into (f64x2.promote_low_f32x4 $x). 2289 auto Conversion = N->getOperand(0); 2290 auto ConversionOp = Conversion.getOpcode(); 2291 MVT ExpectedSourceType; 2292 switch (ConversionOp) { 2293 case ISD::SINT_TO_FP: 2294 case ISD::UINT_TO_FP: 2295 ExpectedSourceType = MVT::v4i32; 2296 break; 2297 case ISD::FP_EXTEND: 2298 ExpectedSourceType = MVT::v4f32; 2299 break; 2300 default: 2301 return SDValue(); 2302 } 2303 2304 if (Conversion.getValueType() != MVT::v4f64) 2305 return SDValue(); 2306 2307 auto Source = Conversion.getOperand(0); 2308 if (Source.getValueType() != ExpectedSourceType) 2309 return SDValue(); 2310 2311 auto IndexNode = dyn_cast<ConstantSDNode>(N->getOperand(1)); 2312 if (IndexNode == nullptr || IndexNode->getZExtValue() != 0) 2313 return SDValue(); 2314 2315 auto Op = GetWasmConversionOp(ConversionOp); 2316 return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2317 } 2318 2319 // Combine this: 2320 // 2321 // (v2f64 ({s,u}int_to_fp 2322 // (v2i32 (extract_subvector (v4i32 $x), 0)))) 2323 // 2324 // into (f64x2.convert_low_i32x4_{s,u} $x). 2325 // 2326 // Or this: 2327 // 2328 // (v2f64 (fp_extend 2329 // (v2f32 (extract_subvector (v4f32 $x), 0)))) 2330 // 2331 // into (f64x2.promote_low_f32x4 $x). 2332 auto ConversionOp = N->getOpcode(); 2333 MVT ExpectedExtractType; 2334 MVT ExpectedSourceType; 2335 switch (ConversionOp) { 2336 case ISD::SINT_TO_FP: 2337 case ISD::UINT_TO_FP: 2338 ExpectedExtractType = MVT::v2i32; 2339 ExpectedSourceType = MVT::v4i32; 2340 break; 2341 case ISD::FP_EXTEND: 2342 ExpectedExtractType = MVT::v2f32; 2343 ExpectedSourceType = MVT::v4f32; 2344 break; 2345 default: 2346 llvm_unreachable("unexpected opcode"); 2347 } 2348 2349 auto Extract = N->getOperand(0); 2350 if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) 2351 return SDValue(); 2352 2353 if (Extract.getValueType() != ExpectedExtractType) 2354 return SDValue(); 2355 2356 auto Source = Extract.getOperand(0); 2357 if (Source.getValueType() != ExpectedSourceType) 2358 return SDValue(); 2359 2360 auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1)); 2361 if (IndexNode == nullptr || IndexNode->getZExtValue() != 0) 2362 return SDValue(); 2363 2364 unsigned Op = GetWasmConversionOp(ConversionOp); 2365 return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2366 } 2367 2368 static SDValue 2369 performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { 2370 auto &DAG = DCI.DAG; 2371 2372 auto GetWasmConversionOp = [](unsigned Op) { 2373 switch (Op) { 2374 case ISD::FP_TO_SINT_SAT: 2375 return WebAssemblyISD::TRUNC_SAT_ZERO_S; 2376 case ISD::FP_TO_UINT_SAT: 2377 return WebAssemblyISD::TRUNC_SAT_ZERO_U; 2378 case ISD::FP_ROUND: 2379 return WebAssemblyISD::DEMOTE_ZERO; 2380 } 2381 llvm_unreachable("unexpected op"); 2382 }; 2383 2384 auto IsZeroSplat = [](SDValue SplatVal) { 2385 auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode()); 2386 APInt SplatValue, SplatUndef; 2387 unsigned SplatBitSize; 2388 bool HasAnyUndefs; 2389 return Splat && 2390 Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, 2391 HasAnyUndefs) && 2392 SplatValue == 0; 2393 }; 2394 2395 if (N->getOpcode() == ISD::CONCAT_VECTORS) { 2396 // Combine this: 2397 // 2398 // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0))) 2399 // 2400 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). 2401 // 2402 // Or this: 2403 // 2404 // (concat_vectors (v2f32 (fp_round (v2f64 $x))), (v2f32 (splat 0))) 2405 // 2406 // into (f32x4.demote_zero_f64x2 $x). 2407 EVT ResVT; 2408 EVT ExpectedConversionType; 2409 auto Conversion = N->getOperand(0); 2410 auto ConversionOp = Conversion.getOpcode(); 2411 switch (ConversionOp) { 2412 case ISD::FP_TO_SINT_SAT: 2413 case ISD::FP_TO_UINT_SAT: 2414 ResVT = MVT::v4i32; 2415 ExpectedConversionType = MVT::v2i32; 2416 break; 2417 case ISD::FP_ROUND: 2418 ResVT = MVT::v4f32; 2419 ExpectedConversionType = MVT::v2f32; 2420 break; 2421 default: 2422 return SDValue(); 2423 } 2424 2425 if (N->getValueType(0) != ResVT) 2426 return SDValue(); 2427 2428 if (Conversion.getValueType() != ExpectedConversionType) 2429 return SDValue(); 2430 2431 auto Source = Conversion.getOperand(0); 2432 if (Source.getValueType() != MVT::v2f64) 2433 return SDValue(); 2434 2435 if (!IsZeroSplat(N->getOperand(1)) || 2436 N->getOperand(1).getValueType() != ExpectedConversionType) 2437 return SDValue(); 2438 2439 unsigned Op = GetWasmConversionOp(ConversionOp); 2440 return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2441 } 2442 2443 // Combine this: 2444 // 2445 // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32) 2446 // 2447 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). 2448 // 2449 // Or this: 2450 // 2451 // (v4f32 (fp_round (concat_vectors $x, (v2f64 (splat 0))))) 2452 // 2453 // into (f32x4.demote_zero_f64x2 $x). 2454 EVT ResVT; 2455 auto ConversionOp = N->getOpcode(); 2456 switch (ConversionOp) { 2457 case ISD::FP_TO_SINT_SAT: 2458 case ISD::FP_TO_UINT_SAT: 2459 ResVT = MVT::v4i32; 2460 break; 2461 case ISD::FP_ROUND: 2462 ResVT = MVT::v4f32; 2463 break; 2464 default: 2465 llvm_unreachable("unexpected op"); 2466 } 2467 2468 if (N->getValueType(0) != ResVT) 2469 return SDValue(); 2470 2471 auto Concat = N->getOperand(0); 2472 if (Concat.getValueType() != MVT::v4f64) 2473 return SDValue(); 2474 2475 auto Source = Concat.getOperand(0); 2476 if (Source.getValueType() != MVT::v2f64) 2477 return SDValue(); 2478 2479 if (!IsZeroSplat(Concat.getOperand(1)) || 2480 Concat.getOperand(1).getValueType() != MVT::v2f64) 2481 return SDValue(); 2482 2483 unsigned Op = GetWasmConversionOp(ConversionOp); 2484 return DAG.getNode(Op, SDLoc(N), ResVT, Source); 2485 } 2486 2487 SDValue 2488 WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, 2489 DAGCombinerInfo &DCI) const { 2490 switch (N->getOpcode()) { 2491 default: 2492 return SDValue(); 2493 case ISD::VECTOR_SHUFFLE: 2494 return performVECTOR_SHUFFLECombine(N, DCI); 2495 case ISD::SIGN_EXTEND: 2496 case ISD::ZERO_EXTEND: 2497 return performVectorExtendCombine(N, DCI); 2498 case ISD::SINT_TO_FP: 2499 case ISD::UINT_TO_FP: 2500 case ISD::FP_EXTEND: 2501 case ISD::EXTRACT_SUBVECTOR: 2502 return performVectorConvertLowCombine(N, DCI); 2503 case ISD::FP_TO_SINT_SAT: 2504 case ISD::FP_TO_UINT_SAT: 2505 case ISD::FP_ROUND: 2506 case ISD::CONCAT_VECTORS: 2507 return performVectorTruncZeroCombine(N, DCI); 2508 } 2509 } 2510