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