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