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.
41b9073fb2SJF Bastien // FIXME copied from BPF and AMDGPU.
42*fd4a88c3SDan Gohman class DiagnosticInfoUnsupported final : public DiagnosticInfo {
43b9073fb2SJF Bastien private:
44b9073fb2SJF Bastien   // Debug location where this diagnostic is triggered.
45b9073fb2SJF Bastien   DebugLoc DLoc;
46b9073fb2SJF Bastien   const Twine &Description;
47b9073fb2SJF Bastien   const Function &Fn;
48b9073fb2SJF Bastien   SDValue Value;
49b9073fb2SJF Bastien 
50b9073fb2SJF Bastien   static int KindID;
51b9073fb2SJF Bastien 
52b9073fb2SJF Bastien   static int getKindID() {
53b9073fb2SJF Bastien     if (KindID == 0)
54b9073fb2SJF Bastien       KindID = llvm::getNextAvailablePluginDiagnosticKind();
55b9073fb2SJF Bastien     return KindID;
56b9073fb2SJF Bastien   }
57b9073fb2SJF Bastien 
58b9073fb2SJF Bastien public:
59b9073fb2SJF Bastien   DiagnosticInfoUnsupported(SDLoc DLoc, const Function &Fn, const Twine &Desc,
60b9073fb2SJF Bastien                             SDValue Value)
61b9073fb2SJF Bastien       : DiagnosticInfo(getKindID(), DS_Error), DLoc(DLoc.getDebugLoc()),
62b9073fb2SJF Bastien         Description(Desc), Fn(Fn), Value(Value) {}
63b9073fb2SJF Bastien 
64b9073fb2SJF Bastien   void print(DiagnosticPrinter &DP) const override {
65b9073fb2SJF Bastien     std::string Str;
66b9073fb2SJF Bastien     raw_string_ostream OS(Str);
67b9073fb2SJF Bastien 
68b9073fb2SJF Bastien     if (DLoc) {
69b9073fb2SJF Bastien       auto DIL = DLoc.get();
70b9073fb2SJF Bastien       StringRef Filename = DIL->getFilename();
71b9073fb2SJF Bastien       unsigned Line = DIL->getLine();
72b9073fb2SJF Bastien       unsigned Column = DIL->getColumn();
73b9073fb2SJF Bastien       OS << Filename << ':' << Line << ':' << Column << ' ';
74b9073fb2SJF Bastien     }
75b9073fb2SJF Bastien 
76b9073fb2SJF Bastien     OS << "in function " << Fn.getName() << ' ' << *Fn.getFunctionType() << '\n'
77b9073fb2SJF Bastien        << Description;
78b9073fb2SJF Bastien     if (Value)
79b9073fb2SJF Bastien       Value->print(OS);
80b9073fb2SJF Bastien     OS << '\n';
81b9073fb2SJF Bastien     OS.flush();
82b9073fb2SJF Bastien     DP << Str;
83b9073fb2SJF Bastien   }
84b9073fb2SJF Bastien 
85b9073fb2SJF Bastien   static bool classof(const DiagnosticInfo *DI) {
86b9073fb2SJF Bastien     return DI->getKind() == getKindID();
87b9073fb2SJF Bastien   }
88b9073fb2SJF Bastien };
89b9073fb2SJF Bastien 
90b9073fb2SJF Bastien int DiagnosticInfoUnsupported::KindID = 0;
91b9073fb2SJF Bastien } // end anonymous namespace
92b9073fb2SJF Bastien 
9310e730a2SDan Gohman WebAssemblyTargetLowering::WebAssemblyTargetLowering(
9410e730a2SDan Gohman     const TargetMachine &TM, const WebAssemblySubtarget &STI)
95bfaf7e15SDan Gohman     : TargetLowering(TM), Subtarget(&STI) {
96af111db8SJF Bastien   auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
97af111db8SJF Bastien 
9871d29aceSJF Bastien   // Booleans always contain 0 or 1.
9971d29aceSJF Bastien   setBooleanContents(ZeroOrOneBooleanContent);
100bfaf7e15SDan Gohman   // WebAssembly does not produce floating-point exceptions on normal floating
101bfaf7e15SDan Gohman   // point operations.
102bfaf7e15SDan Gohman   setHasFloatingPointExceptions(false);
103489abd70SDan Gohman   // We don't know the microarchitecture here, so just reduce register pressure.
104489abd70SDan Gohman   setSchedulingPreference(Sched::RegPressure);
105b9073fb2SJF Bastien   // Tell ISel that we have a stack pointer.
106b9073fb2SJF Bastien   setStackPointerRegisterToSaveRestore(
107b9073fb2SJF Bastien       Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
108b9073fb2SJF Bastien   // Set up the register classes.
109d0bf9812SDan Gohman   addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
110d0bf9812SDan Gohman   addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
111d0bf9812SDan Gohman   addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
112d0bf9812SDan Gohman   addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
113b9073fb2SJF Bastien   // Compute derived properties from the register classes.
114b9073fb2SJF Bastien   computeRegisterProperties(Subtarget->getRegisterInfo());
115b9073fb2SJF Bastien 
116af111db8SJF Bastien   setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
117950a13cfSDan Gohman   setOperationAction(ISD::JumpTable, MVTPtr, Custom);
118af111db8SJF Bastien 
119da06bce8SJF Bastien   for (auto T : {MVT::f32, MVT::f64}) {
120da06bce8SJF Bastien     // Don't expand the floating-point types to constant pools.
121da06bce8SJF Bastien     setOperationAction(ISD::ConstantFP, T, Legal);
122da06bce8SJF Bastien     // Expand floating-point comparisons.
123da06bce8SJF Bastien     for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
124da06bce8SJF Bastien                     ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
125da06bce8SJF Bastien       setCondCodeAction(CC, T, Expand);
12632907a6bSDan Gohman     // Expand floating-point library function operators.
127896e53faSDan Gohman     for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOWI, ISD::FPOW})
12832907a6bSDan Gohman       setOperationAction(Op, T, Expand);
129896e53faSDan Gohman     // Note supported floating-point library function operators that otherwise
130896e53faSDan Gohman     // default to expand.
131896e53faSDan Gohman     for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
132896e53faSDan Gohman                     ISD::FRINT})
133896e53faSDan Gohman       setOperationAction(Op, T, Legal);
134b84ae9bbSDan Gohman     // Support minnan and maxnan, which otherwise default to expand.
135b84ae9bbSDan Gohman     setOperationAction(ISD::FMINNAN, T, Legal);
136b84ae9bbSDan Gohman     setOperationAction(ISD::FMAXNAN, T, Legal);
137da06bce8SJF Bastien   }
13832907a6bSDan Gohman 
13932907a6bSDan Gohman   for (auto T : {MVT::i32, MVT::i64}) {
14032907a6bSDan Gohman     // Expand unavailable integer operations.
14132907a6bSDan Gohman     for (auto Op : {ISD::BSWAP, ISD::ROTL, ISD::ROTR,
14232907a6bSDan Gohman                     ISD::SMUL_LOHI, ISD::UMUL_LOHI,
14332907a6bSDan Gohman                     ISD::MULHS, ISD::MULHU, ISD::SDIVREM, ISD::UDIVREM,
14432907a6bSDan Gohman                     ISD::SHL_PARTS, ISD::SRA_PARTS, ISD::SRL_PARTS,
14532907a6bSDan Gohman                     ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
14632907a6bSDan Gohman       setOperationAction(Op, T, Expand);
14732907a6bSDan Gohman     }
14832907a6bSDan Gohman   }
14932907a6bSDan Gohman 
15032907a6bSDan Gohman   // As a special case, these operators use the type to mean the type to
15132907a6bSDan Gohman   // sign-extend from.
15232907a6bSDan Gohman   for (auto T : {MVT::i1, MVT::i8, MVT::i16})
15332907a6bSDan Gohman     setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
15432907a6bSDan Gohman 
15532907a6bSDan Gohman   // Dynamic stack allocation: use the default expansion.
15632907a6bSDan Gohman   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
15732907a6bSDan Gohman   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
1582683a553SDan Gohman   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
15973ff6afaSJF Bastien 
160950a13cfSDan Gohman   // Expand these forms; we pattern-match the forms that we can handle in isel.
161950a13cfSDan Gohman   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
162950a13cfSDan Gohman     for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
163950a13cfSDan Gohman       setOperationAction(Op, T, Expand);
164950a13cfSDan Gohman 
165950a13cfSDan Gohman   // We have custom switch handling.
166950a13cfSDan Gohman   setOperationAction(ISD::BR_JT, MVT::Other, Custom);
167950a13cfSDan Gohman 
16873ff6afaSJF Bastien   // WebAssembly doesn't have:
16973ff6afaSJF Bastien   //  - Floating-point extending loads.
17073ff6afaSJF Bastien   //  - Floating-point truncating stores.
17173ff6afaSJF Bastien   //  - i1 extending loads.
17273ff6afaSJF Bastien   setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f64, Expand);
17373ff6afaSJF Bastien   setTruncStoreAction(MVT::f64, MVT::f32, Expand);
17473ff6afaSJF Bastien   for (auto T : MVT::integer_valuetypes())
17573ff6afaSJF Bastien     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
17673ff6afaSJF Bastien       setLoadExtAction(Ext, T, MVT::i1, Promote);
177ffa143ceSDerek Schuff 
178ffa143ceSDerek Schuff   // Trap lowers to wasm unreachable
179ffa143ceSDerek Schuff   setOperationAction(ISD::TRAP, MVT::Other, Legal);
180bfaf7e15SDan Gohman }
18110e730a2SDan Gohman 
1827b63484bSDan Gohman FastISel *WebAssemblyTargetLowering::createFastISel(
1837b63484bSDan Gohman     FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
1847b63484bSDan Gohman   return WebAssembly::createFastISel(FuncInfo, LibInfo);
1857b63484bSDan Gohman }
1867b63484bSDan Gohman 
187af111db8SJF Bastien bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
188af111db8SJF Bastien     const GlobalAddressSDNode *GA) const {
189af111db8SJF Bastien   // The WebAssembly target doesn't support folding offsets into global
190af111db8SJF Bastien   // addresses.
191af111db8SJF Bastien   return false;
192af111db8SJF Bastien }
193af111db8SJF Bastien 
194fda53373SJF Bastien MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout &DL,
195fda53373SJF Bastien                                                       EVT VT) const {
196fda53373SJF Bastien   return VT.getSimpleVT();
197fda53373SJF Bastien }
198fda53373SJF Bastien 
199480c8408SJF Bastien const char *
200480c8408SJF Bastien WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
201480c8408SJF Bastien   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
202af111db8SJF Bastien   case WebAssemblyISD::FIRST_NUMBER:
203af111db8SJF Bastien     break;
204af111db8SJF Bastien #define HANDLE_NODETYPE(NODE)                                                  \
205af111db8SJF Bastien   case WebAssemblyISD::NODE:                                                   \
206af111db8SJF Bastien     return "WebAssemblyISD::" #NODE;
207af111db8SJF Bastien #include "WebAssemblyISD.def"
208af111db8SJF Bastien #undef HANDLE_NODETYPE
209480c8408SJF Bastien   }
210480c8408SJF Bastien   return nullptr;
211480c8408SJF Bastien }
212480c8408SJF Bastien 
213f19ed562SDan Gohman std::pair<unsigned, const TargetRegisterClass *>
214f19ed562SDan Gohman WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
215f19ed562SDan Gohman     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
216f19ed562SDan Gohman   // First, see if this is a constraint that directly corresponds to a
217f19ed562SDan Gohman   // WebAssembly register class.
218f19ed562SDan Gohman   if (Constraint.size() == 1) {
219f19ed562SDan Gohman     switch (Constraint[0]) {
220f19ed562SDan Gohman     case 'r':
221f19ed562SDan Gohman       return std::make_pair(0U, &WebAssembly::I32RegClass);
222f19ed562SDan Gohman     default:
223f19ed562SDan Gohman       break;
224f19ed562SDan Gohman     }
225f19ed562SDan Gohman   }
226f19ed562SDan Gohman 
227f19ed562SDan Gohman   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
228f19ed562SDan Gohman }
229f19ed562SDan Gohman 
2303192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
2313192ddfeSDan Gohman   // Assume ctz is a relatively cheap operation.
2323192ddfeSDan Gohman   return true;
2333192ddfeSDan Gohman }
2343192ddfeSDan Gohman 
2353192ddfeSDan Gohman bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
2363192ddfeSDan Gohman   // Assume clz is a relatively cheap operation.
2373192ddfeSDan Gohman   return true;
2383192ddfeSDan Gohman }
2393192ddfeSDan Gohman 
24010e730a2SDan Gohman //===----------------------------------------------------------------------===//
24110e730a2SDan Gohman // WebAssembly Lowering private implementation.
24210e730a2SDan Gohman //===----------------------------------------------------------------------===//
24310e730a2SDan Gohman 
24410e730a2SDan Gohman //===----------------------------------------------------------------------===//
24510e730a2SDan Gohman // Lowering Code
24610e730a2SDan Gohman //===----------------------------------------------------------------------===//
24710e730a2SDan Gohman 
248b9073fb2SJF Bastien static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
249b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
250b9073fb2SJF Bastien   DAG.getContext()->diagnose(
251b9073fb2SJF Bastien       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
252b9073fb2SJF Bastien }
253b9073fb2SJF Bastien 
254d8a9d66dSJF Bastien SDValue
255d8a9d66dSJF Bastien WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
256d8a9d66dSJF Bastien                                      SmallVectorImpl<SDValue> &InVals) const {
257d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
258d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
259d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
260d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
261d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
262d8a9d66dSJF Bastien 
263d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
2649cc692b0SDan Gohman   if (CallConv != CallingConv::C &&
2659cc692b0SDan Gohman       CallConv != CallingConv::Fast &&
2669cc692b0SDan Gohman       CallConv != CallingConv::Cold)
2679cc692b0SDan Gohman     fail(DL, DAG,
2689cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
2699cc692b0SDan Gohman          "calling conventions yet");
270d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
271d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
272d8a9d66dSJF Bastien 
2739cc692b0SDan Gohman   // WebAssembly doesn't currently support explicit tail calls. If they are
2749cc692b0SDan Gohman   // required, fail. Otherwise, just disable them.
2759cc692b0SDan Gohman   if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
2769cc692b0SDan Gohman        MF.getTarget().Options.GuaranteedTailCallOpt) ||
2779cc692b0SDan Gohman       (CLI.CS && CLI.CS->isMustTailCall()))
2789cc692b0SDan Gohman     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
2799cc692b0SDan Gohman   CLI.IsTailCall = false;
2809cc692b0SDan Gohman 
281d8a9d66dSJF Bastien   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
282e590b33bSDan Gohman 
283d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
284e590b33bSDan Gohman   if (Ins.size() > 1)
285e590b33bSDan Gohman     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
286e590b33bSDan Gohman 
287d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
288d8a9d66dSJF Bastien   if (IsVarArg)
289d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
290e590b33bSDan Gohman 
291d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
292d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
293d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
294d8a9d66dSJF Bastien   unsigned NumBytes = CCInfo.getNextStackOffset();
295d8a9d66dSJF Bastien 
296d8a9d66dSJF Bastien   auto PtrVT = getPointerTy(MF.getDataLayout());
297af111db8SJF Bastien   auto Zero = DAG.getConstant(0, DL, PtrVT, true);
298af111db8SJF Bastien   auto NB = DAG.getConstant(NumBytes, DL, PtrVT, true);
299af111db8SJF Bastien   Chain = DAG.getCALLSEQ_START(Chain, NB, DL);
300d8a9d66dSJF Bastien 
301d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
302d8a9d66dSJF Bastien   Ops.push_back(Chain);
303af111db8SJF Bastien   Ops.push_back(Callee);
304af111db8SJF Bastien   Ops.append(OutVals.begin(), OutVals.end());
305d8a9d66dSJF Bastien 
306d8a9d66dSJF Bastien   SmallVector<EVT, 8> Tys;
307af111db8SJF Bastien   for (const auto &In : Ins)
308d8a9d66dSJF Bastien     Tys.push_back(In.VT);
309d8a9d66dSJF Bastien   Tys.push_back(MVT::Other);
310af111db8SJF Bastien   SDVTList TyList = DAG.getVTList(Tys);
311f71abef7SDan Gohman   SDValue Res =
312f71abef7SDan Gohman       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
313f71abef7SDan Gohman                   DL, TyList, Ops);
314af111db8SJF Bastien   if (Ins.empty()) {
315af111db8SJF Bastien     Chain = Res;
316af111db8SJF Bastien   } else {
317d8a9d66dSJF Bastien     InVals.push_back(Res);
318d8a9d66dSJF Bastien     Chain = Res.getValue(1);
319af111db8SJF Bastien   }
320d8a9d66dSJF Bastien 
321af111db8SJF Bastien   Chain = DAG.getCALLSEQ_END(Chain, NB, Zero, SDValue(), DL);
322d8a9d66dSJF Bastien 
323d8a9d66dSJF Bastien   return Chain;
324d8a9d66dSJF Bastien }
325d8a9d66dSJF Bastien 
326b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
327b9073fb2SJF Bastien     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
328b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
329b9073fb2SJF Bastien   // WebAssembly can't currently handle returning tuples.
330b9073fb2SJF Bastien   return Outs.size() <= 1;
331b9073fb2SJF Bastien }
332b9073fb2SJF Bastien 
333b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
334b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
335b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
336b9073fb2SJF Bastien     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
337b9073fb2SJF Bastien     SelectionDAG &DAG) const {
338b9073fb2SJF Bastien   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
339b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
340b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
341600aee98SJF Bastien   if (IsVarArg)
342600aee98SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
343b9073fb2SJF Bastien 
344600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
345600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
3464a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
347b9073fb2SJF Bastien 
348754cd11dSDan Gohman   // Record the number and types of the return values.
349754cd11dSDan Gohman   for (const ISD::OutputArg &Out : Outs) {
350754cd11dSDan Gohman     if (Out.Flags.isByVal())
351754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented byval results");
352754cd11dSDan Gohman     if (Out.Flags.isInAlloca())
353754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
354754cd11dSDan Gohman     if (Out.Flags.isNest())
355754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented nest results");
356754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegs())
357754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
358754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
359754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
360754cd11dSDan Gohman     if (!Out.IsFixed)
361754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly doesn't support non-fixed results yet");
362754cd11dSDan Gohman   }
363754cd11dSDan Gohman 
364b9073fb2SJF Bastien   return Chain;
365b9073fb2SJF Bastien }
366b9073fb2SJF Bastien 
367b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
368b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
369b9073fb2SJF Bastien     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
370b9073fb2SJF Bastien     SmallVectorImpl<SDValue> &InVals) const {
371b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
372b9073fb2SJF Bastien 
373b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
374b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
375b9073fb2SJF Bastien   if (IsVarArg)
376b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
377b9073fb2SJF Bastien 
378600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
379600aee98SJF Bastien     if (In.Flags.isByVal())
380600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
381600aee98SJF Bastien     if (In.Flags.isInAlloca())
382600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
383600aee98SJF Bastien     if (In.Flags.isNest())
384600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
385600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
386600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
387600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
388600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
389600aee98SJF Bastien     // FIXME Do something with In.getOrigAlign()?
390d7fcc6f9SJF Bastien     InVals.push_back(
391d7fcc6f9SJF Bastien         In.Used
392d7fcc6f9SJF Bastien             ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
3935219ecf0SDan Gohman                           DAG.getTargetConstant(InVals.size(), DL, MVT::i32))
394d7fcc6f9SJF Bastien             : DAG.getNode(ISD::UNDEF, DL, In.VT));
395754cd11dSDan Gohman 
396754cd11dSDan Gohman     // Record the number and types of arguments.
397754cd11dSDan Gohman     MF.getInfo<WebAssemblyFunctionInfo>()->addParam(In.VT);
398600aee98SJF Bastien   }
399b9073fb2SJF Bastien 
400b9073fb2SJF Bastien   return Chain;
401b9073fb2SJF Bastien }
402b9073fb2SJF Bastien 
40310e730a2SDan Gohman //===----------------------------------------------------------------------===//
404af111db8SJF Bastien //  Custom lowering hooks.
40510e730a2SDan Gohman //===----------------------------------------------------------------------===//
40610e730a2SDan Gohman 
407af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
408af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
409af111db8SJF Bastien   switch (Op.getOpcode()) {
410af111db8SJF Bastien   default:
411af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
412af111db8SJF Bastien     return SDValue();
413af111db8SJF Bastien   case ISD::GlobalAddress:
414af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
415950a13cfSDan Gohman   case ISD::JumpTable:
416950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
417950a13cfSDan Gohman   case ISD::BR_JT:
418950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
419af111db8SJF Bastien   }
420af111db8SJF Bastien }
421af111db8SJF Bastien 
422af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
423af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
424af111db8SJF Bastien   SDLoc DL(Op);
425af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
426af111db8SJF Bastien   EVT VT = Op.getValueType();
427af111db8SJF Bastien   assert(GA->getOffset() == 0 &&
428af111db8SJF Bastien          "offsets on global addresses are forbidden by isOffsetFoldingLegal");
429af111db8SJF Bastien   assert(GA->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
430af111db8SJF Bastien   if (GA->getAddressSpace() != 0)
431af111db8SJF Bastien     fail(DL, DAG, "WebAssembly only expects the 0 address space");
432af111db8SJF Bastien   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
433af111db8SJF Bastien                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT));
434af111db8SJF Bastien }
435af111db8SJF Bastien 
436950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
437950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
438950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
439bb7ce8e4SDan Gohman   // table operand into a TABLESWITCH instruction, rather than ever
440bb7ce8e4SDan Gohman   // materializing it in a register.
441950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
442950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
443950a13cfSDan Gohman                                 JT->getTargetFlags());
444950a13cfSDan Gohman }
445950a13cfSDan Gohman 
446950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
447950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
448950a13cfSDan Gohman   SDLoc DL(Op);
449950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
450950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
451950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
452950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
453950a13cfSDan Gohman 
454950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
455950a13cfSDan Gohman   Ops.push_back(Chain);
456950a13cfSDan Gohman   Ops.push_back(Index);
457950a13cfSDan Gohman 
458950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
459950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
460950a13cfSDan Gohman 
461950a13cfSDan Gohman   // TODO: For now, we just pick something arbitrary for a default case for now.
462950a13cfSDan Gohman   // We really want to sniff out the guard and put in the real default case (and
463950a13cfSDan Gohman   // delete the guard).
464950a13cfSDan Gohman   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
465950a13cfSDan Gohman 
466950a13cfSDan Gohman   // Add an operand for each case.
467950a13cfSDan Gohman   for (auto MBB : MBBs)
468950a13cfSDan Gohman     Ops.push_back(DAG.getBasicBlock(MBB));
469950a13cfSDan Gohman 
470bb7ce8e4SDan Gohman   return DAG.getNode(WebAssemblyISD::TABLESWITCH, DL, MVT::Other, Ops);
471950a13cfSDan Gohman }
472950a13cfSDan Gohman 
47310e730a2SDan Gohman //===----------------------------------------------------------------------===//
47410e730a2SDan Gohman //                          WebAssembly Optimization Hooks
47510e730a2SDan Gohman //===----------------------------------------------------------------------===//
47610e730a2SDan Gohman 
47710e730a2SDan Gohman MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
47810e730a2SDan Gohman     const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
47910e730a2SDan Gohman     const TargetMachine &TM) const {
480e51c058eSDan Gohman   // TODO: Be more sophisticated than this.
481e51c058eSDan Gohman   return isa<Function>(GV) ? getTextSection() : getDataSection();
48210e730a2SDan Gohman }
483