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);
135*b84ae9bbSDan Gohman     // Support minnan and maxnan, which otherwise default to expand.
136*b84ae9bbSDan Gohman     setOperationAction(ISD::FMINNAN, T, Legal);
137*b84ae9bbSDan Gohman     setOperationAction(ISD::FMAXNAN, T, Legal);
138da06bce8SJF Bastien   }
13932907a6bSDan Gohman 
14032907a6bSDan Gohman   for (auto T : {MVT::i32, MVT::i64}) {
14132907a6bSDan Gohman     // Expand unavailable integer operations.
14232907a6bSDan Gohman     for (auto Op : {ISD::BSWAP, ISD::ROTL, ISD::ROTR,
14332907a6bSDan Gohman                     ISD::SMUL_LOHI, ISD::UMUL_LOHI,
14432907a6bSDan Gohman                     ISD::MULHS, ISD::MULHU, ISD::SDIVREM, ISD::UDIVREM,
14532907a6bSDan Gohman                     ISD::SHL_PARTS, ISD::SRA_PARTS, ISD::SRL_PARTS,
14632907a6bSDan Gohman                     ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
14732907a6bSDan Gohman       setOperationAction(Op, T, Expand);
14832907a6bSDan Gohman     }
14932907a6bSDan Gohman   }
15032907a6bSDan Gohman 
15132907a6bSDan Gohman   // As a special case, these operators use the type to mean the type to
15232907a6bSDan Gohman   // sign-extend from.
15332907a6bSDan Gohman   for (auto T : {MVT::i1, MVT::i8, MVT::i16})
15432907a6bSDan Gohman     setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
15532907a6bSDan Gohman 
15632907a6bSDan Gohman   // Dynamic stack allocation: use the default expansion.
15732907a6bSDan Gohman   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
15832907a6bSDan Gohman   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
1592683a553SDan Gohman   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
16073ff6afaSJF Bastien 
161950a13cfSDan Gohman   // Expand these forms; we pattern-match the forms that we can handle in isel.
162950a13cfSDan Gohman   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
163950a13cfSDan Gohman     for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
164950a13cfSDan Gohman       setOperationAction(Op, T, Expand);
165950a13cfSDan Gohman 
166950a13cfSDan Gohman   // We have custom switch handling.
167950a13cfSDan Gohman   setOperationAction(ISD::BR_JT, MVT::Other, Custom);
168950a13cfSDan Gohman 
16973ff6afaSJF Bastien   // WebAssembly doesn't have:
17073ff6afaSJF Bastien   //  - Floating-point extending loads.
17173ff6afaSJF Bastien   //  - Floating-point truncating stores.
17273ff6afaSJF Bastien   //  - i1 extending loads.
17373ff6afaSJF Bastien   setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f64, Expand);
17473ff6afaSJF Bastien   setTruncStoreAction(MVT::f64, MVT::f32, Expand);
17573ff6afaSJF Bastien   for (auto T : MVT::integer_valuetypes())
17673ff6afaSJF Bastien     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
17773ff6afaSJF Bastien       setLoadExtAction(Ext, T, MVT::i1, Promote);
178ffa143ceSDerek Schuff 
179ffa143ceSDerek Schuff   // Trap lowers to wasm unreachable
180ffa143ceSDerek Schuff   setOperationAction(ISD::TRAP, MVT::Other, Legal);
181bfaf7e15SDan Gohman }
18210e730a2SDan Gohman 
1837b63484bSDan Gohman FastISel *WebAssemblyTargetLowering::createFastISel(
1847b63484bSDan Gohman     FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
1857b63484bSDan Gohman   return WebAssembly::createFastISel(FuncInfo, LibInfo);
1867b63484bSDan Gohman }
1877b63484bSDan Gohman 
188af111db8SJF Bastien bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
189af111db8SJF Bastien     const GlobalAddressSDNode *GA) const {
190af111db8SJF Bastien   // The WebAssembly target doesn't support folding offsets into global
191af111db8SJF Bastien   // addresses.
192af111db8SJF Bastien   return false;
193af111db8SJF Bastien }
194af111db8SJF Bastien 
195fda53373SJF Bastien MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout &DL,
196fda53373SJF Bastien                                                       EVT VT) const {
197fda53373SJF Bastien   return VT.getSimpleVT();
198fda53373SJF Bastien }
199fda53373SJF Bastien 
200480c8408SJF Bastien const char *
201480c8408SJF Bastien WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
202480c8408SJF Bastien   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
203af111db8SJF Bastien   case WebAssemblyISD::FIRST_NUMBER:
204af111db8SJF Bastien     break;
205af111db8SJF Bastien #define HANDLE_NODETYPE(NODE)                                                  \
206af111db8SJF Bastien   case WebAssemblyISD::NODE:                                                   \
207af111db8SJF Bastien     return "WebAssemblyISD::" #NODE;
208af111db8SJF Bastien #include "WebAssemblyISD.def"
209af111db8SJF Bastien #undef HANDLE_NODETYPE
210480c8408SJF Bastien   }
211480c8408SJF Bastien   return nullptr;
212480c8408SJF Bastien }
213480c8408SJF Bastien 
21410e730a2SDan Gohman //===----------------------------------------------------------------------===//
21510e730a2SDan Gohman // WebAssembly Lowering private implementation.
21610e730a2SDan Gohman //===----------------------------------------------------------------------===//
21710e730a2SDan Gohman 
21810e730a2SDan Gohman //===----------------------------------------------------------------------===//
21910e730a2SDan Gohman // Lowering Code
22010e730a2SDan Gohman //===----------------------------------------------------------------------===//
22110e730a2SDan Gohman 
222b9073fb2SJF Bastien static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
223b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
224b9073fb2SJF Bastien   DAG.getContext()->diagnose(
225b9073fb2SJF Bastien       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
226b9073fb2SJF Bastien }
227b9073fb2SJF Bastien 
228d8a9d66dSJF Bastien SDValue
229d8a9d66dSJF Bastien WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
230d8a9d66dSJF Bastien                                      SmallVectorImpl<SDValue> &InVals) const {
231d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
232d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
233d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
234d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
235d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
236d8a9d66dSJF Bastien 
237d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
2389cc692b0SDan Gohman   if (CallConv != CallingConv::C &&
2399cc692b0SDan Gohman       CallConv != CallingConv::Fast &&
2409cc692b0SDan Gohman       CallConv != CallingConv::Cold)
2419cc692b0SDan Gohman     fail(DL, DAG,
2429cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
2439cc692b0SDan Gohman          "calling conventions yet");
244d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
245d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
246d8a9d66dSJF Bastien 
2479cc692b0SDan Gohman   // WebAssembly doesn't currently support explicit tail calls. If they are
2489cc692b0SDan Gohman   // required, fail. Otherwise, just disable them.
2499cc692b0SDan Gohman   if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
2509cc692b0SDan Gohman        MF.getTarget().Options.GuaranteedTailCallOpt) ||
2519cc692b0SDan Gohman       (CLI.CS && CLI.CS->isMustTailCall()))
2529cc692b0SDan Gohman     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
2539cc692b0SDan Gohman   CLI.IsTailCall = false;
2549cc692b0SDan Gohman 
255d8a9d66dSJF Bastien   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
256d8a9d66dSJF Bastien   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
257e590b33bSDan Gohman 
258d8a9d66dSJF Bastien   bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet();
259d8a9d66dSJF Bastien   if (IsStructRet)
260d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support struct return yet");
261d8a9d66dSJF Bastien 
262d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
263e590b33bSDan Gohman   if (Ins.size() > 1)
264e590b33bSDan Gohman     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
265e590b33bSDan Gohman 
266d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
267d8a9d66dSJF Bastien   if (IsVarArg)
268d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
269e590b33bSDan Gohman 
270d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
271d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
272d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
273d8a9d66dSJF Bastien   unsigned NumBytes = CCInfo.getNextStackOffset();
274d8a9d66dSJF Bastien 
275d8a9d66dSJF Bastien   auto PtrVT = getPointerTy(MF.getDataLayout());
276af111db8SJF Bastien   auto Zero = DAG.getConstant(0, DL, PtrVT, true);
277af111db8SJF Bastien   auto NB = DAG.getConstant(NumBytes, DL, PtrVT, true);
278af111db8SJF Bastien   Chain = DAG.getCALLSEQ_START(Chain, NB, DL);
279d8a9d66dSJF Bastien 
280d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
281d8a9d66dSJF Bastien   Ops.push_back(Chain);
282af111db8SJF Bastien   Ops.push_back(Callee);
283af111db8SJF Bastien   Ops.append(OutVals.begin(), OutVals.end());
284d8a9d66dSJF Bastien 
285d8a9d66dSJF Bastien   SmallVector<EVT, 8> Tys;
286af111db8SJF Bastien   for (const auto &In : Ins)
287d8a9d66dSJF Bastien     Tys.push_back(In.VT);
288d8a9d66dSJF Bastien   Tys.push_back(MVT::Other);
289af111db8SJF Bastien   SDVTList TyList = DAG.getVTList(Tys);
290f71abef7SDan Gohman   SDValue Res =
291f71abef7SDan Gohman       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
292f71abef7SDan Gohman                   DL, TyList, Ops);
293af111db8SJF Bastien   if (Ins.empty()) {
294af111db8SJF Bastien     Chain = Res;
295af111db8SJF Bastien   } else {
296d8a9d66dSJF Bastien     InVals.push_back(Res);
297d8a9d66dSJF Bastien     Chain = Res.getValue(1);
298af111db8SJF Bastien   }
299d8a9d66dSJF Bastien 
300d8a9d66dSJF Bastien   // FIXME: handle CLI.RetSExt and CLI.RetZExt?
301d8a9d66dSJF Bastien 
302af111db8SJF Bastien   Chain = DAG.getCALLSEQ_END(Chain, NB, Zero, SDValue(), DL);
303d8a9d66dSJF Bastien 
304d8a9d66dSJF Bastien   return Chain;
305d8a9d66dSJF Bastien }
306d8a9d66dSJF Bastien 
307b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
308b9073fb2SJF Bastien     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
309b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
310b9073fb2SJF Bastien   // WebAssembly can't currently handle returning tuples.
311b9073fb2SJF Bastien   return Outs.size() <= 1;
312b9073fb2SJF Bastien }
313b9073fb2SJF Bastien 
314b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
315b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
316b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
317b9073fb2SJF Bastien     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
318b9073fb2SJF Bastien     SelectionDAG &DAG) const {
319b9073fb2SJF Bastien 
320b9073fb2SJF Bastien   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
321b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
322b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
323600aee98SJF Bastien   if (IsVarArg)
324600aee98SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
325b9073fb2SJF Bastien 
326600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
327600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
3284a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
329b9073fb2SJF Bastien 
330b9073fb2SJF Bastien   return Chain;
331b9073fb2SJF Bastien }
332b9073fb2SJF Bastien 
333b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
334b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
335b9073fb2SJF Bastien     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
336b9073fb2SJF Bastien     SmallVectorImpl<SDValue> &InVals) const {
337b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
338b9073fb2SJF Bastien 
339b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
340b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
341b9073fb2SJF Bastien   if (IsVarArg)
342b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
343b9073fb2SJF Bastien   if (MF.getFunction()->hasStructRetAttr())
344b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support struct return yet");
345b9073fb2SJF Bastien 
346600aee98SJF Bastien   unsigned ArgNo = 0;
347600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
348600aee98SJF Bastien     if (In.Flags.isZExt())
349600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented zext arguments");
350600aee98SJF Bastien     if (In.Flags.isSExt())
351600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented sext arguments");
352600aee98SJF Bastien     if (In.Flags.isInReg())
353600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inreg arguments");
354600aee98SJF Bastien     if (In.Flags.isSRet())
355600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented sret arguments");
356600aee98SJF Bastien     if (In.Flags.isByVal())
357600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
358600aee98SJF Bastien     if (In.Flags.isInAlloca())
359600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
360600aee98SJF Bastien     if (In.Flags.isNest())
361600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
362600aee98SJF Bastien     if (In.Flags.isReturned())
363600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented returned arguments");
364600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
365600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
366600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
367600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
368600aee98SJF Bastien     if (In.Flags.isSplit())
369600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented split arguments");
370600aee98SJF Bastien     // FIXME Do something with In.getOrigAlign()?
371d7fcc6f9SJF Bastien     InVals.push_back(
372d7fcc6f9SJF Bastien         In.Used
373d7fcc6f9SJF Bastien             ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
374d7fcc6f9SJF Bastien                           DAG.getTargetConstant(ArgNo, DL, MVT::i32))
375d7fcc6f9SJF Bastien             : DAG.getNode(ISD::UNDEF, DL, In.VT));
376d7fcc6f9SJF Bastien     ++ArgNo;
377600aee98SJF Bastien   }
378b9073fb2SJF Bastien 
379e51c058eSDan Gohman   // Record the number of arguments, since argument indices and local variable
380e51c058eSDan Gohman   // indices are in the same index space.
381e51c058eSDan Gohman   MF.getInfo<WebAssemblyFunctionInfo>()->setNumArguments(ArgNo);
382e51c058eSDan Gohman 
383b9073fb2SJF Bastien   return Chain;
384b9073fb2SJF Bastien }
385b9073fb2SJF Bastien 
38610e730a2SDan Gohman //===----------------------------------------------------------------------===//
387af111db8SJF Bastien //  Custom lowering hooks.
38810e730a2SDan Gohman //===----------------------------------------------------------------------===//
38910e730a2SDan Gohman 
390af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
391af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
392af111db8SJF Bastien   switch (Op.getOpcode()) {
393af111db8SJF Bastien   default:
394af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
395af111db8SJF Bastien     return SDValue();
396af111db8SJF Bastien   case ISD::GlobalAddress:
397af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
398950a13cfSDan Gohman   case ISD::JumpTable:
399950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
400950a13cfSDan Gohman   case ISD::BR_JT:
401950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
402af111db8SJF Bastien   }
403af111db8SJF Bastien }
404af111db8SJF Bastien 
405af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
406af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
407af111db8SJF Bastien   SDLoc DL(Op);
408af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
409af111db8SJF Bastien   EVT VT = Op.getValueType();
410af111db8SJF Bastien   assert(GA->getOffset() == 0 &&
411af111db8SJF Bastien          "offsets on global addresses are forbidden by isOffsetFoldingLegal");
412af111db8SJF Bastien   assert(GA->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
413af111db8SJF Bastien   if (GA->getAddressSpace() != 0)
414af111db8SJF Bastien     fail(DL, DAG, "WebAssembly only expects the 0 address space");
415af111db8SJF Bastien   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
416af111db8SJF Bastien                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT));
417af111db8SJF Bastien }
418af111db8SJF Bastien 
419950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
420950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
421950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
422950a13cfSDan Gohman   // table operand into a SWITCH instruction, rather than ever materializing
423950a13cfSDan Gohman   // it in a register.
424950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
425950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
426950a13cfSDan Gohman                                 JT->getTargetFlags());
427950a13cfSDan Gohman }
428950a13cfSDan Gohman 
429950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
430950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
431950a13cfSDan Gohman   SDLoc DL(Op);
432950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
433950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
434950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
435950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
436950a13cfSDan Gohman 
437950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
438950a13cfSDan Gohman   Ops.push_back(Chain);
439950a13cfSDan Gohman   Ops.push_back(Index);
440950a13cfSDan Gohman 
441950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
442950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
443950a13cfSDan Gohman 
444950a13cfSDan Gohman   // TODO: For now, we just pick something arbitrary for a default case for now.
445950a13cfSDan Gohman   // We really want to sniff out the guard and put in the real default case (and
446950a13cfSDan Gohman   // delete the guard).
447950a13cfSDan Gohman   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
448950a13cfSDan Gohman 
449950a13cfSDan Gohman   // Add an operand for each case.
450950a13cfSDan Gohman   for (auto MBB : MBBs)
451950a13cfSDan Gohman     Ops.push_back(DAG.getBasicBlock(MBB));
452950a13cfSDan Gohman 
453950a13cfSDan Gohman   return DAG.getNode(WebAssemblyISD::SWITCH, DL, MVT::Other, Ops);
454950a13cfSDan Gohman }
455950a13cfSDan Gohman 
45610e730a2SDan Gohman //===----------------------------------------------------------------------===//
45710e730a2SDan Gohman //                          WebAssembly Optimization Hooks
45810e730a2SDan Gohman //===----------------------------------------------------------------------===//
45910e730a2SDan Gohman 
46010e730a2SDan Gohman MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
46110e730a2SDan Gohman     const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
46210e730a2SDan Gohman     const TargetMachine &TM) const {
463e51c058eSDan Gohman   // TODO: Be more sophisticated than this.
464e51c058eSDan Gohman   return isa<Function>(GV) ? getTextSection() : getDataSection();
46510e730a2SDan Gohman }
466