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