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 /// \brief 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/MachineJumpTableInfo.h" 23 #include "llvm/CodeGen/MachineRegisterInfo.h" 24 #include "llvm/CodeGen/SelectionDAG.h" 25 #include "llvm/IR/DiagnosticInfo.h" 26 #include "llvm/IR/DiagnosticPrinter.h" 27 #include "llvm/IR/Function.h" 28 #include "llvm/IR/Intrinsics.h" 29 #include "llvm/Support/CommandLine.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/ErrorHandling.h" 32 #include "llvm/Support/raw_ostream.h" 33 #include "llvm/Target/TargetOptions.h" 34 using namespace llvm; 35 36 #define DEBUG_TYPE "wasm-lower" 37 38 WebAssemblyTargetLowering::WebAssemblyTargetLowering( 39 const TargetMachine &TM, const WebAssemblySubtarget &STI) 40 : TargetLowering(TM), Subtarget(&STI) { 41 auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; 42 43 // Booleans always contain 0 or 1. 44 setBooleanContents(ZeroOrOneBooleanContent); 45 // WebAssembly does not produce floating-point exceptions on normal floating 46 // point operations. 47 setHasFloatingPointExceptions(false); 48 // We don't know the microarchitecture here, so just reduce register pressure. 49 setSchedulingPreference(Sched::RegPressure); 50 // Tell ISel that we have a stack pointer. 51 setStackPointerRegisterToSaveRestore( 52 Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); 53 // Set up the register classes. 54 addRegisterClass(MVT::i32, &WebAssembly::I32RegClass); 55 addRegisterClass(MVT::i64, &WebAssembly::I64RegClass); 56 addRegisterClass(MVT::f32, &WebAssembly::F32RegClass); 57 addRegisterClass(MVT::f64, &WebAssembly::F64RegClass); 58 // Compute derived properties from the register classes. 59 computeRegisterProperties(Subtarget->getRegisterInfo()); 60 61 setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); 62 setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); 63 setOperationAction(ISD::JumpTable, MVTPtr, Custom); 64 65 // Take the default expansion for va_arg, va_copy, and va_end. There is no 66 // default action for va_start, so we do that custom. 67 setOperationAction(ISD::VASTART, MVT::Other, Custom); 68 setOperationAction(ISD::VAARG, MVT::Other, Expand); 69 setOperationAction(ISD::VACOPY, MVT::Other, Expand); 70 setOperationAction(ISD::VAEND, MVT::Other, Expand); 71 72 for (auto T : {MVT::f32, MVT::f64}) { 73 // Don't expand the floating-point types to constant pools. 74 setOperationAction(ISD::ConstantFP, T, Legal); 75 // Expand floating-point comparisons. 76 for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, 77 ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) 78 setCondCodeAction(CC, T, Expand); 79 // Expand floating-point library function operators. 80 for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOWI, ISD::FPOW, 81 ISD::FREM, ISD::FMA}) 82 setOperationAction(Op, T, Expand); 83 // Note supported floating-point library function operators that otherwise 84 // default to expand. 85 for (auto Op : 86 {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT}) 87 setOperationAction(Op, T, Legal); 88 // Support minnan and maxnan, which otherwise default to expand. 89 setOperationAction(ISD::FMINNAN, T, Legal); 90 setOperationAction(ISD::FMAXNAN, T, Legal); 91 } 92 93 for (auto T : {MVT::i32, MVT::i64}) { 94 // Expand unavailable integer operations. 95 for (auto Op : 96 {ISD::BSWAP, ISD::ROTL, ISD::ROTR, ISD::SMUL_LOHI, ISD::UMUL_LOHI, 97 ISD::MULHS, ISD::MULHU, ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, 98 ISD::SRA_PARTS, ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, 99 ISD::SUBE}) { 100 setOperationAction(Op, T, Expand); 101 } 102 } 103 104 // As a special case, these operators use the type to mean the type to 105 // sign-extend from. 106 for (auto T : {MVT::i1, MVT::i8, MVT::i16, MVT::i32}) 107 setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); 108 109 // Dynamic stack allocation: use the default expansion. 110 setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 111 setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 112 setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); 113 114 setOperationAction(ISD::FrameIndex, MVT::i32, Custom); 115 116 // Expand these forms; we pattern-match the forms that we can handle in isel. 117 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) 118 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) 119 setOperationAction(Op, T, Expand); 120 121 // We have custom switch handling. 122 setOperationAction(ISD::BR_JT, MVT::Other, Custom); 123 124 // WebAssembly doesn't have: 125 // - Floating-point extending loads. 126 // - Floating-point truncating stores. 127 // - i1 extending loads. 128 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 129 setTruncStoreAction(MVT::f64, MVT::f32, Expand); 130 for (auto T : MVT::integer_valuetypes()) 131 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) 132 setLoadExtAction(Ext, T, MVT::i1, Promote); 133 134 // Trap lowers to wasm unreachable 135 setOperationAction(ISD::TRAP, MVT::Other, Legal); 136 } 137 138 FastISel *WebAssemblyTargetLowering::createFastISel( 139 FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const { 140 return WebAssembly::createFastISel(FuncInfo, LibInfo); 141 } 142 143 bool WebAssemblyTargetLowering::isOffsetFoldingLegal( 144 const GlobalAddressSDNode * /*GA*/) const { 145 // All offsets can be folded. 146 return true; 147 } 148 149 MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, 150 EVT VT) const { 151 unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1); 152 if (BitWidth > 1 && BitWidth < 8) 153 BitWidth = 8; 154 155 if (BitWidth > 64) { 156 BitWidth = 64; 157 assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) && 158 "64-bit shift counts ought to be enough for anyone"); 159 } 160 161 MVT Result = MVT::getIntegerVT(BitWidth); 162 assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE && 163 "Unable to represent scalar shift amount type"); 164 return Result; 165 } 166 167 const char * 168 WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const { 169 switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { 170 case WebAssemblyISD::FIRST_NUMBER: 171 break; 172 #define HANDLE_NODETYPE(NODE) \ 173 case WebAssemblyISD::NODE: \ 174 return "WebAssemblyISD::" #NODE; 175 #include "WebAssemblyISD.def" 176 #undef HANDLE_NODETYPE 177 } 178 return nullptr; 179 } 180 181 std::pair<unsigned, const TargetRegisterClass *> 182 WebAssemblyTargetLowering::getRegForInlineAsmConstraint( 183 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 184 // First, see if this is a constraint that directly corresponds to a 185 // WebAssembly register class. 186 if (Constraint.size() == 1) { 187 switch (Constraint[0]) { 188 case 'r': 189 assert(VT != MVT::iPTR && "Pointer MVT not expected here"); 190 if (VT.isInteger() && !VT.isVector()) { 191 if (VT.getSizeInBits() <= 32) 192 return std::make_pair(0U, &WebAssembly::I32RegClass); 193 if (VT.getSizeInBits() <= 64) 194 return std::make_pair(0U, &WebAssembly::I64RegClass); 195 } 196 break; 197 default: 198 break; 199 } 200 } 201 202 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 203 } 204 205 bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const { 206 // Assume ctz is a relatively cheap operation. 207 return true; 208 } 209 210 bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const { 211 // Assume clz is a relatively cheap operation. 212 return true; 213 } 214 215 bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, 216 const AddrMode &AM, 217 Type *Ty, 218 unsigned AS) const { 219 // WebAssembly offsets are added as unsigned without wrapping. The 220 // isLegalAddressingMode gives us no way to determine if wrapping could be 221 // happening, so we approximate this by accepting only non-negative offsets. 222 if (AM.BaseOffs < 0) 223 return false; 224 225 // WebAssembly has no scale register operands. 226 if (AM.Scale != 0) 227 return false; 228 229 // Everything else is legal. 230 return true; 231 } 232 233 bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( 234 EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, 235 bool *Fast) const { 236 // WebAssembly supports unaligned accesses, though it should be declared 237 // with the p2align attribute on loads and stores which do so, and there 238 // may be a performance impact. We tell LLVM they're "fast" because 239 // for the kinds of things that LLVM uses this for (merging adjacent stores 240 // of constants, etc.), WebAssembly implementations will either want the 241 // unaligned access or they'll split anyway. 242 if (Fast) 243 *Fast = true; 244 return true; 245 } 246 247 //===----------------------------------------------------------------------===// 248 // WebAssembly Lowering private implementation. 249 //===----------------------------------------------------------------------===// 250 251 //===----------------------------------------------------------------------===// 252 // Lowering Code 253 //===----------------------------------------------------------------------===// 254 255 static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) { 256 MachineFunction &MF = DAG.getMachineFunction(); 257 DAG.getContext()->diagnose( 258 DiagnosticInfoUnsupported(*MF.getFunction(), msg, DL.getDebugLoc())); 259 } 260 261 // Test whether the given calling convention is supported. 262 static bool CallingConvSupported(CallingConv::ID CallConv) { 263 // We currently support the language-independent target-independent 264 // conventions. We don't yet have a way to annotate calls with properties like 265 // "cold", and we don't have any call-clobbered registers, so these are mostly 266 // all handled the same. 267 return CallConv == CallingConv::C || CallConv == CallingConv::Fast || 268 CallConv == CallingConv::Cold || 269 CallConv == CallingConv::PreserveMost || 270 CallConv == CallingConv::PreserveAll || 271 CallConv == CallingConv::CXX_FAST_TLS; 272 } 273 274 SDValue 275 WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, 276 SmallVectorImpl<SDValue> &InVals) const { 277 SelectionDAG &DAG = CLI.DAG; 278 SDLoc DL = CLI.DL; 279 SDValue Chain = CLI.Chain; 280 SDValue Callee = CLI.Callee; 281 MachineFunction &MF = DAG.getMachineFunction(); 282 283 CallingConv::ID CallConv = CLI.CallConv; 284 if (!CallingConvSupported(CallConv)) 285 fail(DL, DAG, 286 "WebAssembly doesn't support language-specific or target-specific " 287 "calling conventions yet"); 288 if (CLI.IsPatchPoint) 289 fail(DL, DAG, "WebAssembly doesn't support patch point yet"); 290 291 // WebAssembly doesn't currently support explicit tail calls. If they are 292 // required, fail. Otherwise, just disable them. 293 if ((CallConv == CallingConv::Fast && CLI.IsTailCall && 294 MF.getTarget().Options.GuaranteedTailCallOpt) || 295 (CLI.CS && CLI.CS->isMustTailCall())) 296 fail(DL, DAG, "WebAssembly doesn't support tail call yet"); 297 CLI.IsTailCall = false; 298 299 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 300 if (Ins.size() > 1) 301 fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet"); 302 303 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 304 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 305 for (unsigned i = 0; i < Outs.size(); ++i) { 306 const ISD::OutputArg &Out = Outs[i]; 307 SDValue &OutVal = OutVals[i]; 308 if (Out.Flags.isNest()) 309 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 310 if (Out.Flags.isInAlloca()) 311 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 312 if (Out.Flags.isInConsecutiveRegs()) 313 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 314 if (Out.Flags.isInConsecutiveRegsLast()) 315 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 316 if (Out.Flags.isByVal()) { 317 auto *MFI = MF.getFrameInfo(); 318 assert(Out.Flags.getByValSize() && "Zero-size byval?"); 319 int FI = MFI->CreateStackObject(Out.Flags.getByValSize(), 320 Out.Flags.getByValAlign(), 321 /*isSS=*/false); 322 SDValue SizeNode = 323 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32); 324 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 325 Chain = DAG.getMemcpy( 326 Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(), 327 /*isVolatile*/ false, /*AlwaysInline=*/true, 328 /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); 329 OutVal = FINode; 330 } 331 } 332 333 bool IsVarArg = CLI.IsVarArg; 334 unsigned NumFixedArgs = CLI.NumFixedArgs; 335 auto PtrVT = getPointerTy(MF.getDataLayout()); 336 337 // Analyze operands of the call, assigning locations to each operand. 338 SmallVector<CCValAssign, 16> ArgLocs; 339 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 340 341 if (IsVarArg) { 342 // Outgoing non-fixed arguments are placed at the top of the stack. First 343 // compute their offsets and the total amount of argument stack space 344 // needed. 345 for (SDValue Arg : 346 make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) { 347 EVT VT = Arg.getValueType(); 348 assert(VT != MVT::iPTR && "Legalized args should be concrete"); 349 Type *Ty = VT.getTypeForEVT(*DAG.getContext()); 350 unsigned Offset = 351 CCInfo.AllocateStack(MF.getDataLayout().getTypeAllocSize(Ty), 352 MF.getDataLayout().getABITypeAlignment(Ty)); 353 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), 354 Offset, VT.getSimpleVT(), 355 CCValAssign::Full)); 356 } 357 } 358 359 unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); 360 361 SDValue NB; 362 if (NumBytes) { 363 NB = DAG.getConstant(NumBytes, DL, PtrVT, true); 364 Chain = DAG.getCALLSEQ_START(Chain, NB, DL); 365 } 366 367 if (IsVarArg) { 368 // For non-fixed arguments, next emit stores to store the argument values 369 // to the stack at the offsets computed above. 370 SDValue SP = DAG.getCopyFromReg( 371 Chain, DL, getStackPointerRegisterToSaveRestore(), PtrVT); 372 unsigned ValNo = 0; 373 SmallVector<SDValue, 8> Chains; 374 for (SDValue Arg : 375 make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) { 376 assert(ArgLocs[ValNo].getValNo() == ValNo && 377 "ArgLocs should remain in order and only hold varargs args"); 378 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); 379 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, SP, 380 DAG.getConstant(Offset, DL, PtrVT)); 381 Chains.push_back(DAG.getStore(Chain, DL, Arg, Add, 382 MachinePointerInfo::getStack(MF, Offset), 383 false, false, 0)); 384 } 385 if (!Chains.empty()) 386 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); 387 } 388 389 // Compute the operands for the CALLn node. 390 SmallVector<SDValue, 16> Ops; 391 Ops.push_back(Chain); 392 Ops.push_back(Callee); 393 394 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs 395 // isn't reliable. 396 Ops.append(OutVals.begin(), 397 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); 398 399 SmallVector<EVT, 8> Tys; 400 for (const auto &In : Ins) { 401 assert(!In.Flags.isByVal() && "byval is not valid for return values"); 402 assert(!In.Flags.isNest() && "nest is not valid for return values"); 403 if (In.Flags.isInAlloca()) 404 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values"); 405 if (In.Flags.isInConsecutiveRegs()) 406 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values"); 407 if (In.Flags.isInConsecutiveRegsLast()) 408 fail(DL, DAG, 409 "WebAssembly hasn't implemented cons regs last return values"); 410 // Ignore In.getOrigAlign() because all our arguments are passed in 411 // registers. 412 Tys.push_back(In.VT); 413 } 414 Tys.push_back(MVT::Other); 415 SDVTList TyList = DAG.getVTList(Tys); 416 SDValue Res = 417 DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1, 418 DL, TyList, Ops); 419 if (Ins.empty()) { 420 Chain = Res; 421 } else { 422 InVals.push_back(Res); 423 Chain = Res.getValue(1); 424 } 425 426 if (NumBytes) { 427 SDValue Unused = DAG.getTargetConstant(0, DL, PtrVT); 428 Chain = DAG.getCALLSEQ_END(Chain, NB, Unused, SDValue(), DL); 429 } 430 431 return Chain; 432 } 433 434 bool WebAssemblyTargetLowering::CanLowerReturn( 435 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/, 436 const SmallVectorImpl<ISD::OutputArg> &Outs, 437 LLVMContext & /*Context*/) const { 438 // WebAssembly can't currently handle returning tuples. 439 return Outs.size() <= 1; 440 } 441 442 SDValue WebAssemblyTargetLowering::LowerReturn( 443 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, 444 const SmallVectorImpl<ISD::OutputArg> &Outs, 445 const SmallVectorImpl<SDValue> &OutVals, SDLoc DL, 446 SelectionDAG &DAG) const { 447 assert(Outs.size() <= 1 && "WebAssembly can only return up to one value"); 448 if (!CallingConvSupported(CallConv)) 449 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 450 451 SmallVector<SDValue, 4> RetOps(1, Chain); 452 RetOps.append(OutVals.begin(), OutVals.end()); 453 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); 454 455 // Record the number and types of the return values. 456 for (const ISD::OutputArg &Out : Outs) { 457 assert(!Out.Flags.isByVal() && "byval is not valid for return values"); 458 assert(!Out.Flags.isNest() && "nest is not valid for return values"); 459 assert(Out.IsFixed && "non-fixed return value is not valid"); 460 if (Out.Flags.isInAlloca()) 461 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results"); 462 if (Out.Flags.isInConsecutiveRegs()) 463 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results"); 464 if (Out.Flags.isInConsecutiveRegsLast()) 465 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results"); 466 } 467 468 return Chain; 469 } 470 471 SDValue WebAssemblyTargetLowering::LowerFormalArguments( 472 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, 473 const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG, 474 SmallVectorImpl<SDValue> &InVals) const { 475 MachineFunction &MF = DAG.getMachineFunction(); 476 477 if (!CallingConvSupported(CallConv)) 478 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); 479 480 // Set up the incoming ARGUMENTS value, which serves to represent the liveness 481 // of the incoming values before they're represented by virtual registers. 482 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); 483 484 for (const ISD::InputArg &In : Ins) { 485 if (In.Flags.isInAlloca()) 486 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); 487 if (In.Flags.isNest()) 488 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); 489 if (In.Flags.isInConsecutiveRegs()) 490 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); 491 if (In.Flags.isInConsecutiveRegsLast()) 492 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); 493 // Ignore In.getOrigAlign() because all our arguments are passed in 494 // registers. 495 InVals.push_back( 496 In.Used 497 ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, 498 DAG.getTargetConstant(InVals.size(), DL, MVT::i32)) 499 : DAG.getUNDEF(In.VT)); 500 501 // Record the number and types of arguments. 502 MF.getInfo<WebAssemblyFunctionInfo>()->addParam(In.VT); 503 } 504 505 // Incoming varargs arguments are on the stack and will be accessed through 506 // va_arg, so we don't need to do anything for them here. 507 508 return Chain; 509 } 510 511 //===----------------------------------------------------------------------===// 512 // Custom lowering hooks. 513 //===----------------------------------------------------------------------===// 514 515 SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, 516 SelectionDAG &DAG) const { 517 switch (Op.getOpcode()) { 518 default: 519 llvm_unreachable("unimplemented operation lowering"); 520 return SDValue(); 521 case ISD::FrameIndex: 522 return LowerFrameIndex(Op, DAG); 523 case ISD::GlobalAddress: 524 return LowerGlobalAddress(Op, DAG); 525 case ISD::ExternalSymbol: 526 return LowerExternalSymbol(Op, DAG); 527 case ISD::JumpTable: 528 return LowerJumpTable(Op, DAG); 529 case ISD::BR_JT: 530 return LowerBR_JT(Op, DAG); 531 case ISD::VASTART: 532 return LowerVASTART(Op, DAG); 533 } 534 } 535 536 SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, 537 SelectionDAG &DAG) const { 538 int FI = cast<FrameIndexSDNode>(Op)->getIndex(); 539 return DAG.getTargetFrameIndex(FI, Op.getValueType()); 540 } 541 542 SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, 543 SelectionDAG &DAG) const { 544 SDLoc DL(Op); 545 const auto *GA = cast<GlobalAddressSDNode>(Op); 546 EVT VT = Op.getValueType(); 547 assert(GA->getTargetFlags() == 0 && 548 "Unexpected target flags on generic GlobalAddressSDNode"); 549 if (GA->getAddressSpace() != 0) 550 fail(DL, DAG, "WebAssembly only expects the 0 address space"); 551 return DAG.getNode( 552 WebAssemblyISD::Wrapper, DL, VT, 553 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset())); 554 } 555 556 SDValue 557 WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op, 558 SelectionDAG &DAG) const { 559 SDLoc DL(Op); 560 const auto *ES = cast<ExternalSymbolSDNode>(Op); 561 EVT VT = Op.getValueType(); 562 assert(ES->getTargetFlags() == 0 && 563 "Unexpected target flags on generic ExternalSymbolSDNode"); 564 // Set the TargetFlags to 0x1 which indicates that this is a "function" 565 // symbol rather than a data symbol. We do this unconditionally even though 566 // we don't know anything about the symbol other than its name, because all 567 // external symbols used in target-independent SelectionDAG code are for 568 // functions. 569 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, 570 DAG.getTargetExternalSymbol(ES->getSymbol(), VT, 571 /*TargetFlags=*/0x1)); 572 } 573 574 SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op, 575 SelectionDAG &DAG) const { 576 // There's no need for a Wrapper node because we always incorporate a jump 577 // table operand into a TABLESWITCH instruction, rather than ever 578 // materializing it in a register. 579 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); 580 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(), 581 JT->getTargetFlags()); 582 } 583 584 SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, 585 SelectionDAG &DAG) const { 586 SDLoc DL(Op); 587 SDValue Chain = Op.getOperand(0); 588 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1)); 589 SDValue Index = Op.getOperand(2); 590 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags"); 591 592 SmallVector<SDValue, 8> Ops; 593 Ops.push_back(Chain); 594 Ops.push_back(Index); 595 596 MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo(); 597 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; 598 599 // TODO: For now, we just pick something arbitrary for a default case for now. 600 // We really want to sniff out the guard and put in the real default case (and 601 // delete the guard). 602 Ops.push_back(DAG.getBasicBlock(MBBs[0])); 603 604 // Add an operand for each case. 605 for (auto MBB : MBBs) 606 Ops.push_back(DAG.getBasicBlock(MBB)); 607 608 return DAG.getNode(WebAssemblyISD::TABLESWITCH, DL, MVT::Other, Ops); 609 } 610 611 SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, 612 SelectionDAG &DAG) const { 613 SDLoc DL(Op); 614 EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); 615 616 // The incoming non-fixed arguments are placed on the top of the stack, with 617 // natural alignment, at the point of the call, so the base pointer is just 618 // the current frame pointer. 619 DAG.getMachineFunction().getFrameInfo()->setFrameAddressIsTaken(true); 620 unsigned FP = 621 Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); 622 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FP, PtrVT); 623 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 624 return DAG.getStore(Op.getOperand(0), DL, FrameAddr, Op.getOperand(1), 625 MachinePointerInfo(SV), false, false, 0); 626 } 627 628 //===----------------------------------------------------------------------===// 629 // WebAssembly Optimization Hooks 630 //===----------------------------------------------------------------------===// 631