110e730a2SDan Gohman //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
210e730a2SDan Gohman //
310e730a2SDan Gohman //                     The LLVM Compiler Infrastructure
410e730a2SDan Gohman //
510e730a2SDan Gohman // This file is distributed under the University of Illinois Open Source
610e730a2SDan Gohman // License. See LICENSE.TXT for details.
710e730a2SDan Gohman //
810e730a2SDan Gohman //===----------------------------------------------------------------------===//
910e730a2SDan Gohman ///
1010e730a2SDan Gohman /// \file
1110e730a2SDan Gohman /// \brief This file implements the WebAssemblyTargetLowering class.
1210e730a2SDan Gohman ///
1310e730a2SDan Gohman //===----------------------------------------------------------------------===//
1410e730a2SDan Gohman 
1510e730a2SDan Gohman #include "WebAssemblyISelLowering.h"
1610e730a2SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
1710e730a2SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
1810e730a2SDan Gohman #include "WebAssemblySubtarget.h"
1910e730a2SDan Gohman #include "WebAssemblyTargetMachine.h"
2010e730a2SDan Gohman #include "WebAssemblyTargetObjectFile.h"
2110e730a2SDan Gohman #include "llvm/CodeGen/Analysis.h"
22af111db8SJF Bastien #include "llvm/CodeGen/CallingConvLower.h"
23950a13cfSDan Gohman #include "llvm/CodeGen/MachineJumpTableInfo.h"
2410e730a2SDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
2510e730a2SDan Gohman #include "llvm/CodeGen/SelectionDAG.h"
26b9073fb2SJF Bastien #include "llvm/IR/DiagnosticInfo.h"
27b9073fb2SJF Bastien #include "llvm/IR/DiagnosticPrinter.h"
2810e730a2SDan Gohman #include "llvm/IR/Function.h"
2910e730a2SDan Gohman #include "llvm/IR/Intrinsics.h"
3010e730a2SDan Gohman #include "llvm/Support/CommandLine.h"
3110e730a2SDan Gohman #include "llvm/Support/Debug.h"
3210e730a2SDan Gohman #include "llvm/Support/ErrorHandling.h"
3310e730a2SDan Gohman #include "llvm/Support/raw_ostream.h"
3410e730a2SDan Gohman #include "llvm/Target/TargetOptions.h"
3510e730a2SDan Gohman using namespace llvm;
3610e730a2SDan Gohman 
3710e730a2SDan Gohman #define DEBUG_TYPE "wasm-lower"
3810e730a2SDan Gohman 
39b9073fb2SJF Bastien namespace {
40b9073fb2SJF Bastien // Diagnostic information for unimplemented or unsupported feature reporting.
419c54d3b4SDan Gohman // TODO: This code is copied from BPF and AMDGPU; consider factoring it out
429c54d3b4SDan Gohman // and sharing code.
43fd4a88c3SDan Gohman class DiagnosticInfoUnsupported final : public DiagnosticInfo {
44b9073fb2SJF Bastien private:
45b9073fb2SJF Bastien   // Debug location where this diagnostic is triggered.
46b9073fb2SJF Bastien   DebugLoc DLoc;
47b9073fb2SJF Bastien   const Twine &Description;
48b9073fb2SJF Bastien   const Function &Fn;
49b9073fb2SJF Bastien   SDValue Value;
50b9073fb2SJF Bastien 
51b9073fb2SJF Bastien   static int KindID;
52b9073fb2SJF Bastien 
53b9073fb2SJF Bastien   static int getKindID() {
54b9073fb2SJF Bastien     if (KindID == 0)
55b9073fb2SJF Bastien       KindID = llvm::getNextAvailablePluginDiagnosticKind();
56b9073fb2SJF Bastien     return KindID;
57b9073fb2SJF Bastien   }
58b9073fb2SJF Bastien 
59b9073fb2SJF Bastien public:
60b9073fb2SJF Bastien   DiagnosticInfoUnsupported(SDLoc DLoc, const Function &Fn, const Twine &Desc,
61b9073fb2SJF Bastien                             SDValue Value)
62b9073fb2SJF Bastien       : DiagnosticInfo(getKindID(), DS_Error), DLoc(DLoc.getDebugLoc()),
63b9073fb2SJF Bastien         Description(Desc), Fn(Fn), Value(Value) {}
64b9073fb2SJF Bastien 
65b9073fb2SJF Bastien   void print(DiagnosticPrinter &DP) const override {
66b9073fb2SJF Bastien     std::string Str;
67b9073fb2SJF Bastien     raw_string_ostream OS(Str);
68b9073fb2SJF Bastien 
69b9073fb2SJF Bastien     if (DLoc) {
70b9073fb2SJF Bastien       auto DIL = DLoc.get();
71b9073fb2SJF Bastien       StringRef Filename = DIL->getFilename();
72b9073fb2SJF Bastien       unsigned Line = DIL->getLine();
73b9073fb2SJF Bastien       unsigned Column = DIL->getColumn();
74b9073fb2SJF Bastien       OS << Filename << ':' << Line << ':' << Column << ' ';
75b9073fb2SJF Bastien     }
76b9073fb2SJF Bastien 
77b9073fb2SJF Bastien     OS << "in function " << Fn.getName() << ' ' << *Fn.getFunctionType() << '\n'
78b9073fb2SJF Bastien        << Description;
79b9073fb2SJF Bastien     if (Value)
80b9073fb2SJF Bastien       Value->print(OS);
81b9073fb2SJF Bastien     OS << '\n';
82b9073fb2SJF Bastien     OS.flush();
83b9073fb2SJF Bastien     DP << Str;
84b9073fb2SJF Bastien   }
85b9073fb2SJF Bastien 
86b9073fb2SJF Bastien   static bool classof(const DiagnosticInfo *DI) {
87b9073fb2SJF Bastien     return DI->getKind() == getKindID();
88b9073fb2SJF Bastien   }
89b9073fb2SJF Bastien };
90b9073fb2SJF Bastien 
91b9073fb2SJF Bastien int DiagnosticInfoUnsupported::KindID = 0;
92b9073fb2SJF Bastien } // end anonymous namespace
93b9073fb2SJF Bastien 
9410e730a2SDan Gohman WebAssemblyTargetLowering::WebAssemblyTargetLowering(
9510e730a2SDan Gohman     const TargetMachine &TM, const WebAssemblySubtarget &STI)
96bfaf7e15SDan Gohman     : TargetLowering(TM), Subtarget(&STI) {
97af111db8SJF Bastien   auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
98af111db8SJF Bastien 
9971d29aceSJF Bastien   // Booleans always contain 0 or 1.
10071d29aceSJF Bastien   setBooleanContents(ZeroOrOneBooleanContent);
101bfaf7e15SDan Gohman   // WebAssembly does not produce floating-point exceptions on normal floating
102bfaf7e15SDan Gohman   // point operations.
103bfaf7e15SDan Gohman   setHasFloatingPointExceptions(false);
104489abd70SDan Gohman   // We don't know the microarchitecture here, so just reduce register pressure.
105489abd70SDan Gohman   setSchedulingPreference(Sched::RegPressure);
106b9073fb2SJF Bastien   // Tell ISel that we have a stack pointer.
107b9073fb2SJF Bastien   setStackPointerRegisterToSaveRestore(
108b9073fb2SJF Bastien       Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
109b9073fb2SJF Bastien   // Set up the register classes.
110d0bf9812SDan Gohman   addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
111d0bf9812SDan Gohman   addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
112d0bf9812SDan Gohman   addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
113d0bf9812SDan Gohman   addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
114b9073fb2SJF Bastien   // Compute derived properties from the register classes.
115b9073fb2SJF Bastien   computeRegisterProperties(Subtarget->getRegisterInfo());
116b9073fb2SJF Bastien 
117af111db8SJF Bastien   setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
1182c8fe6a4SDan Gohman   setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
119950a13cfSDan Gohman   setOperationAction(ISD::JumpTable, MVTPtr, Custom);
120af111db8SJF Bastien 
12135bfb24cSDan Gohman   // Take the default expansion for va_arg, va_copy, and va_end. There is no
12235bfb24cSDan Gohman   // default action for va_start, so we do that custom.
12335bfb24cSDan Gohman   setOperationAction(ISD::VASTART, MVT::Other, Custom);
12435bfb24cSDan Gohman   setOperationAction(ISD::VAARG, MVT::Other, Expand);
12535bfb24cSDan Gohman   setOperationAction(ISD::VACOPY, MVT::Other, Expand);
12635bfb24cSDan Gohman   setOperationAction(ISD::VAEND, MVT::Other, Expand);
12735bfb24cSDan Gohman 
128da06bce8SJF Bastien   for (auto T : {MVT::f32, MVT::f64}) {
129da06bce8SJF Bastien     // Don't expand the floating-point types to constant pools.
130da06bce8SJF Bastien     setOperationAction(ISD::ConstantFP, T, Legal);
131da06bce8SJF Bastien     // Expand floating-point comparisons.
132da06bce8SJF Bastien     for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
133da06bce8SJF Bastien                     ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
134da06bce8SJF Bastien       setCondCodeAction(CC, T, Expand);
13532907a6bSDan Gohman     // Expand floating-point library function operators.
136ebb23545SDan Gohman     for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOWI, ISD::FPOW,
137ebb23545SDan Gohman                     ISD::FREM})
13832907a6bSDan Gohman       setOperationAction(Op, T, Expand);
139896e53faSDan Gohman     // Note supported floating-point library function operators that otherwise
140896e53faSDan Gohman     // default to expand.
1417a6b9825SDan Gohman     for (auto Op :
1427a6b9825SDan Gohman          {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
143896e53faSDan Gohman       setOperationAction(Op, T, Legal);
144b84ae9bbSDan Gohman     // Support minnan and maxnan, which otherwise default to expand.
145b84ae9bbSDan Gohman     setOperationAction(ISD::FMINNAN, T, Legal);
146b84ae9bbSDan Gohman     setOperationAction(ISD::FMAXNAN, T, Legal);
147da06bce8SJF Bastien   }
14832907a6bSDan Gohman 
14932907a6bSDan Gohman   for (auto T : {MVT::i32, MVT::i64}) {
15032907a6bSDan Gohman     // Expand unavailable integer operations.
1517a6b9825SDan Gohman     for (auto Op :
1527a6b9825SDan Gohman          {ISD::BSWAP, ISD::ROTL, ISD::ROTR, ISD::SMUL_LOHI, ISD::UMUL_LOHI,
1537a6b9825SDan Gohman           ISD::MULHS, ISD::MULHU, ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS,
1547a6b9825SDan Gohman           ISD::SRA_PARTS, ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC,
1557a6b9825SDan Gohman           ISD::SUBE}) {
15632907a6bSDan Gohman       setOperationAction(Op, T, Expand);
15732907a6bSDan Gohman     }
15832907a6bSDan Gohman   }
15932907a6bSDan Gohman 
16032907a6bSDan Gohman   // As a special case, these operators use the type to mean the type to
16132907a6bSDan Gohman   // sign-extend from.
162*a5603b83SDan Gohman   for (auto T : {MVT::i1, MVT::i8, MVT::i16, MVT::i32})
16332907a6bSDan Gohman     setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
16432907a6bSDan Gohman 
16532907a6bSDan Gohman   // Dynamic stack allocation: use the default expansion.
16632907a6bSDan Gohman   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
16732907a6bSDan Gohman   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
1682683a553SDan Gohman   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
16973ff6afaSJF Bastien 
170950a13cfSDan Gohman   // Expand these forms; we pattern-match the forms that we can handle in isel.
171950a13cfSDan Gohman   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
172950a13cfSDan Gohman     for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
173950a13cfSDan Gohman       setOperationAction(Op, T, Expand);
174950a13cfSDan Gohman 
175950a13cfSDan Gohman   // We have custom switch handling.
176950a13cfSDan Gohman   setOperationAction(ISD::BR_JT, MVT::Other, Custom);
177950a13cfSDan Gohman 
17873ff6afaSJF Bastien   // WebAssembly doesn't have:
17973ff6afaSJF Bastien   //  - Floating-point extending loads.
18073ff6afaSJF Bastien   //  - Floating-point truncating stores.
18173ff6afaSJF Bastien   //  - i1 extending loads.
18273ff6afaSJF Bastien   setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f64, Expand);
18373ff6afaSJF Bastien   setTruncStoreAction(MVT::f64, MVT::f32, Expand);
18473ff6afaSJF Bastien   for (auto T : MVT::integer_valuetypes())
18573ff6afaSJF Bastien     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
18673ff6afaSJF Bastien       setLoadExtAction(Ext, T, MVT::i1, Promote);
187ffa143ceSDerek Schuff 
188ffa143ceSDerek Schuff   // Trap lowers to wasm unreachable
189ffa143ceSDerek Schuff   setOperationAction(ISD::TRAP, MVT::Other, Legal);
190bfaf7e15SDan Gohman }
19110e730a2SDan Gohman 
1927b63484bSDan Gohman FastISel *WebAssemblyTargetLowering::createFastISel(
1937b63484bSDan Gohman     FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
1947b63484bSDan Gohman   return WebAssembly::createFastISel(FuncInfo, LibInfo);
1957b63484bSDan Gohman }
1967b63484bSDan Gohman 
197af111db8SJF Bastien bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
1987a6b9825SDan Gohman     const GlobalAddressSDNode * /*GA*/) const {
199a4b710a7SDan Gohman   // All offsets can be folded.
200a4b710a7SDan Gohman   return true;
201af111db8SJF Bastien }
202af111db8SJF Bastien 
2037a6b9825SDan Gohman MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
204fda53373SJF Bastien                                                       EVT VT) const {
205a8483755SDan Gohman   unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
206a8483755SDan Gohman   if (BitWidth > 1 && BitWidth < 8)
207a8483755SDan Gohman     BitWidth = 8;
208a8483755SDan Gohman   MVT Result = MVT::getIntegerVT(BitWidth);
209a8483755SDan Gohman   assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
210a8483755SDan Gohman          "Unable to represent scalar shift amount type");
211a8483755SDan Gohman   return Result;
212fda53373SJF Bastien }
213fda53373SJF Bastien 
214480c8408SJF Bastien const char *
215480c8408SJF Bastien WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
216480c8408SJF Bastien   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
217af111db8SJF Bastien   case WebAssemblyISD::FIRST_NUMBER:
218af111db8SJF Bastien     break;
219af111db8SJF Bastien #define HANDLE_NODETYPE(NODE)                                                  \
220af111db8SJF Bastien   case WebAssemblyISD::NODE:                                                   \
221af111db8SJF Bastien     return "WebAssemblyISD::" #NODE;
222af111db8SJF Bastien #include "WebAssemblyISD.def"
223af111db8SJF Bastien #undef HANDLE_NODETYPE
224480c8408SJF Bastien   }
225480c8408SJF Bastien   return nullptr;
226480c8408SJF Bastien }
227480c8408SJF Bastien 
228f19ed562SDan Gohman std::pair<unsigned, const TargetRegisterClass *>
229f19ed562SDan Gohman WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
230f19ed562SDan Gohman     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
231f19ed562SDan Gohman   // First, see if this is a constraint that directly corresponds to a
232f19ed562SDan Gohman   // WebAssembly register class.
233f19ed562SDan Gohman   if (Constraint.size() == 1) {
234f19ed562SDan Gohman     switch (Constraint[0]) {
235f19ed562SDan Gohman     case 'r':
236284384b6SDan Gohman       assert(VT != MVT::iPTR && "Pointer MVT not expected here");
237284384b6SDan Gohman       if (VT.isInteger() && !VT.isVector()) {
238284384b6SDan Gohman         if (VT.getSizeInBits() <= 32)
239f19ed562SDan Gohman           return std::make_pair(0U, &WebAssembly::I32RegClass);
240284384b6SDan Gohman         if (VT.getSizeInBits() <= 64)
241a774d719SDan Gohman           return std::make_pair(0U, &WebAssembly::I64RegClass);
242284384b6SDan Gohman       }
243a774d719SDan Gohman       break;
244f19ed562SDan Gohman     default:
245f19ed562SDan Gohman       break;
246f19ed562SDan Gohman     }
247f19ed562SDan Gohman   }
248f19ed562SDan Gohman 
249f19ed562SDan Gohman   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
250f19ed562SDan Gohman }
251f19ed562SDan Gohman 
2523192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
2533192ddfeSDan Gohman   // Assume ctz is a relatively cheap operation.
2543192ddfeSDan Gohman   return true;
2553192ddfeSDan Gohman }
2563192ddfeSDan Gohman 
2573192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
2583192ddfeSDan Gohman   // Assume clz is a relatively cheap operation.
2593192ddfeSDan Gohman   return true;
2603192ddfeSDan Gohman }
2613192ddfeSDan Gohman 
26210e730a2SDan Gohman //===----------------------------------------------------------------------===//
26310e730a2SDan Gohman // WebAssembly Lowering private implementation.
26410e730a2SDan Gohman //===----------------------------------------------------------------------===//
26510e730a2SDan Gohman 
26610e730a2SDan Gohman //===----------------------------------------------------------------------===//
26710e730a2SDan Gohman // Lowering Code
26810e730a2SDan Gohman //===----------------------------------------------------------------------===//
26910e730a2SDan Gohman 
270b9073fb2SJF Bastien static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
271b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
272b9073fb2SJF Bastien   DAG.getContext()->diagnose(
273b9073fb2SJF Bastien       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
274b9073fb2SJF Bastien }
275b9073fb2SJF Bastien 
27685dbdda1SDan Gohman // Test whether the given calling convention is supported.
277a3f5ce5fSDan Gohman static bool CallingConvSupported(CallingConv::ID CallConv) {
27885dbdda1SDan Gohman   // We currently support the language-independent target-independent
2791ce2b1afSDan Gohman   // conventions. We don't yet have a way to annotate calls with properties like
2801ce2b1afSDan Gohman   // "cold", and we don't have any call-clobbered registers, so these are mostly
2811ce2b1afSDan Gohman   // all handled the same.
282a3f5ce5fSDan Gohman   return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
2831ce2b1afSDan Gohman          CallConv == CallingConv::Cold ||
2841ce2b1afSDan Gohman          CallConv == CallingConv::PreserveMost ||
2851ce2b1afSDan Gohman          CallConv == CallingConv::PreserveAll ||
2861ce2b1afSDan Gohman          CallConv == CallingConv::CXX_FAST_TLS;
28785dbdda1SDan Gohman }
28885dbdda1SDan Gohman 
289d8a9d66dSJF Bastien SDValue
290d8a9d66dSJF Bastien WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
291d8a9d66dSJF Bastien                                      SmallVectorImpl<SDValue> &InVals) const {
292d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
293d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
294d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
295d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
296d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
297d8a9d66dSJF Bastien 
298d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
29985dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
3009cc692b0SDan Gohman     fail(DL, DAG,
3019cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
3029cc692b0SDan Gohman          "calling conventions yet");
303d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
304d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
305d8a9d66dSJF Bastien 
3069cc692b0SDan Gohman   // WebAssembly doesn't currently support explicit tail calls. If they are
3079cc692b0SDan Gohman   // required, fail. Otherwise, just disable them.
3089cc692b0SDan Gohman   if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
3099cc692b0SDan Gohman        MF.getTarget().Options.GuaranteedTailCallOpt) ||
3109cc692b0SDan Gohman       (CLI.CS && CLI.CS->isMustTailCall()))
3119cc692b0SDan Gohman     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
3129cc692b0SDan Gohman   CLI.IsTailCall = false;
3139cc692b0SDan Gohman 
314d8a9d66dSJF Bastien   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
315e590b33bSDan Gohman 
316d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
317e590b33bSDan Gohman   if (Ins.size() > 1)
318e590b33bSDan Gohman     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
319e590b33bSDan Gohman 
3202d822e73SDan Gohman   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
3212d822e73SDan Gohman   for (const ISD::OutputArg &Out : Outs) {
3227935fa3dSDan Gohman     if (Out.Flags.isByVal())
3237935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
3247935fa3dSDan Gohman     if (Out.Flags.isNest())
3257935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
3262d822e73SDan Gohman     if (Out.Flags.isInAlloca())
3277935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
3282d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegs())
3297935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
3302d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
3317935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
3322d822e73SDan Gohman   }
3332d822e73SDan Gohman 
334d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
33535bfb24cSDan Gohman   unsigned NumFixedArgs = CLI.NumFixedArgs;
33635bfb24cSDan Gohman   auto PtrVT = getPointerTy(MF.getDataLayout());
337e590b33bSDan Gohman 
338d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
339d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
340d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
341d8a9d66dSJF Bastien 
34235bfb24cSDan Gohman   if (IsVarArg) {
34335bfb24cSDan Gohman     // Outgoing non-fixed arguments are placed at the top of the stack. First
34435bfb24cSDan Gohman     // compute their offsets and the total amount of argument stack space
34535bfb24cSDan Gohman     // needed.
34635bfb24cSDan Gohman     for (SDValue Arg :
34735bfb24cSDan Gohman          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
34835bfb24cSDan Gohman       EVT VT = Arg.getValueType();
34935bfb24cSDan Gohman       assert(VT != MVT::iPTR && "Legalized args should be concrete");
35035bfb24cSDan Gohman       Type *Ty = VT.getTypeForEVT(*DAG.getContext());
35135bfb24cSDan Gohman       unsigned Offset =
35235bfb24cSDan Gohman           CCInfo.AllocateStack(MF.getDataLayout().getTypeAllocSize(Ty),
35335bfb24cSDan Gohman                                MF.getDataLayout().getABITypeAlignment(Ty));
35435bfb24cSDan Gohman       CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
35535bfb24cSDan Gohman                                         Offset, VT.getSimpleVT(),
35635bfb24cSDan Gohman                                         CCValAssign::Full));
35735bfb24cSDan Gohman     }
35835bfb24cSDan Gohman   }
35935bfb24cSDan Gohman 
36035bfb24cSDan Gohman   unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
36135bfb24cSDan Gohman 
362af111db8SJF Bastien   auto NB = DAG.getConstant(NumBytes, DL, PtrVT, true);
363af111db8SJF Bastien   Chain = DAG.getCALLSEQ_START(Chain, NB, DL);
364d8a9d66dSJF Bastien 
36535bfb24cSDan Gohman   if (IsVarArg) {
36635bfb24cSDan Gohman     // For non-fixed arguments, next emit stores to store the argument values
36735bfb24cSDan Gohman     // to the stack at the offsets computed above.
36835bfb24cSDan Gohman     SDValue SP = DAG.getCopyFromReg(
36935bfb24cSDan Gohman         Chain, DL, getStackPointerRegisterToSaveRestore(), PtrVT);
37035bfb24cSDan Gohman     unsigned ValNo = 0;
37135bfb24cSDan Gohman     SmallVector<SDValue, 8> Chains;
37235bfb24cSDan Gohman     for (SDValue Arg :
37335bfb24cSDan Gohman          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
37435bfb24cSDan Gohman       assert(ArgLocs[ValNo].getValNo() == ValNo &&
37535bfb24cSDan Gohman              "ArgLocs should remain in order and only hold varargs args");
37635bfb24cSDan Gohman       unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
37735bfb24cSDan Gohman       SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, SP,
37835bfb24cSDan Gohman                                 DAG.getConstant(Offset, DL, PtrVT));
37935bfb24cSDan Gohman       Chains.push_back(DAG.getStore(Chain, DL, Arg, Add,
38035bfb24cSDan Gohman                                     MachinePointerInfo::getStack(MF, Offset),
38135bfb24cSDan Gohman                                     false, false, 0));
38235bfb24cSDan Gohman     }
38335bfb24cSDan Gohman     if (!Chains.empty())
38435bfb24cSDan Gohman       Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
38535bfb24cSDan Gohman   }
38635bfb24cSDan Gohman 
38735bfb24cSDan Gohman   // Compute the operands for the CALLn node.
388d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
389d8a9d66dSJF Bastien   Ops.push_back(Chain);
390af111db8SJF Bastien   Ops.push_back(Callee);
39135bfb24cSDan Gohman 
39235bfb24cSDan Gohman   // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
39335bfb24cSDan Gohman   // isn't reliable.
39435bfb24cSDan Gohman   Ops.append(OutVals.begin(),
39535bfb24cSDan Gohman              IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
396d8a9d66dSJF Bastien 
397d8a9d66dSJF Bastien   SmallVector<EVT, 8> Tys;
3982d822e73SDan Gohman   for (const auto &In : Ins) {
3997935fa3dSDan Gohman     assert(!In.Flags.isByVal() && "byval is not valid for return values");
4007935fa3dSDan Gohman     assert(!In.Flags.isNest() && "nest is not valid for return values");
4012d822e73SDan Gohman     if (In.Flags.isInAlloca())
4027935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
4032d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegs())
4047935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
4052d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegsLast())
4067935fa3dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last return values");
4072d822e73SDan Gohman     // Ignore In.getOrigAlign() because all our arguments are passed in
4082d822e73SDan Gohman     // registers.
409d8a9d66dSJF Bastien     Tys.push_back(In.VT);
4102d822e73SDan Gohman   }
411d8a9d66dSJF Bastien   Tys.push_back(MVT::Other);
412af111db8SJF Bastien   SDVTList TyList = DAG.getVTList(Tys);
413f71abef7SDan Gohman   SDValue Res =
414f71abef7SDan Gohman       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
415f71abef7SDan Gohman                   DL, TyList, Ops);
416af111db8SJF Bastien   if (Ins.empty()) {
417af111db8SJF Bastien     Chain = Res;
418af111db8SJF Bastien   } else {
419d8a9d66dSJF Bastien     InVals.push_back(Res);
420d8a9d66dSJF Bastien     Chain = Res.getValue(1);
421af111db8SJF Bastien   }
422d8a9d66dSJF Bastien 
42335bfb24cSDan Gohman   SDValue Unused = DAG.getUNDEF(PtrVT);
42435bfb24cSDan Gohman   Chain = DAG.getCALLSEQ_END(Chain, NB, Unused, SDValue(), DL);
425d8a9d66dSJF Bastien 
426d8a9d66dSJF Bastien   return Chain;
427d8a9d66dSJF Bastien }
428d8a9d66dSJF Bastien 
429b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
4307a6b9825SDan Gohman     CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
4317a6b9825SDan Gohman     const SmallVectorImpl<ISD::OutputArg> &Outs,
4327a6b9825SDan Gohman     LLVMContext & /*Context*/) const {
433b9073fb2SJF Bastien   // WebAssembly can't currently handle returning tuples.
434b9073fb2SJF Bastien   return Outs.size() <= 1;
435b9073fb2SJF Bastien }
436b9073fb2SJF Bastien 
437b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
43835bfb24cSDan Gohman     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
439b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
440b9073fb2SJF Bastien     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
441b9073fb2SJF Bastien     SelectionDAG &DAG) const {
442b9073fb2SJF Bastien   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
44385dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
444b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
445b9073fb2SJF Bastien 
446600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
447600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
4484a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
449b9073fb2SJF Bastien 
450754cd11dSDan Gohman   // Record the number and types of the return values.
451754cd11dSDan Gohman   for (const ISD::OutputArg &Out : Outs) {
452ac132e93SDan Gohman     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
453ac132e93SDan Gohman     assert(!Out.Flags.isNest() && "nest is not valid for return values");
45435bfb24cSDan Gohman     assert(Out.IsFixed && "non-fixed return value is not valid");
455754cd11dSDan Gohman     if (Out.Flags.isInAlloca())
456754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
457754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegs())
458754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
459754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
460754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
461754cd11dSDan Gohman   }
462754cd11dSDan Gohman 
463b9073fb2SJF Bastien   return Chain;
464b9073fb2SJF Bastien }
465b9073fb2SJF Bastien 
466b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
46735bfb24cSDan Gohman     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
468b9073fb2SJF Bastien     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
469b9073fb2SJF Bastien     SmallVectorImpl<SDValue> &InVals) const {
470b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
471b9073fb2SJF Bastien 
47285dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
473b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
474b9073fb2SJF Bastien 
475fb3e0594SDan Gohman   // Set up the incoming ARGUMENTS value, which serves to represent the liveness
476fb3e0594SDan Gohman   // of the incoming values before they're represented by virtual registers.
477fb3e0594SDan Gohman   MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
478fb3e0594SDan Gohman 
479600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
480600aee98SJF Bastien     if (In.Flags.isByVal())
481600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
482600aee98SJF Bastien     if (In.Flags.isInAlloca())
483600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
484600aee98SJF Bastien     if (In.Flags.isNest())
485600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
486600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
487600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
488600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
489600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
4909c54d3b4SDan Gohman     // Ignore In.getOrigAlign() because all our arguments are passed in
4919c54d3b4SDan Gohman     // registers.
492d7fcc6f9SJF Bastien     InVals.push_back(
493d7fcc6f9SJF Bastien         In.Used
494d7fcc6f9SJF Bastien             ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
4955219ecf0SDan Gohman                           DAG.getTargetConstant(InVals.size(), DL, MVT::i32))
496cb7940f9SDan Gohman             : DAG.getUNDEF(In.VT));
497754cd11dSDan Gohman 
498754cd11dSDan Gohman     // Record the number and types of arguments.
499754cd11dSDan Gohman     MF.getInfo<WebAssemblyFunctionInfo>()->addParam(In.VT);
500600aee98SJF Bastien   }
501b9073fb2SJF Bastien 
50235bfb24cSDan Gohman   // Incoming varargs arguments are on the stack and will be accessed through
50335bfb24cSDan Gohman   // va_arg, so we don't need to do anything for them here.
50435bfb24cSDan Gohman 
505b9073fb2SJF Bastien   return Chain;
506b9073fb2SJF Bastien }
507b9073fb2SJF Bastien 
50810e730a2SDan Gohman //===----------------------------------------------------------------------===//
509af111db8SJF Bastien //  Custom lowering hooks.
51010e730a2SDan Gohman //===----------------------------------------------------------------------===//
51110e730a2SDan Gohman 
512af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
513af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
514af111db8SJF Bastien   switch (Op.getOpcode()) {
515af111db8SJF Bastien   default:
516af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
517af111db8SJF Bastien     return SDValue();
518af111db8SJF Bastien   case ISD::GlobalAddress:
519af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
5202c8fe6a4SDan Gohman   case ISD::ExternalSymbol:
5212c8fe6a4SDan Gohman     return LowerExternalSymbol(Op, DAG);
522950a13cfSDan Gohman   case ISD::JumpTable:
523950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
524950a13cfSDan Gohman   case ISD::BR_JT:
525950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
52635bfb24cSDan Gohman   case ISD::VASTART:
52735bfb24cSDan Gohman     return LowerVASTART(Op, DAG);
528af111db8SJF Bastien   }
529af111db8SJF Bastien }
530af111db8SJF Bastien 
531af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
532af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
533af111db8SJF Bastien   SDLoc DL(Op);
534af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
535af111db8SJF Bastien   EVT VT = Op.getValueType();
536af111db8SJF Bastien   assert(GA->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
537af111db8SJF Bastien   if (GA->getAddressSpace() != 0)
538af111db8SJF Bastien     fail(DL, DAG, "WebAssembly only expects the 0 address space");
539af111db8SJF Bastien   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
540a4b710a7SDan Gohman                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
541a4b710a7SDan Gohman                                                 GA->getOffset()));
542af111db8SJF Bastien }
543af111db8SJF Bastien 
5447a6b9825SDan Gohman SDValue
5457a6b9825SDan Gohman WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
5462c8fe6a4SDan Gohman                                                SelectionDAG &DAG) const {
5472c8fe6a4SDan Gohman   SDLoc DL(Op);
5482c8fe6a4SDan Gohman   const auto *ES = cast<ExternalSymbolSDNode>(Op);
5492c8fe6a4SDan Gohman   EVT VT = Op.getValueType();
5502c8fe6a4SDan Gohman   assert(ES->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
5512c8fe6a4SDan Gohman   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
5522c8fe6a4SDan Gohman                      DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
5532c8fe6a4SDan Gohman }
5542c8fe6a4SDan Gohman 
555950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
556950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
557950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
558bb7ce8e4SDan Gohman   // table operand into a TABLESWITCH instruction, rather than ever
559bb7ce8e4SDan Gohman   // materializing it in a register.
560950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
561950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
562950a13cfSDan Gohman                                 JT->getTargetFlags());
563950a13cfSDan Gohman }
564950a13cfSDan Gohman 
565950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
566950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
567950a13cfSDan Gohman   SDLoc DL(Op);
568950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
569950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
570950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
571950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
572950a13cfSDan Gohman 
573950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
574950a13cfSDan Gohman   Ops.push_back(Chain);
575950a13cfSDan Gohman   Ops.push_back(Index);
576950a13cfSDan Gohman 
577950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
578950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
579950a13cfSDan Gohman 
580950a13cfSDan Gohman   // TODO: For now, we just pick something arbitrary for a default case for now.
581950a13cfSDan Gohman   // We really want to sniff out the guard and put in the real default case (and
582950a13cfSDan Gohman   // delete the guard).
583950a13cfSDan Gohman   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
584950a13cfSDan Gohman 
585950a13cfSDan Gohman   // Add an operand for each case.
586950a13cfSDan Gohman   for (auto MBB : MBBs)
587950a13cfSDan Gohman     Ops.push_back(DAG.getBasicBlock(MBB));
588950a13cfSDan Gohman 
589bb7ce8e4SDan Gohman   return DAG.getNode(WebAssemblyISD::TABLESWITCH, DL, MVT::Other, Ops);
590950a13cfSDan Gohman }
591950a13cfSDan Gohman 
59235bfb24cSDan Gohman SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
59335bfb24cSDan Gohman                                                 SelectionDAG &DAG) const {
59435bfb24cSDan Gohman   SDLoc DL(Op);
59535bfb24cSDan Gohman   EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
59635bfb24cSDan Gohman 
59735bfb24cSDan Gohman   // The incoming non-fixed arguments are placed on the top of the stack, with
59835bfb24cSDan Gohman   // natural alignment, at the point of the call, so the base pointer is just
59935bfb24cSDan Gohman   // the current frame pointer.
60035bfb24cSDan Gohman   DAG.getMachineFunction().getFrameInfo()->setFrameAddressIsTaken(true);
60135bfb24cSDan Gohman   unsigned FP =
602fd98ea89SDan Gohman       Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
60335bfb24cSDan Gohman   SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FP, PtrVT);
60435bfb24cSDan Gohman   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
60535bfb24cSDan Gohman   return DAG.getStore(Op.getOperand(0), DL, FrameAddr, Op.getOperand(1),
60635bfb24cSDan Gohman                       MachinePointerInfo(SV), false, false, 0);
60735bfb24cSDan Gohman }
60835bfb24cSDan Gohman 
60910e730a2SDan Gohman //===----------------------------------------------------------------------===//
61010e730a2SDan Gohman //                          WebAssembly Optimization Hooks
61110e730a2SDan Gohman //===----------------------------------------------------------------------===//
61210e730a2SDan Gohman 
61310e730a2SDan Gohman MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
6147a6b9825SDan Gohman     const GlobalValue *GV, SectionKind /*Kind*/, Mangler & /*Mang*/,
6157a6b9825SDan Gohman     const TargetMachine & /*TM*/) const {
616e51c058eSDan Gohman   // TODO: Be more sophisticated than this.
617e51c058eSDan Gohman   return isa<Function>(GV) ? getTextSection() : getDataSection();
61810e730a2SDan Gohman }
619