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.
16232907a6bSDan Gohman   for (auto T : {MVT::i1, MVT::i8, MVT::i16})
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 {
199*a4b710a7SDan Gohman   // All offsets can be folded.
200*a4b710a7SDan Gohman   return true;
201af111db8SJF Bastien }
202af111db8SJF Bastien 
2037a6b9825SDan Gohman MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
204fda53373SJF Bastien                                                       EVT VT) const {
205fda53373SJF Bastien   return VT.getSimpleVT();
206fda53373SJF Bastien }
207fda53373SJF Bastien 
208480c8408SJF Bastien const char *
209480c8408SJF Bastien WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
210480c8408SJF Bastien   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
211af111db8SJF Bastien   case WebAssemblyISD::FIRST_NUMBER:
212af111db8SJF Bastien     break;
213af111db8SJF Bastien #define HANDLE_NODETYPE(NODE)                                                  \
214af111db8SJF Bastien   case WebAssemblyISD::NODE:                                                   \
215af111db8SJF Bastien     return "WebAssemblyISD::" #NODE;
216af111db8SJF Bastien #include "WebAssemblyISD.def"
217af111db8SJF Bastien #undef HANDLE_NODETYPE
218480c8408SJF Bastien   }
219480c8408SJF Bastien   return nullptr;
220480c8408SJF Bastien }
221480c8408SJF Bastien 
222f19ed562SDan Gohman std::pair<unsigned, const TargetRegisterClass *>
223f19ed562SDan Gohman WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
224f19ed562SDan Gohman     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
225f19ed562SDan Gohman   // First, see if this is a constraint that directly corresponds to a
226f19ed562SDan Gohman   // WebAssembly register class.
227f19ed562SDan Gohman   if (Constraint.size() == 1) {
228f19ed562SDan Gohman     switch (Constraint[0]) {
229f19ed562SDan Gohman     case 'r':
230284384b6SDan Gohman       assert(VT != MVT::iPTR && "Pointer MVT not expected here");
231284384b6SDan Gohman       if (VT.isInteger() && !VT.isVector()) {
232284384b6SDan Gohman         if (VT.getSizeInBits() <= 32)
233f19ed562SDan Gohman           return std::make_pair(0U, &WebAssembly::I32RegClass);
234284384b6SDan Gohman         if (VT.getSizeInBits() <= 64)
235a774d719SDan Gohman           return std::make_pair(0U, &WebAssembly::I64RegClass);
236284384b6SDan Gohman       }
237a774d719SDan Gohman       break;
238f19ed562SDan Gohman     default:
239f19ed562SDan Gohman       break;
240f19ed562SDan Gohman     }
241f19ed562SDan Gohman   }
242f19ed562SDan Gohman 
243f19ed562SDan Gohman   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
244f19ed562SDan Gohman }
245f19ed562SDan Gohman 
2463192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
2473192ddfeSDan Gohman   // Assume ctz is a relatively cheap operation.
2483192ddfeSDan Gohman   return true;
2493192ddfeSDan Gohman }
2503192ddfeSDan Gohman 
2513192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
2523192ddfeSDan Gohman   // Assume clz is a relatively cheap operation.
2533192ddfeSDan Gohman   return true;
2543192ddfeSDan Gohman }
2553192ddfeSDan Gohman 
25610e730a2SDan Gohman //===----------------------------------------------------------------------===//
25710e730a2SDan Gohman // WebAssembly Lowering private implementation.
25810e730a2SDan Gohman //===----------------------------------------------------------------------===//
25910e730a2SDan Gohman 
26010e730a2SDan Gohman //===----------------------------------------------------------------------===//
26110e730a2SDan Gohman // Lowering Code
26210e730a2SDan Gohman //===----------------------------------------------------------------------===//
26310e730a2SDan Gohman 
264b9073fb2SJF Bastien static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
265b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
266b9073fb2SJF Bastien   DAG.getContext()->diagnose(
267b9073fb2SJF Bastien       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
268b9073fb2SJF Bastien }
269b9073fb2SJF Bastien 
27085dbdda1SDan Gohman // Test whether the given calling convention is supported.
271a3f5ce5fSDan Gohman static bool CallingConvSupported(CallingConv::ID CallConv) {
27285dbdda1SDan Gohman   // We currently support the language-independent target-independent
2731ce2b1afSDan Gohman   // conventions. We don't yet have a way to annotate calls with properties like
2741ce2b1afSDan Gohman   // "cold", and we don't have any call-clobbered registers, so these are mostly
2751ce2b1afSDan Gohman   // all handled the same.
276a3f5ce5fSDan Gohman   return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
2771ce2b1afSDan Gohman          CallConv == CallingConv::Cold ||
2781ce2b1afSDan Gohman          CallConv == CallingConv::PreserveMost ||
2791ce2b1afSDan Gohman          CallConv == CallingConv::PreserveAll ||
2801ce2b1afSDan Gohman          CallConv == CallingConv::CXX_FAST_TLS;
28185dbdda1SDan Gohman }
28285dbdda1SDan Gohman 
283d8a9d66dSJF Bastien SDValue
284d8a9d66dSJF Bastien WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
285d8a9d66dSJF Bastien                                      SmallVectorImpl<SDValue> &InVals) const {
286d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
287d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
288d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
289d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
290d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
291d8a9d66dSJF Bastien 
292d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
29385dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
2949cc692b0SDan Gohman     fail(DL, DAG,
2959cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
2969cc692b0SDan Gohman          "calling conventions yet");
297d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
298d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
299d8a9d66dSJF Bastien 
3009cc692b0SDan Gohman   // WebAssembly doesn't currently support explicit tail calls. If they are
3019cc692b0SDan Gohman   // required, fail. Otherwise, just disable them.
3029cc692b0SDan Gohman   if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
3039cc692b0SDan Gohman        MF.getTarget().Options.GuaranteedTailCallOpt) ||
3049cc692b0SDan Gohman       (CLI.CS && CLI.CS->isMustTailCall()))
3059cc692b0SDan Gohman     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
3069cc692b0SDan Gohman   CLI.IsTailCall = false;
3079cc692b0SDan Gohman 
308d8a9d66dSJF Bastien   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
309e590b33bSDan Gohman 
310d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
311e590b33bSDan Gohman   if (Ins.size() > 1)
312e590b33bSDan Gohman     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
313e590b33bSDan Gohman 
3142d822e73SDan Gohman   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
3152d822e73SDan Gohman   for (const ISD::OutputArg &Out : Outs) {
3162d822e73SDan Gohman     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
3172d822e73SDan Gohman     assert(!Out.Flags.isNest() && "nest is not valid for return values");
3182d822e73SDan Gohman     if (Out.Flags.isInAlloca())
3192d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
3202d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegs())
3212d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
3222d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
3232d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
3242d822e73SDan Gohman   }
3252d822e73SDan Gohman 
326d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
32735bfb24cSDan Gohman   unsigned NumFixedArgs = CLI.NumFixedArgs;
32835bfb24cSDan Gohman   auto PtrVT = getPointerTy(MF.getDataLayout());
329e590b33bSDan Gohman 
330d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
331d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
332d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
333d8a9d66dSJF Bastien 
33435bfb24cSDan Gohman   if (IsVarArg) {
33535bfb24cSDan Gohman     // Outgoing non-fixed arguments are placed at the top of the stack. First
33635bfb24cSDan Gohman     // compute their offsets and the total amount of argument stack space
33735bfb24cSDan Gohman     // needed.
33835bfb24cSDan Gohman     for (SDValue Arg :
33935bfb24cSDan Gohman          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
34035bfb24cSDan Gohman       EVT VT = Arg.getValueType();
34135bfb24cSDan Gohman       assert(VT != MVT::iPTR && "Legalized args should be concrete");
34235bfb24cSDan Gohman       Type *Ty = VT.getTypeForEVT(*DAG.getContext());
34335bfb24cSDan Gohman       unsigned Offset =
34435bfb24cSDan Gohman           CCInfo.AllocateStack(MF.getDataLayout().getTypeAllocSize(Ty),
34535bfb24cSDan Gohman                                MF.getDataLayout().getABITypeAlignment(Ty));
34635bfb24cSDan Gohman       CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
34735bfb24cSDan Gohman                                         Offset, VT.getSimpleVT(),
34835bfb24cSDan Gohman                                         CCValAssign::Full));
34935bfb24cSDan Gohman     }
35035bfb24cSDan Gohman   }
35135bfb24cSDan Gohman 
35235bfb24cSDan Gohman   unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
35335bfb24cSDan Gohman 
354af111db8SJF Bastien   auto NB = DAG.getConstant(NumBytes, DL, PtrVT, true);
355af111db8SJF Bastien   Chain = DAG.getCALLSEQ_START(Chain, NB, DL);
356d8a9d66dSJF Bastien 
35735bfb24cSDan Gohman   if (IsVarArg) {
35835bfb24cSDan Gohman     // For non-fixed arguments, next emit stores to store the argument values
35935bfb24cSDan Gohman     // to the stack at the offsets computed above.
36035bfb24cSDan Gohman     SDValue SP = DAG.getCopyFromReg(
36135bfb24cSDan Gohman         Chain, DL, getStackPointerRegisterToSaveRestore(), PtrVT);
36235bfb24cSDan Gohman     unsigned ValNo = 0;
36335bfb24cSDan Gohman     SmallVector<SDValue, 8> Chains;
36435bfb24cSDan Gohman     for (SDValue Arg :
36535bfb24cSDan Gohman          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
36635bfb24cSDan Gohman       assert(ArgLocs[ValNo].getValNo() == ValNo &&
36735bfb24cSDan Gohman              "ArgLocs should remain in order and only hold varargs args");
36835bfb24cSDan Gohman       unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
36935bfb24cSDan Gohman       SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, SP,
37035bfb24cSDan Gohman                                 DAG.getConstant(Offset, DL, PtrVT));
37135bfb24cSDan Gohman       Chains.push_back(DAG.getStore(Chain, DL, Arg, Add,
37235bfb24cSDan Gohman                                     MachinePointerInfo::getStack(MF, Offset),
37335bfb24cSDan Gohman                                     false, false, 0));
37435bfb24cSDan Gohman     }
37535bfb24cSDan Gohman     if (!Chains.empty())
37635bfb24cSDan Gohman       Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
37735bfb24cSDan Gohman   }
37835bfb24cSDan Gohman 
37935bfb24cSDan Gohman   // Compute the operands for the CALLn node.
380d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
381d8a9d66dSJF Bastien   Ops.push_back(Chain);
382af111db8SJF Bastien   Ops.push_back(Callee);
38335bfb24cSDan Gohman 
38435bfb24cSDan Gohman   // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
38535bfb24cSDan Gohman   // isn't reliable.
38635bfb24cSDan Gohman   Ops.append(OutVals.begin(),
38735bfb24cSDan Gohman              IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
388d8a9d66dSJF Bastien 
389d8a9d66dSJF Bastien   SmallVector<EVT, 8> Tys;
3902d822e73SDan Gohman   for (const auto &In : Ins) {
3912d822e73SDan Gohman     if (In.Flags.isByVal())
3922d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
3932d822e73SDan Gohman     if (In.Flags.isInAlloca())
3942d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
3952d822e73SDan Gohman     if (In.Flags.isNest())
3962d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
3972d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegs())
3982d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
3992d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegsLast())
4002d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
4012d822e73SDan Gohman     // Ignore In.getOrigAlign() because all our arguments are passed in
4022d822e73SDan Gohman     // registers.
403d8a9d66dSJF Bastien     Tys.push_back(In.VT);
4042d822e73SDan Gohman   }
405d8a9d66dSJF Bastien   Tys.push_back(MVT::Other);
406af111db8SJF Bastien   SDVTList TyList = DAG.getVTList(Tys);
407f71abef7SDan Gohman   SDValue Res =
408f71abef7SDan Gohman       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
409f71abef7SDan Gohman                   DL, TyList, Ops);
410af111db8SJF Bastien   if (Ins.empty()) {
411af111db8SJF Bastien     Chain = Res;
412af111db8SJF Bastien   } else {
413d8a9d66dSJF Bastien     InVals.push_back(Res);
414d8a9d66dSJF Bastien     Chain = Res.getValue(1);
415af111db8SJF Bastien   }
416d8a9d66dSJF Bastien 
41735bfb24cSDan Gohman   SDValue Unused = DAG.getUNDEF(PtrVT);
41835bfb24cSDan Gohman   Chain = DAG.getCALLSEQ_END(Chain, NB, Unused, SDValue(), DL);
419d8a9d66dSJF Bastien 
420d8a9d66dSJF Bastien   return Chain;
421d8a9d66dSJF Bastien }
422d8a9d66dSJF Bastien 
423b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
4247a6b9825SDan Gohman     CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
4257a6b9825SDan Gohman     const SmallVectorImpl<ISD::OutputArg> &Outs,
4267a6b9825SDan Gohman     LLVMContext & /*Context*/) const {
427b9073fb2SJF Bastien   // WebAssembly can't currently handle returning tuples.
428b9073fb2SJF Bastien   return Outs.size() <= 1;
429b9073fb2SJF Bastien }
430b9073fb2SJF Bastien 
431b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
43235bfb24cSDan Gohman     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
433b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
434b9073fb2SJF Bastien     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
435b9073fb2SJF Bastien     SelectionDAG &DAG) const {
436b9073fb2SJF Bastien   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
43785dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
438b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
439b9073fb2SJF Bastien 
440600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
441600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
4424a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
443b9073fb2SJF Bastien 
444754cd11dSDan Gohman   // Record the number and types of the return values.
445754cd11dSDan Gohman   for (const ISD::OutputArg &Out : Outs) {
446ac132e93SDan Gohman     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
447ac132e93SDan Gohman     assert(!Out.Flags.isNest() && "nest is not valid for return values");
44835bfb24cSDan Gohman     assert(Out.IsFixed && "non-fixed return value is not valid");
449754cd11dSDan Gohman     if (Out.Flags.isInAlloca())
450754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
451754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegs())
452754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
453754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
454754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
455754cd11dSDan Gohman   }
456754cd11dSDan Gohman 
457b9073fb2SJF Bastien   return Chain;
458b9073fb2SJF Bastien }
459b9073fb2SJF Bastien 
460b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
46135bfb24cSDan Gohman     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
462b9073fb2SJF Bastien     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
463b9073fb2SJF Bastien     SmallVectorImpl<SDValue> &InVals) const {
464b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
465b9073fb2SJF Bastien 
46685dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
467b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
468b9073fb2SJF Bastien 
469fb3e0594SDan Gohman   // Set up the incoming ARGUMENTS value, which serves to represent the liveness
470fb3e0594SDan Gohman   // of the incoming values before they're represented by virtual registers.
471fb3e0594SDan Gohman   MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
472fb3e0594SDan Gohman 
473600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
474600aee98SJF Bastien     if (In.Flags.isByVal())
475600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
476600aee98SJF Bastien     if (In.Flags.isInAlloca())
477600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
478600aee98SJF Bastien     if (In.Flags.isNest())
479600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
480600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
481600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
482600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
483600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
4849c54d3b4SDan Gohman     // Ignore In.getOrigAlign() because all our arguments are passed in
4859c54d3b4SDan Gohman     // registers.
486d7fcc6f9SJF Bastien     InVals.push_back(
487d7fcc6f9SJF Bastien         In.Used
488d7fcc6f9SJF Bastien             ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
4895219ecf0SDan Gohman                           DAG.getTargetConstant(InVals.size(), DL, MVT::i32))
490cb7940f9SDan Gohman             : DAG.getUNDEF(In.VT));
491754cd11dSDan Gohman 
492754cd11dSDan Gohman     // Record the number and types of arguments.
493754cd11dSDan Gohman     MF.getInfo<WebAssemblyFunctionInfo>()->addParam(In.VT);
494600aee98SJF Bastien   }
495b9073fb2SJF Bastien 
49635bfb24cSDan Gohman   // Incoming varargs arguments are on the stack and will be accessed through
49735bfb24cSDan Gohman   // va_arg, so we don't need to do anything for them here.
49835bfb24cSDan Gohman 
499b9073fb2SJF Bastien   return Chain;
500b9073fb2SJF Bastien }
501b9073fb2SJF Bastien 
50210e730a2SDan Gohman //===----------------------------------------------------------------------===//
503af111db8SJF Bastien //  Custom lowering hooks.
50410e730a2SDan Gohman //===----------------------------------------------------------------------===//
50510e730a2SDan Gohman 
506af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
507af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
508af111db8SJF Bastien   switch (Op.getOpcode()) {
509af111db8SJF Bastien   default:
510af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
511af111db8SJF Bastien     return SDValue();
512af111db8SJF Bastien   case ISD::GlobalAddress:
513af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
5142c8fe6a4SDan Gohman   case ISD::ExternalSymbol:
5152c8fe6a4SDan Gohman     return LowerExternalSymbol(Op, DAG);
516950a13cfSDan Gohman   case ISD::JumpTable:
517950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
518950a13cfSDan Gohman   case ISD::BR_JT:
519950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
52035bfb24cSDan Gohman   case ISD::VASTART:
52135bfb24cSDan Gohman     return LowerVASTART(Op, DAG);
522af111db8SJF Bastien   }
523af111db8SJF Bastien }
524af111db8SJF Bastien 
525af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
526af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
527af111db8SJF Bastien   SDLoc DL(Op);
528af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
529af111db8SJF Bastien   EVT VT = Op.getValueType();
530af111db8SJF Bastien   assert(GA->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
531af111db8SJF Bastien   if (GA->getAddressSpace() != 0)
532af111db8SJF Bastien     fail(DL, DAG, "WebAssembly only expects the 0 address space");
533af111db8SJF Bastien   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
534*a4b710a7SDan Gohman                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
535*a4b710a7SDan Gohman                                                 GA->getOffset()));
536af111db8SJF Bastien }
537af111db8SJF Bastien 
5387a6b9825SDan Gohman SDValue
5397a6b9825SDan Gohman WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
5402c8fe6a4SDan Gohman                                                SelectionDAG &DAG) const {
5412c8fe6a4SDan Gohman   SDLoc DL(Op);
5422c8fe6a4SDan Gohman   const auto *ES = cast<ExternalSymbolSDNode>(Op);
5432c8fe6a4SDan Gohman   EVT VT = Op.getValueType();
5442c8fe6a4SDan Gohman   assert(ES->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
5452c8fe6a4SDan Gohman   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
5462c8fe6a4SDan Gohman                      DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
5472c8fe6a4SDan Gohman }
5482c8fe6a4SDan Gohman 
549950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
550950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
551950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
552bb7ce8e4SDan Gohman   // table operand into a TABLESWITCH instruction, rather than ever
553bb7ce8e4SDan Gohman   // materializing it in a register.
554950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
555950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
556950a13cfSDan Gohman                                 JT->getTargetFlags());
557950a13cfSDan Gohman }
558950a13cfSDan Gohman 
559950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
560950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
561950a13cfSDan Gohman   SDLoc DL(Op);
562950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
563950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
564950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
565950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
566950a13cfSDan Gohman 
567950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
568950a13cfSDan Gohman   Ops.push_back(Chain);
569950a13cfSDan Gohman   Ops.push_back(Index);
570950a13cfSDan Gohman 
571950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
572950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
573950a13cfSDan Gohman 
574950a13cfSDan Gohman   // TODO: For now, we just pick something arbitrary for a default case for now.
575950a13cfSDan Gohman   // We really want to sniff out the guard and put in the real default case (and
576950a13cfSDan Gohman   // delete the guard).
577950a13cfSDan Gohman   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
578950a13cfSDan Gohman 
579950a13cfSDan Gohman   // Add an operand for each case.
580950a13cfSDan Gohman   for (auto MBB : MBBs)
581950a13cfSDan Gohman     Ops.push_back(DAG.getBasicBlock(MBB));
582950a13cfSDan Gohman 
583bb7ce8e4SDan Gohman   return DAG.getNode(WebAssemblyISD::TABLESWITCH, DL, MVT::Other, Ops);
584950a13cfSDan Gohman }
585950a13cfSDan Gohman 
58635bfb24cSDan Gohman SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
58735bfb24cSDan Gohman                                                 SelectionDAG &DAG) const {
58835bfb24cSDan Gohman   SDLoc DL(Op);
58935bfb24cSDan Gohman   EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
59035bfb24cSDan Gohman 
59135bfb24cSDan Gohman   // The incoming non-fixed arguments are placed on the top of the stack, with
59235bfb24cSDan Gohman   // natural alignment, at the point of the call, so the base pointer is just
59335bfb24cSDan Gohman   // the current frame pointer.
59435bfb24cSDan Gohman   DAG.getMachineFunction().getFrameInfo()->setFrameAddressIsTaken(true);
59535bfb24cSDan Gohman   unsigned FP =
59635bfb24cSDan Gohman       static_cast<const WebAssemblyRegisterInfo *>(Subtarget->getRegisterInfo())
59735bfb24cSDan Gohman           ->getFrameRegister(DAG.getMachineFunction());
59835bfb24cSDan Gohman   SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FP, PtrVT);
59935bfb24cSDan Gohman   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
60035bfb24cSDan Gohman   return DAG.getStore(Op.getOperand(0), DL, FrameAddr, Op.getOperand(1),
60135bfb24cSDan Gohman                       MachinePointerInfo(SV), false, false, 0);
60235bfb24cSDan Gohman }
60335bfb24cSDan Gohman 
60410e730a2SDan Gohman //===----------------------------------------------------------------------===//
60510e730a2SDan Gohman //                          WebAssembly Optimization Hooks
60610e730a2SDan Gohman //===----------------------------------------------------------------------===//
60710e730a2SDan Gohman 
60810e730a2SDan Gohman MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
6097a6b9825SDan Gohman     const GlobalValue *GV, SectionKind /*Kind*/, Mangler & /*Mang*/,
6107a6b9825SDan Gohman     const TargetMachine & /*TM*/) const {
611e51c058eSDan Gohman   // TODO: Be more sophisticated than this.
612e51c058eSDan Gohman   return isa<Function>(GV) ? getTextSection() : getDataSection();
61310e730a2SDan Gohman }
614