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