1 //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// This file implements the WebAssemblyTargetLowering class. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "WebAssemblyISelLowering.h" 16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 17 #include "WebAssemblyMachineFunctionInfo.h" 18 #include "WebAssemblySubtarget.h" 19 #include "WebAssemblyTargetMachine.h" 20 #include "llvm/CodeGen/Analysis.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/IR/DiagnosticInfo.h" 28 #include "llvm/IR/DiagnosticPrinter.h" 29 #include "llvm/IR/Function.h" 30 #include "llvm/IR/Intrinsics.h" 31 #include "llvm/Support/Debug.h" 32 #include "llvm/Support/ErrorHandling.h" 33 #include "llvm/Support/raw_ostream.h" 34 #include "llvm/Target/TargetOptions.h" 35 using namespace llvm; 36 37 #define DEBUG_TYPE "wasm-lower" 38 39 // Emit proposed instructions that may not have been implemented in engines 40 cl::opt<bool> EnableUnimplementedWasmSIMDInstrs( 41 "wasm-enable-unimplemented-simd", 42 cl::desc("Emit potentially-unimplemented WebAssembly SIMD instructions"), 43 cl::init(false)); 44 45 WebAssemblyTargetLowering::WebAssemblyTargetLowering( 46 const TargetMachine &TM, const WebAssemblySubtarget &STI) 47 : TargetLowering(TM), Subtarget(&STI) { 48 auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; 49 50 // Booleans always contain 0 or 1. 51 setBooleanContents(ZeroOrOneBooleanContent); 52 // Except in SIMD vectors 53 setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); 54 // WebAssembly does not produce floating-point exceptions on normal floating 55 // point operations. 56 setHasFloatingPointExceptions(false); 57 // We don't know the microarchitecture here, so just reduce register pressure. 58 setSchedulingPreference(Sched::RegPressure); 59 // Tell ISel that we have a stack pointer. 60 setStackPointerRegisterToSaveRestore( 61 Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); 62 // Set up the register classes. 63 addRegisterClass(MVT::i32, &WebAssembly::I32RegClass); 64 addRegisterClass(MVT::i64, &WebAssembly::I64RegClass); 65 addRegisterClass(MVT::f32, &WebAssembly::F32RegClass); 66 addRegisterClass(MVT::f64, &WebAssembly::F64RegClass); 67 if (Subtarget->hasSIMD128()) { 68 addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass); 69 addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass); 70 addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass); 71 addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass); 72 if (EnableUnimplementedWasmSIMDInstrs) { 73 addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); 74 addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); 75 } 76 } 77 // Compute derived properties from the register classes. 78 computeRegisterProperties(Subtarget->getRegisterInfo()); 79 80 setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); 81 setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); 82 setOperationAction(ISD::JumpTable, MVTPtr, Custom); 83 setOperationAction(ISD::BlockAddress, MVTPtr, Custom); 84 setOperationAction(ISD::BRIND, MVT::Other, Custom); 85 86 // Take the default expansion for va_arg, va_copy, and va_end. There is no 87 // default action for va_start, so we do that custom. 88 setOperationAction(ISD::VASTART, MVT::Other, Custom); 89 setOperationAction(ISD::VAARG, MVT::Other, Expand); 90 setOperationAction(ISD::VACOPY, MVT::Other, Expand); 91 setOperationAction(ISD::VAEND, MVT::Other, Expand); 92 93 for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) { 94 // Don't expand the floating-point types to constant pools. 95 setOperationAction(ISD::ConstantFP, T, Legal); 96 // Expand floating-point comparisons. 97 for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, 98 ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) 99 setCondCodeAction(CC, T, Expand); 100 // Expand floating-point library function operators. 101 for (auto Op : 102 {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA}) 103 setOperationAction(Op, T, Expand); 104 // Note supported floating-point library function operators that otherwise 105 // default to expand. 106 for (auto Op : 107 {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT}) 108 setOperationAction(Op, T, Legal); 109 // Support minimum and maximum, which otherwise default to expand. 110 setOperationAction(ISD::FMINIMUM, T, Legal); 111 setOperationAction(ISD::FMAXIMUM, T, Legal); 112 // WebAssembly currently has no builtin f16 support. 113 setOperationAction(ISD::FP16_TO_FP, T, Expand); 114 setOperationAction(ISD::FP_TO_FP16, T, Expand); 115 setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand); 116 setTruncStoreAction(T, MVT::f16, Expand); 117 } 118 119 // Support saturating add for i8x16 and i16x8 120 if (Subtarget->hasSIMD128()) 121 for (auto T : {MVT::v16i8, MVT::v8i16}) 122 for (auto Op : {ISD::SADDSAT, ISD::UADDSAT}) 123 setOperationAction(Op, T, Legal); 124 125 for (auto T : {MVT::i32, MVT::i64}) { 126 // Expand unavailable integer operations. 127 for (auto Op : 128 {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU, 129 ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS, 130 ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) { 131 setOperationAction(Op, T, Expand); 132 } 133 } 134 135 // There is no i64x2.mul instruction 136 setOperationAction(ISD::MUL, MVT::v2i64, Expand); 137 138 // We have custom shuffle lowering to expose the shuffle mask 139 if (Subtarget->hasSIMD128()) { 140 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) { 141 setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom); 142 } 143 if (EnableUnimplementedWasmSIMDInstrs) { 144 setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2i64, Custom); 145 setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2f64, Custom); 146 } 147 } 148 149 // Custom lowering since wasm shifts must have a scalar shift amount 150 if (Subtarget->hasSIMD128()) { 151 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) 152 for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) 153 setOperationAction(Op, T, Custom); 154 if (EnableUnimplementedWasmSIMDInstrs) 155 for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) 156 setOperationAction(Op, MVT::v2i64, Custom); 157 } 158 159 // There is no select instruction for vectors 160 if (Subtarget->hasSIMD128()) { 161 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) 162 setOperationAction(ISD::VSELECT, T, Expand); 163 if (EnableUnimplementedWasmSIMDInstrs) 164 for (auto T : {MVT::v2i64, MVT::v2f64}) 165 setOperationAction(ISD::VSELECT, T, Expand); 166 } 167 168 // As a special case, these operators use the type to mean the type to 169 // sign-extend from. 170 setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 171 if (!Subtarget->hasSignExt()) { 172 for (auto T : {MVT::i8, MVT::i16, MVT::i32}) 173 setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); 174 } 175 for (auto T : MVT::integer_vector_valuetypes()) 176 setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); 177 178 // Dynamic stack allocation: use the default expansion. 179 setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 180 setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 181 setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); 182 183 setOperationAction(ISD::FrameIndex, MVT::i32, Custom); 184 setOperationAction(ISD::CopyToReg, MVT::Other, Custom); 185 186 // Expand these forms; we pattern-match the forms that we can handle in isel. 187 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) 188 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) 189 setOperationAction(Op, T, Expand); 190 191 // We have custom switch handling. 192 setOperationAction(ISD::BR_JT, MVT::Other, Custom); 193 194 // WebAssembly doesn't have: 195 // - Floating-point extending loads. 196 // - Floating-point truncating stores. 197 // - i1 extending loads. 198 // - extending/truncating SIMD loads/stores 199 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 200 setTruncStoreAction(MVT::f64, MVT::f32, Expand); 201 for (auto T : MVT::integer_valuetypes()) 202 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 203 setLoadExtAction(Ext, T, MVT::i1, Promote); 204 if (Subtarget->hasSIMD128()) { 205 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, 206 MVT::v2f64}) { 207 for (auto MemT : MVT::vector_valuetypes()) { 208 if (MVT(T) != MemT) { 209 setTruncStoreAction(T, MemT, Expand); 210 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 211 setLoadExtAction(Ext, T, MemT, Expand); 212 } 213 } 214 } 215 } 216 217 // Custom lower lane accesses to expand out variable indices 218 if (Subtarget->hasSIMD128()) { 219 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) { 220 setOperationAction(ISD::EXTRACT_VECTOR_ELT, T, Custom); 221 setOperationAction(ISD::INSERT_VECTOR_ELT, T, Custom); 222 } 223 if (EnableUnimplementedWasmSIMDInstrs) { 224 for (auto T : {MVT::v2i64, MVT::v2f64}) { 225 setOperationAction(ISD::EXTRACT_VECTOR_ELT, T, Custom); 226 setOperationAction(ISD::INSERT_VECTOR_ELT, T, Custom); 227 } 228 } 229 } 230 231 // Trap lowers to wasm unreachable 232 setOperationAction(ISD::TRAP, MVT::Other, Legal); 233 234 // Exception handling intrinsics 235 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); 236 237 setMaxAtomicSizeInBitsSupported(64); 238 } 239 240 TargetLowering::AtomicExpansionKind 241 WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { 242 // We have wasm instructions for these 243 switch (AI->getOperation()) { 244 case AtomicRMWInst::Add: 245 case AtomicRMWInst::Sub: 246 case AtomicRMWInst::And: 247 case AtomicRMWInst::Or: 248 case AtomicRMWInst::Xor: 249 case AtomicRMWInst::Xchg: 250 return AtomicExpansionKind::None; 251 default: 252 break; 253 } 254 return AtomicExpansionKind::CmpXChg; 255 } 256 257 FastISel *WebAssemblyTargetLowering::createFastISel( 258 FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const { 259 return WebAssembly::createFastISel(FuncInfo, LibInfo); 260 } 261 262 bool WebAssemblyTargetLowering::isOffsetFoldingLegal( 263 const GlobalAddressSDNode * /*GA*/) const { 264 // All offsets can be folded. 265 return true; 266 } 267 268 MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, 269 EVT VT) const { 270 unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1); 271 if (BitWidth > 1 && BitWidth < 8) 272 BitWidth = 8; 273 274 if (BitWidth > 64) { 275 // The shift will be lowered to a libcall, and compiler-rt libcalls expect 276 // the count to be an i32. 277 BitWidth = 32; 278 assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) && 279 "32-bit shift counts ought to be enough for anyone"); 280 } 281 282 MVT Result = MVT::getIntegerVT(BitWidth); 283 assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE && 284 "Unable to represent scalar shift amount type"); 285 return Result; 286 } 287 288 // Lower an fp-to-int conversion operator from the LLVM opcode, which has an 289 // undefined result on invalid/overflow, to the WebAssembly opcode, which 290 // traps on invalid/overflow. 291 static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL, 292 MachineBasicBlock *BB, 293 const TargetInstrInfo &TII, 294 bool IsUnsigned, bool Int64, 295 bool Float64, unsigned LoweredOpcode) { 296 MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); 297 298 unsigned OutReg = MI.getOperand(0).getReg(); 299 unsigned InReg = MI.getOperand(1).getReg(); 300 301 unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32; 302 unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32; 303 unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32; 304 unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32; 305 unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; 306 unsigned Eqz = WebAssembly::EQZ_I32; 307 unsigned And = WebAssembly::AND_I32; 308 int64_t Limit = Int64 ? INT64_MIN : INT32_MIN; 309 int64_t Substitute = IsUnsigned ? 0 : Limit; 310 double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit; 311 auto &Context = BB->getParent()->getFunction().getContext(); 312 Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context); 313 314 const BasicBlock *LLVM_BB = BB->getBasicBlock(); 315 MachineFunction *F = BB->getParent(); 316 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVM_BB); 317 MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVM_BB); 318 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVM_BB); 319 320 MachineFunction::iterator It = ++BB->getIterator(); 321 F->insert(It, FalseMBB); 322 F->insert(It, TrueMBB); 323 F->insert(It, DoneMBB); 324 325 // Transfer the remainder of BB and its successor edges to DoneMBB. 326 DoneMBB->splice(DoneMBB->begin(), BB, 327 std::next(MachineBasicBlock::iterator(MI)), BB->end()); 328 DoneMBB->transferSuccessorsAndUpdatePHIs(BB); 329 330 BB->addSuccessor(TrueMBB); 331 BB->addSuccessor(FalseMBB); 332 TrueMBB->addSuccessor(DoneMBB); 333 FalseMBB->addSuccessor(DoneMBB); 334 335 unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg; 336 Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 337 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 338 CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 339 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 340 FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 341 TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); 342 343 MI.eraseFromParent(); 344 // For signed numbers, we can do a single comparison to determine whether 345 // fabs(x) is within range. 346 if (IsUnsigned) { 347 Tmp0 = InReg; 348 } else { 349 BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg); 350 } 351 BuildMI(BB, DL, TII.get(FConst), Tmp1) 352 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal))); 353 BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1); 354 355 // For unsigned numbers, we have to do a separate comparison with zero. 356 if (IsUnsigned) { 357 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); 358 unsigned SecondCmpReg = 359 MRI.createVirtualRegister(&WebAssembly::I32RegClass); 360 unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 361 BuildMI(BB, DL, TII.get(FConst), Tmp1) 362 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0))); 363 BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1); 364 BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg); 365 CmpReg = AndReg; 366 } 367 368 BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg); 369 370 // Create the CFG diamond to select between doing the conversion or using 371 // the substitute value. 372 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg); 373 BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg); 374 BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB); 375 BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute); 376 BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg) 377 .addReg(FalseReg) 378 .addMBB(FalseMBB) 379 .addReg(TrueReg) 380 .addMBB(TrueMBB); 381 382 return DoneMBB; 383 } 384 385 MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter( 386 MachineInstr &MI, MachineBasicBlock *BB) const { 387 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 388 DebugLoc DL = MI.getDebugLoc(); 389 390 switch (MI.getOpcode()) { 391 default: 392 llvm_unreachable("Unexpected instr type to insert"); 393 case WebAssembly::FP_TO_SINT_I32_F32: 394 return LowerFPToInt(MI, DL, BB, TII, false, false, false, 395 WebAssembly::I32_TRUNC_S_F32); 396 case WebAssembly::FP_TO_UINT_I32_F32: 397 return LowerFPToInt(MI, DL, BB, TII, true, false, false, 398 WebAssembly::I32_TRUNC_U_F32); 399 case WebAssembly::FP_TO_SINT_I64_F32: 400 return LowerFPToInt(MI, DL, BB, TII, false, true, false, 401 WebAssembly::I64_TRUNC_S_F32); 402 case WebAssembly::FP_TO_UINT_I64_F32: 403 return LowerFPToInt(MI, DL, BB, TII, true, true, false, 404 WebAssembly::I64_TRUNC_U_F32); 405 case WebAssembly::FP_TO_SINT_I32_F64: 406 return LowerFPToInt(MI, DL, BB, TII, false, false, true, 407 WebAssembly::I32_TRUNC_S_F64); 408 case WebAssembly::FP_TO_UINT_I32_F64: 409 return LowerFPToInt(MI, DL, BB, TII, true, false, true, 410 WebAssembly::I32_TRUNC_U_F64); 411 case WebAssembly::FP_TO_SINT_I64_F64: 412 return LowerFPToInt(MI, DL, BB, TII, false, true, true, 413 WebAssembly::I64_TRUNC_S_F64); 414 case WebAssembly::FP_TO_UINT_I64_F64: 415 return LowerFPToInt(MI, DL, BB, TII, true, true, true, 416 WebAssembly::I64_TRUNC_U_F64); 417 llvm_unreachable("Unexpected instruction to emit with custom inserter"); 418 } 419 } 420 421 const char * 422 WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const { 423 switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { 424 case WebAssemblyISD::FIRST_NUMBER: 425 break; 426 #define HANDLE_NODETYPE(NODE) \ 427 case WebAssemblyISD::NODE: \ 428 return "WebAssemblyISD::" #NODE; 429 #include "WebAssemblyISD.def" 430 #undef HANDLE_NODETYPE 431 } 432 return nullptr; 433 } 434 435 std::pair<unsigned, const TargetRegisterClass *> 436 WebAssemblyTargetLowering::getRegForInlineAsmConstraint( 437 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 438 // First, see if this is a constraint that directly corresponds to a 439 // WebAssembly register class. 440 if (Constraint.size() == 1) { 441 switch (Constraint[0]) { 442 case 'r': 443 assert(VT != MVT::iPTR && "Pointer MVT not expected here"); 444 if (Subtarget->hasSIMD128() && VT.isVector()) { 445 if (VT.getSizeInBits() == 128) 446 return std::make_pair(0U, &WebAssembly::V128RegClass); 447 } 448 if (VT.isInteger() && !VT.isVector()) { 449 if (VT.getSizeInBits() <= 32) 450 return std::make_pair(0U, &WebAssembly::I32RegClass); 451 if (VT.getSizeInBits() <= 64) 452 return std::make_pair(0U, &WebAssembly::I64RegClass); 453 } 454 break; 455 default: 456 break; 457 } 458 } 459 460 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 461 } 462 463 bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const { 464 // Assume ctz is a relatively cheap operation. 465 return true; 466 } 467 468 bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const { 469 // Assume clz is a relatively cheap operation. 470 return true; 471 } 472 473 bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, 474 const AddrMode &AM, 475 Type *Ty, unsigned AS, 476 Instruction *I) const { 477 // WebAssembly offsets are added as unsigned without wrapping. The 478 // isLegalAddressingMode gives us no way to determine if wrapping could be 479 // happening, so we approximate this by accepting only non-negative offsets. 480 if (AM.BaseOffs < 0) 481 return false; 482 483 // WebAssembly has no scale register operands. 484 if (AM.Scale != 0) 485 return false; 486 487 // Everything else is legal. 488 return true; 489 } 490 491 bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( 492 EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, bool *Fast) const { 493 // WebAssembly supports unaligned accesses, though it should be declared 494 // with the p2align attribute on loads and stores which do so, and there 495 // may be a performance impact. We tell LLVM they're "fast" because 496 // for the kinds of things that LLVM uses this for (merging adjacent stores 497 // of constants, etc.), WebAssembly implementations will either want the 498 // unaligned access or they'll split anyway. 499 if (Fast) 500 *Fast = true; 501 return true; 502 } 503 504 bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, 505 AttributeList Attr) const { 506 // The current thinking is that wasm engines will perform this optimization, 507 // so we can save on code size. 508 return true; 509 } 510 511 EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL, 512 LLVMContext &C, 513 EVT VT) const { 514 if (VT.isVector()) 515 return VT.changeVectorElementTypeToInteger(); 516 517 return TargetLowering::getSetCCResultType(DL, C, VT); 518 } 519 520 bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, 521 const CallInst &I, 522 MachineFunction &MF, 523 unsigned Intrinsic) const { 524 switch (Intrinsic) { 525 case Intrinsic::wasm_atomic_notify: 526 Info.opc = ISD::INTRINSIC_W_CHAIN; 527 Info.memVT = MVT::i32; 528 Info.ptrVal = I.getArgOperand(0); 529 Info.offset = 0; 530 Info.align = 4; 531 // atomic.notify instruction does not really load the memory specified with 532 // this argument, but MachineMemOperand should either be load or store, so 533 // we set this to a load. 534 // FIXME Volatile isn't really correct, but currently all LLVM atomic 535 // instructions are treated as volatiles in the backend, so we should be 536 // consistent. The same applies for wasm_atomic_wait intrinsics too. 537 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 538 return true; 539 case Intrinsic::wasm_atomic_wait_i32: 540 Info.opc = ISD::INTRINSIC_W_CHAIN; 541 Info.memVT = MVT::i32; 542 Info.ptrVal = I.getArgOperand(0); 543 Info.offset = 0; 544 Info.align = 4; 545 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 546 return true; 547 case Intrinsic::wasm_atomic_wait_i64: 548 Info.opc = ISD::INTRINSIC_W_CHAIN; 549 Info.memVT = MVT::i64; 550 Info.ptrVal = I.getArgOperand(0); 551 Info.offset = 0; 552 Info.align = 8; 553 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; 554 return true; 555 default: 556 return false; 557 } 558 } 559 560 //===----------------------------------------------------------------------===// 561 // WebAssembly Lowering private implementation. 562 //===----------------------------------------------------------------------===// 563 564 //===----------------------------------------------------------------------===// 565 // Lowering Code 566 //===----------------------------------------------------------------------===// 567 568 static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *msg) { 569 MachineFunction &MF = DAG.getMachineFunction(); 570 DAG.getContext()->diagnose( 571 DiagnosticInfoUnsupported(MF.getFunction(), msg, DL.getDebugLoc())); 572 } 573 574 // Test whether the given calling convention is supported. 575 static bool CallingConvSupported(CallingConv::ID CallConv) { 576 // We currently support the language-independent target-independent 577 // conventions. We don't yet have a way to annotate calls with properties like 578 // "cold", and we don't have any call-clobbered registers, so these are mostly 579 // all handled the same. 580 return CallConv == CallingConv::C || CallConv == CallingConv::Fast || 581 CallConv == CallingConv::Cold || 582 CallConv == CallingConv::PreserveMost || 583 CallConv == CallingConv::PreserveAll || 584 CallConv == CallingConv::CXX_FAST_TLS; 585 } 586 587 SDValue 588 WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, 589 SmallVectorImpl<SDValue> &InVals) const { 590 SelectionDAG &DAG = CLI.DAG; 591 SDLoc DL = CLI.DL; 592 SDValue Chain = CLI.Chain; 593 SDValue Callee = CLI.Callee; 594 MachineFunction &MF = DAG.getMachineFunction(); 595 auto Layout = MF.getDataLayout(); 596 597 CallingConv::ID CallConv = CLI.CallConv; 598 if (!CallingConvSupported(CallConv)) 599 fail(DL, DAG, 600 "WebAssembly doesn't support language-specific or target-specific " 601 "calling conventions yet"); 602 if (CLI.IsPatchPoint) 603 fail(DL, DAG, "WebAssembly doesn't support patch point yet"); 604 605 // WebAssembly doesn't currently support explicit tail calls. If they are 606 // required, fail. Otherwise, just disable them. 607 if ((CallConv == CallingConv::Fast && CLI.IsTailCall && 608 MF.getTarget().Options.GuaranteedTailCallOpt) || 609 (CLI.CS && CLI.CS.isMustTailCall())) 610 fail(DL, DAG, "WebAssembly doesn't support tail call yet"); 611 CLI.IsTailCall = false; 612 613 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 614 if (Ins.size() > 1) 615 fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet"); 616 617 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 618 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 619 unsigned NumFixedArgs = 0; 620 for (unsigned i = 0; i < Outs.size(); ++i) { 621 const ISD::OutputArg &Out = Outs[i]; 622 SDValue &OutVal = OutVals[i]; 623 if (Out.Flags.isNest()) 624 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 625 if (Out.Flags.isInAlloca()) 626 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 627 if (Out.Flags.isInConsecutiveRegs()) 628 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 629 if (Out.Flags.isInConsecutiveRegsLast()) 630 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 631 if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) { 632 auto &MFI = MF.getFrameInfo(); 633 int FI = MFI.CreateStackObject(Out.Flags.getByValSize(), 634 Out.Flags.getByValAlign(), 635 /*isSS=*/false); 636 SDValue SizeNode = 637 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32); 638 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 639 Chain = DAG.getMemcpy( 640 Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(), 641 /*isVolatile*/ false, /*AlwaysInline=*/false, 642 /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); 643 OutVal = FINode; 644 } 645 // Count the number of fixed args *after* legalization. 646 NumFixedArgs += Out.IsFixed; 647 } 648 649 bool IsVarArg = CLI.IsVarArg; 650 auto PtrVT = getPointerTy(Layout); 651 652 // Analyze operands of the call, assigning locations to each operand. 653 SmallVector<CCValAssign, 16> ArgLocs; 654 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 655 656 if (IsVarArg) { 657 // Outgoing non-fixed arguments are placed in a buffer. First 658 // compute their offsets and the total amount of buffer space needed. 659 for (SDValue Arg : 660 make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) { 661 EVT VT = Arg.getValueType(); 662 assert(VT != MVT::iPTR && "Legalized args should be concrete"); 663 Type *Ty = VT.getTypeForEVT(*DAG.getContext()); 664 unsigned Offset = CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), 665 Layout.getABITypeAlignment(Ty)); 666 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), 667 Offset, VT.getSimpleVT(), 668 CCValAssign::Full)); 669 } 670 } 671 672 unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); 673 674 SDValue FINode; 675 if (IsVarArg && NumBytes) { 676 // For non-fixed arguments, next emit stores to store the argument values 677 // to the stack buffer at the offsets computed above. 678 int FI = MF.getFrameInfo().CreateStackObject(NumBytes, 679 Layout.getStackAlignment(), 680 /*isSS=*/false); 681 unsigned ValNo = 0; 682 SmallVector<SDValue, 8> Chains; 683 for (SDValue Arg : 684 make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) { 685 assert(ArgLocs[ValNo].getValNo() == ValNo && 686 "ArgLocs should remain in order and only hold varargs args"); 687 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); 688 FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); 689 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode, 690 DAG.getConstant(Offset, DL, PtrVT)); 691 Chains.push_back( 692 DAG.getStore(Chain, DL, Arg, Add, 693 MachinePointerInfo::getFixedStack(MF, FI, Offset), 0)); 694 } 695 if (!Chains.empty()) 696 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); 697 } else if (IsVarArg) { 698 FINode = DAG.getIntPtrConstant(0, DL); 699 } 700 701 // Compute the operands for the CALLn node. 702 SmallVector<SDValue, 16> Ops; 703 Ops.push_back(Chain); 704 Ops.push_back(Callee); 705 706 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs 707 // isn't reliable. 708 Ops.append(OutVals.begin(), 709 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); 710 // Add a pointer to the vararg buffer. 711 if (IsVarArg) 712 Ops.push_back(FINode); 713 714 SmallVector<EVT, 8> InTys; 715 for (const auto &In : Ins) { 716 assert(!In.Flags.isByVal() && "byval is not valid for return values"); 717 assert(!In.Flags.isNest() && "nest is not valid for return values"); 718 if (In.Flags.isInAlloca()) 719 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values"); 720 if (In.Flags.isInConsecutiveRegs()) 721 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values"); 722 if (In.Flags.isInConsecutiveRegsLast()) 723 fail(DL, DAG, 724 "WebAssembly hasn't implemented cons regs last return values"); 725 // Ignore In.getOrigAlign() because all our arguments are passed in 726 // registers. 727 InTys.push_back(In.VT); 728 } 729 InTys.push_back(MVT::Other); 730 SDVTList InTyList = DAG.getVTList(InTys); 731 SDValue Res = 732 DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1, 733 DL, InTyList, Ops); 734 if (Ins.empty()) { 735 Chain = Res; 736 } else { 737 InVals.push_back(Res); 738 Chain = Res.getValue(1); 739 } 740 741 return Chain; 742 } 743 744 bool WebAssemblyTargetLowering::CanLowerReturn( 745 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/, 746 const SmallVectorImpl<ISD::OutputArg> &Outs, 747 LLVMContext & /*Context*/) const { 748 // WebAssembly can't currently handle returning tuples. 749 return Outs.size() <= 1; 750 } 751 752 SDValue WebAssemblyTargetLowering::LowerReturn( 753 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, 754 const SmallVectorImpl<ISD::OutputArg> &Outs, 755 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 756 SelectionDAG &DAG) const { 757 assert(Outs.size() <= 1 && "WebAssembly can only return up to one value"); 758 if (!CallingConvSupported(CallConv)) 759 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 760 761 SmallVector<SDValue, 4> RetOps(1, Chain); 762 RetOps.append(OutVals.begin(), OutVals.end()); 763 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); 764 765 // Record the number and types of the return values. 766 for (const ISD::OutputArg &Out : Outs) { 767 assert(!Out.Flags.isByVal() && "byval is not valid for return values"); 768 assert(!Out.Flags.isNest() && "nest is not valid for return values"); 769 assert(Out.IsFixed && "non-fixed return value is not valid"); 770 if (Out.Flags.isInAlloca()) 771 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results"); 772 if (Out.Flags.isInConsecutiveRegs()) 773 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results"); 774 if (Out.Flags.isInConsecutiveRegsLast()) 775 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results"); 776 } 777 778 return Chain; 779 } 780 781 SDValue WebAssemblyTargetLowering::LowerFormalArguments( 782 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 783 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 784 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 785 if (!CallingConvSupported(CallConv)) 786 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 787 788 MachineFunction &MF = DAG.getMachineFunction(); 789 auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); 790 791 // Set up the incoming ARGUMENTS value, which serves to represent the liveness 792 // of the incoming values before they're represented by virtual registers. 793 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); 794 795 for (const ISD::InputArg &In : Ins) { 796 if (In.Flags.isInAlloca()) 797 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 798 if (In.Flags.isNest()) 799 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 800 if (In.Flags.isInConsecutiveRegs()) 801 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 802 if (In.Flags.isInConsecutiveRegsLast()) 803 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 804 // Ignore In.getOrigAlign() because all our arguments are passed in 805 // registers. 806 InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, 807 DAG.getTargetConstant(InVals.size(), 808 DL, MVT::i32)) 809 : DAG.getUNDEF(In.VT)); 810 811 // Record the number and types of arguments. 812 MFI->addParam(In.VT); 813 } 814 815 // Varargs are copied into a buffer allocated by the caller, and a pointer to 816 // the buffer is passed as an argument. 817 if (IsVarArg) { 818 MVT PtrVT = getPointerTy(MF.getDataLayout()); 819 unsigned VarargVreg = 820 MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT)); 821 MFI->setVarargBufferVreg(VarargVreg); 822 Chain = DAG.getCopyToReg( 823 Chain, DL, VarargVreg, 824 DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT, 825 DAG.getTargetConstant(Ins.size(), DL, MVT::i32))); 826 MFI->addParam(PtrVT); 827 } 828 829 // Record the number and types of arguments and results. 830 SmallVector<MVT, 4> Params; 831 SmallVector<MVT, 4> Results; 832 ComputeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(), 833 DAG.getTarget(), Params, Results); 834 for (MVT VT : Results) 835 MFI->addResult(VT); 836 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify 837 // the param logic here with ComputeSignatureVTs 838 assert(MFI->getParams().size() == Params.size() && 839 std::equal(MFI->getParams().begin(), MFI->getParams().end(), 840 Params.begin())); 841 842 return Chain; 843 } 844 845 //===----------------------------------------------------------------------===// 846 // Custom lowering hooks. 847 //===----------------------------------------------------------------------===// 848 849 SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, 850 SelectionDAG &DAG) const { 851 SDLoc DL(Op); 852 switch (Op.getOpcode()) { 853 default: 854 llvm_unreachable("unimplemented operation lowering"); 855 return SDValue(); 856 case ISD::FrameIndex: 857 return LowerFrameIndex(Op, DAG); 858 case ISD::GlobalAddress: 859 return LowerGlobalAddress(Op, DAG); 860 case ISD::ExternalSymbol: 861 return LowerExternalSymbol(Op, DAG); 862 case ISD::JumpTable: 863 return LowerJumpTable(Op, DAG); 864 case ISD::BR_JT: 865 return LowerBR_JT(Op, DAG); 866 case ISD::VASTART: 867 return LowerVASTART(Op, DAG); 868 case ISD::BlockAddress: 869 case ISD::BRIND: 870 fail(DL, DAG, "WebAssembly hasn't implemented computed gotos"); 871 return SDValue(); 872 case ISD::RETURNADDR: // Probably nothing meaningful can be returned here. 873 fail(DL, DAG, "WebAssembly hasn't implemented __builtin_return_address"); 874 return SDValue(); 875 case ISD::FRAMEADDR: 876 return LowerFRAMEADDR(Op, DAG); 877 case ISD::CopyToReg: 878 return LowerCopyToReg(Op, DAG); 879 case ISD::INTRINSIC_WO_CHAIN: 880 return LowerINTRINSIC_WO_CHAIN(Op, DAG); 881 case ISD::EXTRACT_VECTOR_ELT: 882 case ISD::INSERT_VECTOR_ELT: 883 return LowerAccessVectorElement(Op, DAG); 884 case ISD::VECTOR_SHUFFLE: 885 return LowerVECTOR_SHUFFLE(Op, DAG); 886 case ISD::SHL: 887 case ISD::SRA: 888 case ISD::SRL: 889 return LowerShift(Op, DAG); 890 } 891 } 892 893 SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op, 894 SelectionDAG &DAG) const { 895 SDValue Src = Op.getOperand(2); 896 if (isa<FrameIndexSDNode>(Src.getNode())) { 897 // CopyToReg nodes don't support FrameIndex operands. Other targets select 898 // the FI to some LEA-like instruction, but since we don't have that, we 899 // need to insert some kind of instruction that can take an FI operand and 900 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy 901 // copy_local between Op and its FI operand. 902 SDValue Chain = Op.getOperand(0); 903 SDLoc DL(Op); 904 unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg(); 905 EVT VT = Src.getValueType(); 906 SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32 907 : WebAssembly::COPY_I64, 908 DL, VT, Src), 909 0); 910 return Op.getNode()->getNumValues() == 1 911 ? DAG.getCopyToReg(Chain, DL, Reg, Copy) 912 : DAG.getCopyToReg(Chain, DL, Reg, Copy, 913 Op.getNumOperands() == 4 ? Op.getOperand(3) 914 : SDValue()); 915 } 916 return SDValue(); 917 } 918 919 SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, 920 SelectionDAG &DAG) const { 921 int FI = cast<FrameIndexSDNode>(Op)->getIndex(); 922 return DAG.getTargetFrameIndex(FI, Op.getValueType()); 923 } 924 925 SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op, 926 SelectionDAG &DAG) const { 927 // Non-zero depths are not supported by WebAssembly currently. Use the 928 // legalizer's default expansion, which is to return 0 (what this function is 929 // documented to do). 930 if (Op.getConstantOperandVal(0) > 0) 931 return SDValue(); 932 933 DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true); 934 EVT VT = Op.getValueType(); 935 unsigned FP = 936 Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); 937 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT); 938 } 939 940 SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, 941 SelectionDAG &DAG) const { 942 SDLoc DL(Op); 943 const auto *GA = cast<GlobalAddressSDNode>(Op); 944 EVT VT = Op.getValueType(); 945 assert(GA->getTargetFlags() == 0 && 946 "Unexpected target flags on generic GlobalAddressSDNode"); 947 if (GA->getAddressSpace() != 0) 948 fail(DL, DAG, "WebAssembly only expects the 0 address space"); 949 return DAG.getNode( 950 WebAssemblyISD::Wrapper, DL, VT, 951 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset())); 952 } 953 954 SDValue 955 WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op, 956 SelectionDAG &DAG) const { 957 SDLoc DL(Op); 958 const auto *ES = cast<ExternalSymbolSDNode>(Op); 959 EVT VT = Op.getValueType(); 960 assert(ES->getTargetFlags() == 0 && 961 "Unexpected target flags on generic ExternalSymbolSDNode"); 962 // Set the TargetFlags to 0x1 which indicates that this is a "function" 963 // symbol rather than a data symbol. We do this unconditionally even though 964 // we don't know anything about the symbol other than its name, because all 965 // external symbols used in target-independent SelectionDAG code are for 966 // functions. 967 return DAG.getNode( 968 WebAssemblyISD::Wrapper, DL, VT, 969 DAG.getTargetExternalSymbol(ES->getSymbol(), VT, 970 WebAssemblyII::MO_SYMBOL_FUNCTION)); 971 } 972 973 SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op, 974 SelectionDAG &DAG) const { 975 // There's no need for a Wrapper node because we always incorporate a jump 976 // table operand into a BR_TABLE instruction, rather than ever 977 // materializing it in a register. 978 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); 979 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(), 980 JT->getTargetFlags()); 981 } 982 983 SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, 984 SelectionDAG &DAG) const { 985 SDLoc DL(Op); 986 SDValue Chain = Op.getOperand(0); 987 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1)); 988 SDValue Index = Op.getOperand(2); 989 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags"); 990 991 SmallVector<SDValue, 8> Ops; 992 Ops.push_back(Chain); 993 Ops.push_back(Index); 994 995 MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo(); 996 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; 997 998 // Add an operand for each case. 999 for (auto MBB : MBBs) 1000 Ops.push_back(DAG.getBasicBlock(MBB)); 1001 1002 // TODO: For now, we just pick something arbitrary for a default case for now. 1003 // We really want to sniff out the guard and put in the real default case (and 1004 // delete the guard). 1005 Ops.push_back(DAG.getBasicBlock(MBBs[0])); 1006 1007 return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops); 1008 } 1009 1010 SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, 1011 SelectionDAG &DAG) const { 1012 SDLoc DL(Op); 1013 EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); 1014 1015 auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>(); 1016 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 1017 1018 SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL, 1019 MFI->getVarargBufferVreg(), PtrVT); 1020 return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1), 1021 MachinePointerInfo(SV), 0); 1022 } 1023 1024 SDValue 1025 WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, 1026 SelectionDAG &DAG) const { 1027 unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 1028 SDLoc DL(Op); 1029 switch (IntNo) { 1030 default: 1031 return {}; // Don't custom lower most intrinsics. 1032 1033 case Intrinsic::wasm_lsda: { 1034 MachineFunction &MF = DAG.getMachineFunction(); 1035 EVT VT = Op.getValueType(); 1036 const TargetLowering &TLI = DAG.getTargetLoweringInfo(); 1037 MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); 1038 auto &Context = MF.getMMI().getContext(); 1039 MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") + 1040 Twine(MF.getFunctionNumber())); 1041 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 1042 DAG.getMCSymbol(S, PtrVT)); 1043 } 1044 } 1045 } 1046 1047 SDValue 1048 WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, 1049 SelectionDAG &DAG) const { 1050 SDLoc DL(Op); 1051 ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask(); 1052 MVT VecType = Op.getOperand(0).getSimpleValueType(); 1053 assert(VecType.is128BitVector() && "Unexpected shuffle vector type"); 1054 size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8; 1055 1056 // Space for two vector args and sixteen mask indices 1057 SDValue Ops[18]; 1058 size_t OpIdx = 0; 1059 Ops[OpIdx++] = Op.getOperand(0); 1060 Ops[OpIdx++] = Op.getOperand(1); 1061 1062 // Expand mask indices to byte indices and materialize them as operands 1063 for (size_t I = 0, Lanes = Mask.size(); I < Lanes; ++I) { 1064 for (size_t J = 0; J < LaneBytes; ++J) { 1065 // Lower undefs (represented by -1 in mask) to zero 1066 uint64_t ByteIndex = 1067 Mask[I] == -1 ? 0 : (uint64_t)Mask[I] * LaneBytes + J; 1068 Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32); 1069 } 1070 } 1071 1072 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); 1073 } 1074 1075 SDValue 1076 WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op, 1077 SelectionDAG &DAG) const { 1078 // Allow constant lane indices, expand variable lane indices 1079 SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode(); 1080 if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef()) 1081 return Op; 1082 else 1083 // Perform default expansion 1084 return SDValue(); 1085 } 1086 1087 SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, 1088 SelectionDAG &DAG) const { 1089 SDLoc DL(Op); 1090 1091 // Only manually lower vector shifts 1092 assert(Op.getSimpleValueType().isVector()); 1093 1094 // Unroll non-splat vector shifts 1095 BuildVectorSDNode *ShiftVec; 1096 SDValue SplatVal; 1097 if (!(ShiftVec = dyn_cast<BuildVectorSDNode>(Op.getOperand(1).getNode())) || 1098 !(SplatVal = ShiftVec->getSplatValue())) 1099 return DAG.UnrollVectorOp(Op.getNode()); 1100 1101 // All splats except i64x2 const splats are handled by patterns 1102 ConstantSDNode *SplatConst = dyn_cast<ConstantSDNode>(SplatVal); 1103 if (!SplatConst || Op.getSimpleValueType() != MVT::v2i64) 1104 return Op; 1105 1106 // i64x2 const splats are custom lowered to avoid unnecessary wraps 1107 unsigned Opcode; 1108 switch (Op.getOpcode()) { 1109 case ISD::SHL: 1110 Opcode = WebAssemblyISD::VEC_SHL; 1111 break; 1112 case ISD::SRA: 1113 Opcode = WebAssemblyISD::VEC_SHR_S; 1114 break; 1115 case ISD::SRL: 1116 Opcode = WebAssemblyISD::VEC_SHR_U; 1117 break; 1118 default: 1119 llvm_unreachable("unexpected opcode"); 1120 } 1121 APInt Shift = SplatConst->getAPIntValue().zextOrTrunc(32); 1122 return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), 1123 DAG.getConstant(Shift, DL, MVT::i32)); 1124 } 1125 1126 //===----------------------------------------------------------------------===// 1127 // WebAssembly Optimization Hooks 1128 //===----------------------------------------------------------------------===// 1129