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"
35b9073fb2SJF Bastien 
3610e730a2SDan Gohman using namespace llvm;
3710e730a2SDan Gohman 
3810e730a2SDan Gohman #define DEBUG_TYPE "wasm-lower"
3910e730a2SDan Gohman 
40b9073fb2SJF Bastien namespace {
41b9073fb2SJF Bastien // Diagnostic information for unimplemented or unsupported feature reporting.
42b9073fb2SJF Bastien // FIXME copied from BPF and AMDGPU.
43b9073fb2SJF Bastien class DiagnosticInfoUnsupported : 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);
118950a13cfSDan Gohman   setOperationAction(ISD::JumpTable, MVTPtr, Custom);
119af111db8SJF Bastien 
120da06bce8SJF Bastien   for (auto T : {MVT::f32, MVT::f64}) {
121da06bce8SJF Bastien     // Don't expand the floating-point types to constant pools.
122da06bce8SJF Bastien     setOperationAction(ISD::ConstantFP, T, Legal);
123da06bce8SJF Bastien     // Expand floating-point comparisons.
124da06bce8SJF Bastien     for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
125da06bce8SJF Bastien                     ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
126da06bce8SJF Bastien       setCondCodeAction(CC, T, Expand);
12732907a6bSDan Gohman     // Expand floating-point library function operators.
128896e53faSDan Gohman     for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOWI, ISD::FPOW})
12932907a6bSDan Gohman       setOperationAction(Op, T, Expand);
130896e53faSDan Gohman     // Note supported floating-point library function operators that otherwise
131896e53faSDan Gohman     // default to expand.
132896e53faSDan Gohman     for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
133896e53faSDan Gohman                     ISD::FRINT})
134896e53faSDan Gohman       setOperationAction(Op, T, Legal);
135da06bce8SJF Bastien   }
13632907a6bSDan Gohman 
13732907a6bSDan Gohman   for (auto T : {MVT::i32, MVT::i64}) {
13832907a6bSDan Gohman     // Expand unavailable integer operations.
13932907a6bSDan Gohman     for (auto Op : {ISD::BSWAP, ISD::ROTL, ISD::ROTR,
14032907a6bSDan Gohman                     ISD::SMUL_LOHI, ISD::UMUL_LOHI,
14132907a6bSDan Gohman                     ISD::MULHS, ISD::MULHU, ISD::SDIVREM, ISD::UDIVREM,
14232907a6bSDan Gohman                     ISD::SHL_PARTS, ISD::SRA_PARTS, ISD::SRL_PARTS,
14332907a6bSDan Gohman                     ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
14432907a6bSDan Gohman       setOperationAction(Op, T, Expand);
14532907a6bSDan Gohman     }
14632907a6bSDan Gohman   }
14732907a6bSDan Gohman 
14832907a6bSDan Gohman   // As a special case, these operators use the type to mean the type to
14932907a6bSDan Gohman   // sign-extend from.
15032907a6bSDan Gohman   for (auto T : {MVT::i1, MVT::i8, MVT::i16})
15132907a6bSDan Gohman     setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
15232907a6bSDan Gohman 
15332907a6bSDan Gohman   // Dynamic stack allocation: use the default expansion.
15432907a6bSDan Gohman   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
15532907a6bSDan Gohman   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
1562683a553SDan Gohman   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
15773ff6afaSJF Bastien 
158950a13cfSDan Gohman   // Expand these forms; we pattern-match the forms that we can handle in isel.
159950a13cfSDan Gohman   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
160950a13cfSDan Gohman     for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
161950a13cfSDan Gohman       setOperationAction(Op, T, Expand);
162950a13cfSDan Gohman 
163950a13cfSDan Gohman   // We have custom switch handling.
164950a13cfSDan Gohman   setOperationAction(ISD::BR_JT, MVT::Other, Custom);
165950a13cfSDan Gohman 
16673ff6afaSJF Bastien   // WebAssembly doesn't have:
16773ff6afaSJF Bastien   //  - Floating-point extending loads.
16873ff6afaSJF Bastien   //  - Floating-point truncating stores.
16973ff6afaSJF Bastien   //  - i1 extending loads.
17073ff6afaSJF Bastien   setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f64, Expand);
17173ff6afaSJF Bastien   setTruncStoreAction(MVT::f64, MVT::f32, Expand);
17273ff6afaSJF Bastien   for (auto T : MVT::integer_valuetypes())
17373ff6afaSJF Bastien     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
17473ff6afaSJF Bastien       setLoadExtAction(Ext, T, MVT::i1, Promote);
175bfaf7e15SDan Gohman }
17610e730a2SDan Gohman 
1777b63484bSDan Gohman FastISel *WebAssemblyTargetLowering::createFastISel(
1787b63484bSDan Gohman     FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
1797b63484bSDan Gohman   return WebAssembly::createFastISel(FuncInfo, LibInfo);
1807b63484bSDan Gohman }
1817b63484bSDan Gohman 
182af111db8SJF Bastien bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
183af111db8SJF Bastien     const GlobalAddressSDNode *GA) const {
184af111db8SJF Bastien   // The WebAssembly target doesn't support folding offsets into global
185af111db8SJF Bastien   // addresses.
186af111db8SJF Bastien   return false;
187af111db8SJF Bastien }
188af111db8SJF Bastien 
189fda53373SJF Bastien MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout &DL,
190fda53373SJF Bastien                                                       EVT VT) const {
191fda53373SJF Bastien   return VT.getSimpleVT();
192fda53373SJF Bastien }
193fda53373SJF Bastien 
194480c8408SJF Bastien const char *
195480c8408SJF Bastien WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
196480c8408SJF Bastien   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
197af111db8SJF Bastien   case WebAssemblyISD::FIRST_NUMBER:
198af111db8SJF Bastien     break;
199af111db8SJF Bastien #define HANDLE_NODETYPE(NODE)                                                  \
200af111db8SJF Bastien   case WebAssemblyISD::NODE:                                                   \
201af111db8SJF Bastien     return "WebAssemblyISD::" #NODE;
202af111db8SJF Bastien #include "WebAssemblyISD.def"
203af111db8SJF Bastien #undef HANDLE_NODETYPE
204480c8408SJF Bastien   }
205480c8408SJF Bastien   return nullptr;
206480c8408SJF Bastien }
207480c8408SJF Bastien 
20810e730a2SDan Gohman //===----------------------------------------------------------------------===//
20910e730a2SDan Gohman // WebAssembly Lowering private implementation.
21010e730a2SDan Gohman //===----------------------------------------------------------------------===//
21110e730a2SDan Gohman 
21210e730a2SDan Gohman //===----------------------------------------------------------------------===//
21310e730a2SDan Gohman // Lowering Code
21410e730a2SDan Gohman //===----------------------------------------------------------------------===//
21510e730a2SDan Gohman 
216b9073fb2SJF Bastien static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
217b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
218b9073fb2SJF Bastien   DAG.getContext()->diagnose(
219b9073fb2SJF Bastien       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
220b9073fb2SJF Bastien }
221b9073fb2SJF Bastien 
222d8a9d66dSJF Bastien SDValue
223d8a9d66dSJF Bastien WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
224d8a9d66dSJF Bastien                                      SmallVectorImpl<SDValue> &InVals) const {
225d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
226d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
227d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
228d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
229d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
230d8a9d66dSJF Bastien 
231d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
2329cc692b0SDan Gohman   if (CallConv != CallingConv::C &&
2339cc692b0SDan Gohman       CallConv != CallingConv::Fast &&
2349cc692b0SDan Gohman       CallConv != CallingConv::Cold)
2359cc692b0SDan Gohman     fail(DL, DAG,
2369cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
2379cc692b0SDan Gohman          "calling conventions yet");
238d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
239d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
240d8a9d66dSJF Bastien 
2419cc692b0SDan Gohman   // WebAssembly doesn't currently support explicit tail calls. If they are
2429cc692b0SDan Gohman   // required, fail. Otherwise, just disable them.
2439cc692b0SDan Gohman   if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
2449cc692b0SDan Gohman        MF.getTarget().Options.GuaranteedTailCallOpt) ||
2459cc692b0SDan Gohman       (CLI.CS && CLI.CS->isMustTailCall()))
2469cc692b0SDan Gohman     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
2479cc692b0SDan Gohman   CLI.IsTailCall = false;
2489cc692b0SDan Gohman 
249d8a9d66dSJF Bastien   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
250d8a9d66dSJF Bastien   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
251e590b33bSDan Gohman 
252d8a9d66dSJF Bastien   bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet();
253d8a9d66dSJF Bastien   if (IsStructRet)
254d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support struct return yet");
255d8a9d66dSJF Bastien 
256d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
257e590b33bSDan Gohman   if (Ins.size() > 1)
258e590b33bSDan Gohman     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
259e590b33bSDan Gohman 
260d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
261d8a9d66dSJF Bastien   if (IsVarArg)
262d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
263e590b33bSDan Gohman 
264d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
265d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
266d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
267d8a9d66dSJF Bastien   unsigned NumBytes = CCInfo.getNextStackOffset();
268d8a9d66dSJF Bastien 
269d8a9d66dSJF Bastien   auto PtrVT = getPointerTy(MF.getDataLayout());
270af111db8SJF Bastien   auto Zero = DAG.getConstant(0, DL, PtrVT, true);
271af111db8SJF Bastien   auto NB = DAG.getConstant(NumBytes, DL, PtrVT, true);
272af111db8SJF Bastien   Chain = DAG.getCALLSEQ_START(Chain, NB, DL);
273d8a9d66dSJF Bastien 
274d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
275d8a9d66dSJF Bastien   Ops.push_back(Chain);
276af111db8SJF Bastien   Ops.push_back(Callee);
277af111db8SJF Bastien   Ops.append(OutVals.begin(), OutVals.end());
278d8a9d66dSJF Bastien 
279d8a9d66dSJF Bastien   SmallVector<EVT, 8> Tys;
280af111db8SJF Bastien   for (const auto &In : Ins)
281d8a9d66dSJF Bastien     Tys.push_back(In.VT);
282d8a9d66dSJF Bastien   Tys.push_back(MVT::Other);
283af111db8SJF Bastien   SDVTList TyList = DAG.getVTList(Tys);
284f71abef7SDan Gohman   SDValue Res =
285f71abef7SDan Gohman       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
286f71abef7SDan Gohman                   DL, TyList, Ops);
287af111db8SJF Bastien   if (Ins.empty()) {
288af111db8SJF Bastien     Chain = Res;
289af111db8SJF Bastien   } else {
290d8a9d66dSJF Bastien     InVals.push_back(Res);
291d8a9d66dSJF Bastien     Chain = Res.getValue(1);
292af111db8SJF Bastien   }
293d8a9d66dSJF Bastien 
294d8a9d66dSJF Bastien   // FIXME: handle CLI.RetSExt and CLI.RetZExt?
295d8a9d66dSJF Bastien 
296af111db8SJF Bastien   Chain = DAG.getCALLSEQ_END(Chain, NB, Zero, SDValue(), DL);
297d8a9d66dSJF Bastien 
298d8a9d66dSJF Bastien   return Chain;
299d8a9d66dSJF Bastien }
300d8a9d66dSJF Bastien 
301b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
302b9073fb2SJF Bastien     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
303b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
304b9073fb2SJF Bastien   // WebAssembly can't currently handle returning tuples.
305b9073fb2SJF Bastien   return Outs.size() <= 1;
306b9073fb2SJF Bastien }
307b9073fb2SJF Bastien 
308b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
309b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
310b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
311b9073fb2SJF Bastien     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
312b9073fb2SJF Bastien     SelectionDAG &DAG) const {
313b9073fb2SJF Bastien 
314b9073fb2SJF Bastien   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
315b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
316b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
317600aee98SJF Bastien   if (IsVarArg)
318600aee98SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
319b9073fb2SJF Bastien 
320600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
321600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
3224a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
323b9073fb2SJF Bastien 
324b9073fb2SJF Bastien   return Chain;
325b9073fb2SJF Bastien }
326b9073fb2SJF Bastien 
327b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
328b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
329b9073fb2SJF Bastien     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
330b9073fb2SJF Bastien     SmallVectorImpl<SDValue> &InVals) const {
331b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
332b9073fb2SJF Bastien 
333b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
334b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
335b9073fb2SJF Bastien   if (IsVarArg)
336b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
337b9073fb2SJF Bastien   if (MF.getFunction()->hasStructRetAttr())
338b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support struct return yet");
339b9073fb2SJF Bastien 
340600aee98SJF Bastien   unsigned ArgNo = 0;
341600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
342600aee98SJF Bastien     if (In.Flags.isZExt())
343600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented zext arguments");
344600aee98SJF Bastien     if (In.Flags.isSExt())
345600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented sext arguments");
346600aee98SJF Bastien     if (In.Flags.isInReg())
347600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inreg arguments");
348600aee98SJF Bastien     if (In.Flags.isSRet())
349600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented sret arguments");
350600aee98SJF Bastien     if (In.Flags.isByVal())
351600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
352600aee98SJF Bastien     if (In.Flags.isInAlloca())
353600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
354600aee98SJF Bastien     if (In.Flags.isNest())
355600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
356600aee98SJF Bastien     if (In.Flags.isReturned())
357600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented returned arguments");
358600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
359600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
360600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
361600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
362600aee98SJF Bastien     if (In.Flags.isSplit())
363600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented split arguments");
364600aee98SJF Bastien     // FIXME Do something with In.getOrigAlign()?
365d7fcc6f9SJF Bastien     InVals.push_back(
366d7fcc6f9SJF Bastien         In.Used
367d7fcc6f9SJF Bastien             ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
368d7fcc6f9SJF Bastien                           DAG.getTargetConstant(ArgNo, DL, MVT::i32))
369d7fcc6f9SJF Bastien             : DAG.getNode(ISD::UNDEF, DL, In.VT));
370d7fcc6f9SJF Bastien     ++ArgNo;
371600aee98SJF Bastien   }
372b9073fb2SJF Bastien 
373*e51c058eSDan Gohman   // Record the number of arguments, since argument indices and local variable
374*e51c058eSDan Gohman   // indices are in the same index space.
375*e51c058eSDan Gohman   MF.getInfo<WebAssemblyFunctionInfo>()->setNumArguments(ArgNo);
376*e51c058eSDan Gohman 
377b9073fb2SJF Bastien   return Chain;
378b9073fb2SJF Bastien }
379b9073fb2SJF Bastien 
38010e730a2SDan Gohman //===----------------------------------------------------------------------===//
381af111db8SJF Bastien //  Custom lowering hooks.
38210e730a2SDan Gohman //===----------------------------------------------------------------------===//
38310e730a2SDan Gohman 
384af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
385af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
386af111db8SJF Bastien   switch (Op.getOpcode()) {
387af111db8SJF Bastien   default:
388af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
389af111db8SJF Bastien     return SDValue();
390af111db8SJF Bastien   case ISD::GlobalAddress:
391af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
392950a13cfSDan Gohman   case ISD::JumpTable:
393950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
394950a13cfSDan Gohman   case ISD::BR_JT:
395950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
396af111db8SJF Bastien   }
397af111db8SJF Bastien }
398af111db8SJF Bastien 
399af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
400af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
401af111db8SJF Bastien   SDLoc DL(Op);
402af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
403af111db8SJF Bastien   EVT VT = Op.getValueType();
404af111db8SJF Bastien   assert(GA->getOffset() == 0 &&
405af111db8SJF Bastien          "offsets on global addresses are forbidden by isOffsetFoldingLegal");
406af111db8SJF Bastien   assert(GA->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
407af111db8SJF Bastien   if (GA->getAddressSpace() != 0)
408af111db8SJF Bastien     fail(DL, DAG, "WebAssembly only expects the 0 address space");
409af111db8SJF Bastien   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
410af111db8SJF Bastien                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT));
411af111db8SJF Bastien }
412af111db8SJF Bastien 
413950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
414950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
415950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
416950a13cfSDan Gohman   // table operand into a SWITCH instruction, rather than ever materializing
417950a13cfSDan Gohman   // it in a register.
418950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
419950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
420950a13cfSDan Gohman                                 JT->getTargetFlags());
421950a13cfSDan Gohman }
422950a13cfSDan Gohman 
423950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
424950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
425950a13cfSDan Gohman   SDLoc DL(Op);
426950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
427950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
428950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
429950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
430950a13cfSDan Gohman 
431950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
432950a13cfSDan Gohman   Ops.push_back(Chain);
433950a13cfSDan Gohman   Ops.push_back(Index);
434950a13cfSDan Gohman 
435950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
436950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
437950a13cfSDan Gohman 
438950a13cfSDan Gohman   // TODO: For now, we just pick something arbitrary for a default case for now.
439950a13cfSDan Gohman   // We really want to sniff out the guard and put in the real default case (and
440950a13cfSDan Gohman   // delete the guard).
441950a13cfSDan Gohman   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
442950a13cfSDan Gohman 
443950a13cfSDan Gohman   // Add an operand for each case.
444950a13cfSDan Gohman   for (auto MBB : MBBs)
445950a13cfSDan Gohman     Ops.push_back(DAG.getBasicBlock(MBB));
446950a13cfSDan Gohman 
447950a13cfSDan Gohman   return DAG.getNode(WebAssemblyISD::SWITCH, DL, MVT::Other, Ops);
448950a13cfSDan Gohman }
449950a13cfSDan Gohman 
45010e730a2SDan Gohman //===----------------------------------------------------------------------===//
45110e730a2SDan Gohman //                          WebAssembly Optimization Hooks
45210e730a2SDan Gohman //===----------------------------------------------------------------------===//
45310e730a2SDan Gohman 
45410e730a2SDan Gohman MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
45510e730a2SDan Gohman     const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
45610e730a2SDan Gohman     const TargetMachine &TM) const {
457*e51c058eSDan Gohman   // TODO: Be more sophisticated than this.
458*e51c058eSDan Gohman   return isa<Function>(GV) ? getTextSection() : getDataSection();
45910e730a2SDan Gohman }
460