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.
136*ebb23545SDan Gohman     for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOWI, ISD::FPOW,
137*ebb23545SDan 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 {
199af111db8SJF Bastien   // The WebAssembly target doesn't support folding offsets into global
200af111db8SJF Bastien   // addresses.
201af111db8SJF Bastien   return false;
202af111db8SJF Bastien }
203af111db8SJF Bastien 
2047a6b9825SDan Gohman MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
205fda53373SJF Bastien                                                       EVT VT) const {
206fda53373SJF Bastien   return VT.getSimpleVT();
207fda53373SJF Bastien }
208fda53373SJF Bastien 
209480c8408SJF Bastien const char *
210480c8408SJF Bastien WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
211480c8408SJF Bastien   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
212af111db8SJF Bastien   case WebAssemblyISD::FIRST_NUMBER:
213af111db8SJF Bastien     break;
214af111db8SJF Bastien #define HANDLE_NODETYPE(NODE)                                                  \
215af111db8SJF Bastien   case WebAssemblyISD::NODE:                                                   \
216af111db8SJF Bastien     return "WebAssemblyISD::" #NODE;
217af111db8SJF Bastien #include "WebAssemblyISD.def"
218af111db8SJF Bastien #undef HANDLE_NODETYPE
219480c8408SJF Bastien   }
220480c8408SJF Bastien   return nullptr;
221480c8408SJF Bastien }
222480c8408SJF Bastien 
223f19ed562SDan Gohman std::pair<unsigned, const TargetRegisterClass *>
224f19ed562SDan Gohman WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
225f19ed562SDan Gohman     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
226f19ed562SDan Gohman   // First, see if this is a constraint that directly corresponds to a
227f19ed562SDan Gohman   // WebAssembly register class.
228f19ed562SDan Gohman   if (Constraint.size() == 1) {
229f19ed562SDan Gohman     switch (Constraint[0]) {
230f19ed562SDan Gohman     case 'r':
231a774d719SDan Gohman       if (VT == MVT::i32)
232f19ed562SDan Gohman         return std::make_pair(0U, &WebAssembly::I32RegClass);
233a774d719SDan Gohman       if (VT == MVT::i64)
234a774d719SDan Gohman         return std::make_pair(0U, &WebAssembly::I64RegClass);
235a774d719SDan Gohman       break;
236f19ed562SDan Gohman     default:
237f19ed562SDan Gohman       break;
238f19ed562SDan Gohman     }
239f19ed562SDan Gohman   }
240f19ed562SDan Gohman 
241f19ed562SDan Gohman   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
242f19ed562SDan Gohman }
243f19ed562SDan Gohman 
2443192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
2453192ddfeSDan Gohman   // Assume ctz is a relatively cheap operation.
2463192ddfeSDan Gohman   return true;
2473192ddfeSDan Gohman }
2483192ddfeSDan Gohman 
2493192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
2503192ddfeSDan Gohman   // Assume clz is a relatively cheap operation.
2513192ddfeSDan Gohman   return true;
2523192ddfeSDan Gohman }
2533192ddfeSDan Gohman 
25410e730a2SDan Gohman //===----------------------------------------------------------------------===//
25510e730a2SDan Gohman // WebAssembly Lowering private implementation.
25610e730a2SDan Gohman //===----------------------------------------------------------------------===//
25710e730a2SDan Gohman 
25810e730a2SDan Gohman //===----------------------------------------------------------------------===//
25910e730a2SDan Gohman // Lowering Code
26010e730a2SDan Gohman //===----------------------------------------------------------------------===//
26110e730a2SDan Gohman 
262b9073fb2SJF Bastien static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
263b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
264b9073fb2SJF Bastien   DAG.getContext()->diagnose(
265b9073fb2SJF Bastien       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
266b9073fb2SJF Bastien }
267b9073fb2SJF Bastien 
26885dbdda1SDan Gohman // Test whether the given calling convention is supported.
269a3f5ce5fSDan Gohman static bool CallingConvSupported(CallingConv::ID CallConv) {
27085dbdda1SDan Gohman   // We currently support the language-independent target-independent
2711ce2b1afSDan Gohman   // conventions. We don't yet have a way to annotate calls with properties like
2721ce2b1afSDan Gohman   // "cold", and we don't have any call-clobbered registers, so these are mostly
2731ce2b1afSDan Gohman   // all handled the same.
274a3f5ce5fSDan Gohman   return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
2751ce2b1afSDan Gohman          CallConv == CallingConv::Cold ||
2761ce2b1afSDan Gohman          CallConv == CallingConv::PreserveMost ||
2771ce2b1afSDan Gohman          CallConv == CallingConv::PreserveAll ||
2781ce2b1afSDan Gohman          CallConv == CallingConv::CXX_FAST_TLS;
27985dbdda1SDan Gohman }
28085dbdda1SDan Gohman 
281d8a9d66dSJF Bastien SDValue
282d8a9d66dSJF Bastien WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
283d8a9d66dSJF Bastien                                      SmallVectorImpl<SDValue> &InVals) const {
284d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
285d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
286d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
287d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
288d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
289d8a9d66dSJF Bastien 
290d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
29185dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
2929cc692b0SDan Gohman     fail(DL, DAG,
2939cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
2949cc692b0SDan Gohman          "calling conventions yet");
295d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
296d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
297d8a9d66dSJF Bastien 
2989cc692b0SDan Gohman   // WebAssembly doesn't currently support explicit tail calls. If they are
2999cc692b0SDan Gohman   // required, fail. Otherwise, just disable them.
3009cc692b0SDan Gohman   if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
3019cc692b0SDan Gohman        MF.getTarget().Options.GuaranteedTailCallOpt) ||
3029cc692b0SDan Gohman       (CLI.CS && CLI.CS->isMustTailCall()))
3039cc692b0SDan Gohman     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
3049cc692b0SDan Gohman   CLI.IsTailCall = false;
3059cc692b0SDan Gohman 
306d8a9d66dSJF Bastien   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
307e590b33bSDan Gohman 
308d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
309e590b33bSDan Gohman   if (Ins.size() > 1)
310e590b33bSDan Gohman     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
311e590b33bSDan Gohman 
3122d822e73SDan Gohman   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
3132d822e73SDan Gohman   for (const ISD::OutputArg &Out : Outs) {
3142d822e73SDan Gohman     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
3152d822e73SDan Gohman     assert(!Out.Flags.isNest() && "nest is not valid for return values");
3162d822e73SDan Gohman     if (Out.Flags.isInAlloca())
3172d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
3182d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegs())
3192d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
3202d822e73SDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
3212d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
3222d822e73SDan Gohman   }
3232d822e73SDan Gohman 
324d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
32535bfb24cSDan Gohman   unsigned NumFixedArgs = CLI.NumFixedArgs;
32635bfb24cSDan Gohman   auto PtrVT = getPointerTy(MF.getDataLayout());
327e590b33bSDan Gohman 
328d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
329d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
330d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
331d8a9d66dSJF Bastien 
33235bfb24cSDan Gohman   if (IsVarArg) {
33335bfb24cSDan Gohman     // Outgoing non-fixed arguments are placed at the top of the stack. First
33435bfb24cSDan Gohman     // compute their offsets and the total amount of argument stack space
33535bfb24cSDan Gohman     // needed.
33635bfb24cSDan Gohman     for (SDValue Arg :
33735bfb24cSDan Gohman          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
33835bfb24cSDan Gohman       EVT VT = Arg.getValueType();
33935bfb24cSDan Gohman       assert(VT != MVT::iPTR && "Legalized args should be concrete");
34035bfb24cSDan Gohman       Type *Ty = VT.getTypeForEVT(*DAG.getContext());
34135bfb24cSDan Gohman       unsigned Offset =
34235bfb24cSDan Gohman           CCInfo.AllocateStack(MF.getDataLayout().getTypeAllocSize(Ty),
34335bfb24cSDan Gohman                                MF.getDataLayout().getABITypeAlignment(Ty));
34435bfb24cSDan Gohman       CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
34535bfb24cSDan Gohman                                         Offset, VT.getSimpleVT(),
34635bfb24cSDan Gohman                                         CCValAssign::Full));
34735bfb24cSDan Gohman     }
34835bfb24cSDan Gohman   }
34935bfb24cSDan Gohman 
35035bfb24cSDan Gohman   unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
35135bfb24cSDan Gohman 
352af111db8SJF Bastien   auto NB = DAG.getConstant(NumBytes, DL, PtrVT, true);
353af111db8SJF Bastien   Chain = DAG.getCALLSEQ_START(Chain, NB, DL);
354d8a9d66dSJF Bastien 
35535bfb24cSDan Gohman   if (IsVarArg) {
35635bfb24cSDan Gohman     // For non-fixed arguments, next emit stores to store the argument values
35735bfb24cSDan Gohman     // to the stack at the offsets computed above.
35835bfb24cSDan Gohman     SDValue SP = DAG.getCopyFromReg(
35935bfb24cSDan Gohman         Chain, DL, getStackPointerRegisterToSaveRestore(), PtrVT);
36035bfb24cSDan Gohman     unsigned ValNo = 0;
36135bfb24cSDan Gohman     SmallVector<SDValue, 8> Chains;
36235bfb24cSDan Gohman     for (SDValue Arg :
36335bfb24cSDan Gohman          make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
36435bfb24cSDan Gohman       assert(ArgLocs[ValNo].getValNo() == ValNo &&
36535bfb24cSDan Gohman              "ArgLocs should remain in order and only hold varargs args");
36635bfb24cSDan Gohman       unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
36735bfb24cSDan Gohman       SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, SP,
36835bfb24cSDan Gohman                                 DAG.getConstant(Offset, DL, PtrVT));
36935bfb24cSDan Gohman       Chains.push_back(DAG.getStore(Chain, DL, Arg, Add,
37035bfb24cSDan Gohman                                     MachinePointerInfo::getStack(MF, Offset),
37135bfb24cSDan Gohman                                     false, false, 0));
37235bfb24cSDan Gohman     }
37335bfb24cSDan Gohman     if (!Chains.empty())
37435bfb24cSDan Gohman       Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
37535bfb24cSDan Gohman   }
37635bfb24cSDan Gohman 
37735bfb24cSDan Gohman   // Compute the operands for the CALLn node.
378d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
379d8a9d66dSJF Bastien   Ops.push_back(Chain);
380af111db8SJF Bastien   Ops.push_back(Callee);
38135bfb24cSDan Gohman 
38235bfb24cSDan Gohman   // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
38335bfb24cSDan Gohman   // isn't reliable.
38435bfb24cSDan Gohman   Ops.append(OutVals.begin(),
38535bfb24cSDan Gohman              IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
386d8a9d66dSJF Bastien 
387d8a9d66dSJF Bastien   SmallVector<EVT, 8> Tys;
3882d822e73SDan Gohman   for (const auto &In : Ins) {
3892d822e73SDan Gohman     if (In.Flags.isByVal())
3902d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
3912d822e73SDan Gohman     if (In.Flags.isInAlloca())
3922d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
3932d822e73SDan Gohman     if (In.Flags.isNest())
3942d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
3952d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegs())
3962d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
3972d822e73SDan Gohman     if (In.Flags.isInConsecutiveRegsLast())
3982d822e73SDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
3992d822e73SDan Gohman     // Ignore In.getOrigAlign() because all our arguments are passed in
4002d822e73SDan Gohman     // registers.
401d8a9d66dSJF Bastien     Tys.push_back(In.VT);
4022d822e73SDan Gohman   }
403d8a9d66dSJF Bastien   Tys.push_back(MVT::Other);
404af111db8SJF Bastien   SDVTList TyList = DAG.getVTList(Tys);
405f71abef7SDan Gohman   SDValue Res =
406f71abef7SDan Gohman       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
407f71abef7SDan Gohman                   DL, TyList, Ops);
408af111db8SJF Bastien   if (Ins.empty()) {
409af111db8SJF Bastien     Chain = Res;
410af111db8SJF Bastien   } else {
411d8a9d66dSJF Bastien     InVals.push_back(Res);
412d8a9d66dSJF Bastien     Chain = Res.getValue(1);
413af111db8SJF Bastien   }
414d8a9d66dSJF Bastien 
41535bfb24cSDan Gohman   SDValue Unused = DAG.getUNDEF(PtrVT);
41635bfb24cSDan Gohman   Chain = DAG.getCALLSEQ_END(Chain, NB, Unused, SDValue(), DL);
417d8a9d66dSJF Bastien 
418d8a9d66dSJF Bastien   return Chain;
419d8a9d66dSJF Bastien }
420d8a9d66dSJF Bastien 
421b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
4227a6b9825SDan Gohman     CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
4237a6b9825SDan Gohman     const SmallVectorImpl<ISD::OutputArg> &Outs,
4247a6b9825SDan Gohman     LLVMContext & /*Context*/) const {
425b9073fb2SJF Bastien   // WebAssembly can't currently handle returning tuples.
426b9073fb2SJF Bastien   return Outs.size() <= 1;
427b9073fb2SJF Bastien }
428b9073fb2SJF Bastien 
429b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
43035bfb24cSDan Gohman     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
431b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
432b9073fb2SJF Bastien     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
433b9073fb2SJF Bastien     SelectionDAG &DAG) const {
434b9073fb2SJF Bastien   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
43585dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
436b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
437b9073fb2SJF Bastien 
438600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
439600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
4404a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
441b9073fb2SJF Bastien 
442754cd11dSDan Gohman   // Record the number and types of the return values.
443754cd11dSDan Gohman   for (const ISD::OutputArg &Out : Outs) {
444ac132e93SDan Gohman     assert(!Out.Flags.isByVal() && "byval is not valid for return values");
445ac132e93SDan Gohman     assert(!Out.Flags.isNest() && "nest is not valid for return values");
44635bfb24cSDan Gohman     assert(Out.IsFixed && "non-fixed return value is not valid");
447754cd11dSDan Gohman     if (Out.Flags.isInAlloca())
448754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
449754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegs())
450754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
451754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
452754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
453754cd11dSDan Gohman   }
454754cd11dSDan Gohman 
455b9073fb2SJF Bastien   return Chain;
456b9073fb2SJF Bastien }
457b9073fb2SJF Bastien 
458b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
45935bfb24cSDan Gohman     SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
460b9073fb2SJF Bastien     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
461b9073fb2SJF Bastien     SmallVectorImpl<SDValue> &InVals) const {
462b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
463b9073fb2SJF Bastien 
46485dbdda1SDan Gohman   if (!CallingConvSupported(CallConv))
465b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
466b9073fb2SJF Bastien 
467fb3e0594SDan Gohman   // Set up the incoming ARGUMENTS value, which serves to represent the liveness
468fb3e0594SDan Gohman   // of the incoming values before they're represented by virtual registers.
469fb3e0594SDan Gohman   MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
470fb3e0594SDan Gohman 
471600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
472600aee98SJF Bastien     if (In.Flags.isByVal())
473600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
474600aee98SJF Bastien     if (In.Flags.isInAlloca())
475600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
476600aee98SJF Bastien     if (In.Flags.isNest())
477600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
478600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
479600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
480600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
481600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
4829c54d3b4SDan Gohman     // Ignore In.getOrigAlign() because all our arguments are passed in
4839c54d3b4SDan Gohman     // registers.
484d7fcc6f9SJF Bastien     InVals.push_back(
485d7fcc6f9SJF Bastien         In.Used
486d7fcc6f9SJF Bastien             ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
4875219ecf0SDan Gohman                           DAG.getTargetConstant(InVals.size(), DL, MVT::i32))
488cb7940f9SDan Gohman             : DAG.getUNDEF(In.VT));
489754cd11dSDan Gohman 
490754cd11dSDan Gohman     // Record the number and types of arguments.
491754cd11dSDan Gohman     MF.getInfo<WebAssemblyFunctionInfo>()->addParam(In.VT);
492600aee98SJF Bastien   }
493b9073fb2SJF Bastien 
49435bfb24cSDan Gohman   // Incoming varargs arguments are on the stack and will be accessed through
49535bfb24cSDan Gohman   // va_arg, so we don't need to do anything for them here.
49635bfb24cSDan Gohman 
497b9073fb2SJF Bastien   return Chain;
498b9073fb2SJF Bastien }
499b9073fb2SJF Bastien 
50010e730a2SDan Gohman //===----------------------------------------------------------------------===//
501af111db8SJF Bastien //  Custom lowering hooks.
50210e730a2SDan Gohman //===----------------------------------------------------------------------===//
50310e730a2SDan Gohman 
504af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
505af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
506af111db8SJF Bastien   switch (Op.getOpcode()) {
507af111db8SJF Bastien   default:
508af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
509af111db8SJF Bastien     return SDValue();
510af111db8SJF Bastien   case ISD::GlobalAddress:
511af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
5122c8fe6a4SDan Gohman   case ISD::ExternalSymbol:
5132c8fe6a4SDan Gohman     return LowerExternalSymbol(Op, DAG);
514950a13cfSDan Gohman   case ISD::JumpTable:
515950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
516950a13cfSDan Gohman   case ISD::BR_JT:
517950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
51835bfb24cSDan Gohman   case ISD::VASTART:
51935bfb24cSDan Gohman     return LowerVASTART(Op, DAG);
520af111db8SJF Bastien   }
521af111db8SJF Bastien }
522af111db8SJF Bastien 
523af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
524af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
525af111db8SJF Bastien   SDLoc DL(Op);
526af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
527af111db8SJF Bastien   EVT VT = Op.getValueType();
528af111db8SJF Bastien   assert(GA->getOffset() == 0 &&
529af111db8SJF Bastien          "offsets on global addresses are forbidden by isOffsetFoldingLegal");
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,
534af111db8SJF Bastien                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT));
535af111db8SJF Bastien }
536af111db8SJF Bastien 
5377a6b9825SDan Gohman SDValue
5387a6b9825SDan Gohman WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
5392c8fe6a4SDan Gohman                                                SelectionDAG &DAG) const {
5402c8fe6a4SDan Gohman   SDLoc DL(Op);
5412c8fe6a4SDan Gohman   const auto *ES = cast<ExternalSymbolSDNode>(Op);
5422c8fe6a4SDan Gohman   EVT VT = Op.getValueType();
5432c8fe6a4SDan Gohman   assert(ES->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
5442c8fe6a4SDan Gohman   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
5452c8fe6a4SDan Gohman                      DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
5462c8fe6a4SDan Gohman }
5472c8fe6a4SDan Gohman 
548950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
549950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
550950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
551bb7ce8e4SDan Gohman   // table operand into a TABLESWITCH instruction, rather than ever
552bb7ce8e4SDan Gohman   // materializing it in a register.
553950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
554950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
555950a13cfSDan Gohman                                 JT->getTargetFlags());
556950a13cfSDan Gohman }
557950a13cfSDan Gohman 
558950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
559950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
560950a13cfSDan Gohman   SDLoc DL(Op);
561950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
562950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
563950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
564950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
565950a13cfSDan Gohman 
566950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
567950a13cfSDan Gohman   Ops.push_back(Chain);
568950a13cfSDan Gohman   Ops.push_back(Index);
569950a13cfSDan Gohman 
570950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
571950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
572950a13cfSDan Gohman 
573950a13cfSDan Gohman   // TODO: For now, we just pick something arbitrary for a default case for now.
574950a13cfSDan Gohman   // We really want to sniff out the guard and put in the real default case (and
575950a13cfSDan Gohman   // delete the guard).
576950a13cfSDan Gohman   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
577950a13cfSDan Gohman 
578950a13cfSDan Gohman   // Add an operand for each case.
579950a13cfSDan Gohman   for (auto MBB : MBBs)
580950a13cfSDan Gohman     Ops.push_back(DAG.getBasicBlock(MBB));
581950a13cfSDan Gohman 
582bb7ce8e4SDan Gohman   return DAG.getNode(WebAssemblyISD::TABLESWITCH, DL, MVT::Other, Ops);
583950a13cfSDan Gohman }
584950a13cfSDan Gohman 
58535bfb24cSDan Gohman SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
58635bfb24cSDan Gohman                                                 SelectionDAG &DAG) const {
58735bfb24cSDan Gohman   SDLoc DL(Op);
58835bfb24cSDan Gohman   EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
58935bfb24cSDan Gohman 
59035bfb24cSDan Gohman   // The incoming non-fixed arguments are placed on the top of the stack, with
59135bfb24cSDan Gohman   // natural alignment, at the point of the call, so the base pointer is just
59235bfb24cSDan Gohman   // the current frame pointer.
59335bfb24cSDan Gohman   DAG.getMachineFunction().getFrameInfo()->setFrameAddressIsTaken(true);
59435bfb24cSDan Gohman   unsigned FP =
59535bfb24cSDan Gohman       static_cast<const WebAssemblyRegisterInfo *>(Subtarget->getRegisterInfo())
59635bfb24cSDan Gohman           ->getFrameRegister(DAG.getMachineFunction());
59735bfb24cSDan Gohman   SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FP, PtrVT);
59835bfb24cSDan Gohman   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
59935bfb24cSDan Gohman   return DAG.getStore(Op.getOperand(0), DL, FrameAddr, Op.getOperand(1),
60035bfb24cSDan Gohman                       MachinePointerInfo(SV), false, false, 0);
60135bfb24cSDan Gohman }
60235bfb24cSDan Gohman 
60310e730a2SDan Gohman //===----------------------------------------------------------------------===//
60410e730a2SDan Gohman //                          WebAssembly Optimization Hooks
60510e730a2SDan Gohman //===----------------------------------------------------------------------===//
60610e730a2SDan Gohman 
60710e730a2SDan Gohman MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
6087a6b9825SDan Gohman     const GlobalValue *GV, SectionKind /*Kind*/, Mangler & /*Mang*/,
6097a6b9825SDan Gohman     const TargetMachine & /*TM*/) const {
610e51c058eSDan Gohman   // TODO: Be more sophisticated than this.
611e51c058eSDan Gohman   return isa<Function>(GV) ? getTextSection() : getDataSection();
61210e730a2SDan Gohman }
613