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);
135b84ae9bbSDan Gohman     // Support minnan and maxnan, which otherwise default to expand.
136b84ae9bbSDan Gohman     setOperationAction(ISD::FMINNAN, T, Legal);
137b84ae9bbSDan 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 
214f19ed562SDan Gohman std::pair<unsigned, const TargetRegisterClass *>
215f19ed562SDan Gohman WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
216f19ed562SDan Gohman     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
217f19ed562SDan Gohman   // First, see if this is a constraint that directly corresponds to a
218f19ed562SDan Gohman   // WebAssembly register class.
219f19ed562SDan Gohman   if (Constraint.size() == 1) {
220f19ed562SDan Gohman     switch (Constraint[0]) {
221f19ed562SDan Gohman     case 'r':
222f19ed562SDan Gohman       return std::make_pair(0U, &WebAssembly::I32RegClass);
223f19ed562SDan Gohman     default:
224f19ed562SDan Gohman       break;
225f19ed562SDan Gohman     }
226f19ed562SDan Gohman   }
227f19ed562SDan Gohman 
228f19ed562SDan Gohman   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
229f19ed562SDan Gohman }
230f19ed562SDan Gohman 
23110e730a2SDan Gohman //===----------------------------------------------------------------------===//
23210e730a2SDan Gohman // WebAssembly Lowering private implementation.
23310e730a2SDan Gohman //===----------------------------------------------------------------------===//
23410e730a2SDan Gohman 
23510e730a2SDan Gohman //===----------------------------------------------------------------------===//
23610e730a2SDan Gohman // Lowering Code
23710e730a2SDan Gohman //===----------------------------------------------------------------------===//
23810e730a2SDan Gohman 
239b9073fb2SJF Bastien static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
240b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
241b9073fb2SJF Bastien   DAG.getContext()->diagnose(
242b9073fb2SJF Bastien       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
243b9073fb2SJF Bastien }
244b9073fb2SJF Bastien 
245d8a9d66dSJF Bastien SDValue
246d8a9d66dSJF Bastien WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
247d8a9d66dSJF Bastien                                      SmallVectorImpl<SDValue> &InVals) const {
248d8a9d66dSJF Bastien   SelectionDAG &DAG = CLI.DAG;
249d8a9d66dSJF Bastien   SDLoc DL = CLI.DL;
250d8a9d66dSJF Bastien   SDValue Chain = CLI.Chain;
251d8a9d66dSJF Bastien   SDValue Callee = CLI.Callee;
252d8a9d66dSJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
253d8a9d66dSJF Bastien 
254d8a9d66dSJF Bastien   CallingConv::ID CallConv = CLI.CallConv;
2559cc692b0SDan Gohman   if (CallConv != CallingConv::C &&
2569cc692b0SDan Gohman       CallConv != CallingConv::Fast &&
2579cc692b0SDan Gohman       CallConv != CallingConv::Cold)
2589cc692b0SDan Gohman     fail(DL, DAG,
2599cc692b0SDan Gohman          "WebAssembly doesn't support language-specific or target-specific "
2609cc692b0SDan Gohman          "calling conventions yet");
261d8a9d66dSJF Bastien   if (CLI.IsPatchPoint)
262d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
263d8a9d66dSJF Bastien 
2649cc692b0SDan Gohman   // WebAssembly doesn't currently support explicit tail calls. If they are
2659cc692b0SDan Gohman   // required, fail. Otherwise, just disable them.
2669cc692b0SDan Gohman   if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
2679cc692b0SDan Gohman        MF.getTarget().Options.GuaranteedTailCallOpt) ||
2689cc692b0SDan Gohman       (CLI.CS && CLI.CS->isMustTailCall()))
2699cc692b0SDan Gohman     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
2709cc692b0SDan Gohman   CLI.IsTailCall = false;
2719cc692b0SDan Gohman 
272d8a9d66dSJF Bastien   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
273e590b33bSDan Gohman 
274d8a9d66dSJF Bastien   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
275e590b33bSDan Gohman   if (Ins.size() > 1)
276e590b33bSDan Gohman     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
277e590b33bSDan Gohman 
278d8a9d66dSJF Bastien   bool IsVarArg = CLI.IsVarArg;
279d8a9d66dSJF Bastien   if (IsVarArg)
280d8a9d66dSJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
281e590b33bSDan Gohman 
282d8a9d66dSJF Bastien   // Analyze operands of the call, assigning locations to each operand.
283d8a9d66dSJF Bastien   SmallVector<CCValAssign, 16> ArgLocs;
284d8a9d66dSJF Bastien   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
285d8a9d66dSJF Bastien   unsigned NumBytes = CCInfo.getNextStackOffset();
286d8a9d66dSJF Bastien 
287d8a9d66dSJF Bastien   auto PtrVT = getPointerTy(MF.getDataLayout());
288af111db8SJF Bastien   auto Zero = DAG.getConstant(0, DL, PtrVT, true);
289af111db8SJF Bastien   auto NB = DAG.getConstant(NumBytes, DL, PtrVT, true);
290af111db8SJF Bastien   Chain = DAG.getCALLSEQ_START(Chain, NB, DL);
291d8a9d66dSJF Bastien 
292d8a9d66dSJF Bastien   SmallVector<SDValue, 16> Ops;
293d8a9d66dSJF Bastien   Ops.push_back(Chain);
294af111db8SJF Bastien   Ops.push_back(Callee);
295af111db8SJF Bastien   Ops.append(OutVals.begin(), OutVals.end());
296d8a9d66dSJF Bastien 
297d8a9d66dSJF Bastien   SmallVector<EVT, 8> Tys;
298af111db8SJF Bastien   for (const auto &In : Ins)
299d8a9d66dSJF Bastien     Tys.push_back(In.VT);
300d8a9d66dSJF Bastien   Tys.push_back(MVT::Other);
301af111db8SJF Bastien   SDVTList TyList = DAG.getVTList(Tys);
302f71abef7SDan Gohman   SDValue Res =
303f71abef7SDan Gohman       DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
304f71abef7SDan Gohman                   DL, TyList, Ops);
305af111db8SJF Bastien   if (Ins.empty()) {
306af111db8SJF Bastien     Chain = Res;
307af111db8SJF Bastien   } else {
308d8a9d66dSJF Bastien     InVals.push_back(Res);
309d8a9d66dSJF Bastien     Chain = Res.getValue(1);
310af111db8SJF Bastien   }
311d8a9d66dSJF Bastien 
312af111db8SJF Bastien   Chain = DAG.getCALLSEQ_END(Chain, NB, Zero, SDValue(), DL);
313d8a9d66dSJF Bastien 
314d8a9d66dSJF Bastien   return Chain;
315d8a9d66dSJF Bastien }
316d8a9d66dSJF Bastien 
317b9073fb2SJF Bastien bool WebAssemblyTargetLowering::CanLowerReturn(
318b9073fb2SJF Bastien     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
319b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
320b9073fb2SJF Bastien   // WebAssembly can't currently handle returning tuples.
321b9073fb2SJF Bastien   return Outs.size() <= 1;
322b9073fb2SJF Bastien }
323b9073fb2SJF Bastien 
324b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerReturn(
325b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
326b9073fb2SJF Bastien     const SmallVectorImpl<ISD::OutputArg> &Outs,
327b9073fb2SJF Bastien     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
328b9073fb2SJF Bastien     SelectionDAG &DAG) const {
329754cd11dSDan Gohman   MachineFunction &MF = DAG.getMachineFunction();
330b9073fb2SJF Bastien 
331b9073fb2SJF Bastien   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
332b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
333b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
334600aee98SJF Bastien   if (IsVarArg)
335600aee98SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
336b9073fb2SJF Bastien 
337600aee98SJF Bastien   SmallVector<SDValue, 4> RetOps(1, Chain);
338600aee98SJF Bastien   RetOps.append(OutVals.begin(), OutVals.end());
3394a2d5604SJF Bastien   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
340b9073fb2SJF Bastien 
341754cd11dSDan Gohman   // Record the number and types of the return values.
342754cd11dSDan Gohman   for (const ISD::OutputArg &Out : Outs) {
343754cd11dSDan Gohman     if (Out.Flags.isByVal())
344754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented byval results");
345754cd11dSDan Gohman     if (Out.Flags.isInAlloca())
346754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
347754cd11dSDan Gohman     if (Out.Flags.isNest())
348754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented nest results");
349754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegs())
350754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
351754cd11dSDan Gohman     if (Out.Flags.isInConsecutiveRegsLast())
352754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
353754cd11dSDan Gohman     if (!Out.IsFixed)
354754cd11dSDan Gohman       fail(DL, DAG, "WebAssembly doesn't support non-fixed results yet");
355754cd11dSDan Gohman     MF.getInfo<WebAssemblyFunctionInfo>()->addResult(Out.VT);
356754cd11dSDan Gohman   }
357754cd11dSDan Gohman 
358b9073fb2SJF Bastien   return Chain;
359b9073fb2SJF Bastien }
360b9073fb2SJF Bastien 
361b9073fb2SJF Bastien SDValue WebAssemblyTargetLowering::LowerFormalArguments(
362b9073fb2SJF Bastien     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
363b9073fb2SJF Bastien     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
364b9073fb2SJF Bastien     SmallVectorImpl<SDValue> &InVals) const {
365b9073fb2SJF Bastien   MachineFunction &MF = DAG.getMachineFunction();
366b9073fb2SJF Bastien 
367b9073fb2SJF Bastien   if (CallConv != CallingConv::C)
368b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
369b9073fb2SJF Bastien   if (IsVarArg)
370b9073fb2SJF Bastien     fail(DL, DAG, "WebAssembly doesn't support varargs yet");
371b9073fb2SJF Bastien 
372600aee98SJF Bastien   for (const ISD::InputArg &In : Ins) {
373600aee98SJF Bastien     if (In.Flags.isByVal())
374600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
375600aee98SJF Bastien     if (In.Flags.isInAlloca())
376600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
377600aee98SJF Bastien     if (In.Flags.isNest())
378600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
379600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegs())
380600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
381600aee98SJF Bastien     if (In.Flags.isInConsecutiveRegsLast())
382600aee98SJF Bastien       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
383600aee98SJF Bastien     // FIXME Do something with In.getOrigAlign()?
384d7fcc6f9SJF Bastien     InVals.push_back(
385d7fcc6f9SJF Bastien         In.Used
386d7fcc6f9SJF Bastien             ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
387*5219ecf0SDan Gohman                           DAG.getTargetConstant(InVals.size(), DL, MVT::i32))
388d7fcc6f9SJF Bastien             : DAG.getNode(ISD::UNDEF, DL, In.VT));
389754cd11dSDan Gohman 
390754cd11dSDan Gohman     // Record the number and types of arguments.
391754cd11dSDan Gohman     MF.getInfo<WebAssemblyFunctionInfo>()->addParam(In.VT);
392600aee98SJF Bastien   }
393b9073fb2SJF Bastien 
394b9073fb2SJF Bastien   return Chain;
395b9073fb2SJF Bastien }
396b9073fb2SJF Bastien 
39710e730a2SDan Gohman //===----------------------------------------------------------------------===//
398af111db8SJF Bastien //  Custom lowering hooks.
39910e730a2SDan Gohman //===----------------------------------------------------------------------===//
40010e730a2SDan Gohman 
401af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
402af111db8SJF Bastien                                                   SelectionDAG &DAG) const {
403af111db8SJF Bastien   switch (Op.getOpcode()) {
404af111db8SJF Bastien   default:
405af111db8SJF Bastien     llvm_unreachable("unimplemented operation lowering");
406af111db8SJF Bastien     return SDValue();
407af111db8SJF Bastien   case ISD::GlobalAddress:
408af111db8SJF Bastien     return LowerGlobalAddress(Op, DAG);
409950a13cfSDan Gohman   case ISD::JumpTable:
410950a13cfSDan Gohman     return LowerJumpTable(Op, DAG);
411950a13cfSDan Gohman   case ISD::BR_JT:
412950a13cfSDan Gohman     return LowerBR_JT(Op, DAG);
413af111db8SJF Bastien   }
414af111db8SJF Bastien }
415af111db8SJF Bastien 
416af111db8SJF Bastien SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
417af111db8SJF Bastien                                                       SelectionDAG &DAG) const {
418af111db8SJF Bastien   SDLoc DL(Op);
419af111db8SJF Bastien   const auto *GA = cast<GlobalAddressSDNode>(Op);
420af111db8SJF Bastien   EVT VT = Op.getValueType();
421af111db8SJF Bastien   assert(GA->getOffset() == 0 &&
422af111db8SJF Bastien          "offsets on global addresses are forbidden by isOffsetFoldingLegal");
423af111db8SJF Bastien   assert(GA->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
424af111db8SJF Bastien   if (GA->getAddressSpace() != 0)
425af111db8SJF Bastien     fail(DL, DAG, "WebAssembly only expects the 0 address space");
426af111db8SJF Bastien   return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
427af111db8SJF Bastien                      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT));
428af111db8SJF Bastien }
429af111db8SJF Bastien 
430950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
431950a13cfSDan Gohman                                                   SelectionDAG &DAG) const {
432950a13cfSDan Gohman   // There's no need for a Wrapper node because we always incorporate a jump
433950a13cfSDan Gohman   // table operand into a SWITCH instruction, rather than ever materializing
434950a13cfSDan Gohman   // it in a register.
435950a13cfSDan Gohman   const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
436950a13cfSDan Gohman   return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
437950a13cfSDan Gohman                                 JT->getTargetFlags());
438950a13cfSDan Gohman }
439950a13cfSDan Gohman 
440950a13cfSDan Gohman SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
441950a13cfSDan Gohman                                               SelectionDAG &DAG) const {
442950a13cfSDan Gohman   SDLoc DL(Op);
443950a13cfSDan Gohman   SDValue Chain = Op.getOperand(0);
444950a13cfSDan Gohman   const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
445950a13cfSDan Gohman   SDValue Index = Op.getOperand(2);
446950a13cfSDan Gohman   assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
447950a13cfSDan Gohman 
448950a13cfSDan Gohman   SmallVector<SDValue, 8> Ops;
449950a13cfSDan Gohman   Ops.push_back(Chain);
450950a13cfSDan Gohman   Ops.push_back(Index);
451950a13cfSDan Gohman 
452950a13cfSDan Gohman   MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
453950a13cfSDan Gohman   const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
454950a13cfSDan Gohman 
455950a13cfSDan Gohman   // TODO: For now, we just pick something arbitrary for a default case for now.
456950a13cfSDan Gohman   // We really want to sniff out the guard and put in the real default case (and
457950a13cfSDan Gohman   // delete the guard).
458950a13cfSDan Gohman   Ops.push_back(DAG.getBasicBlock(MBBs[0]));
459950a13cfSDan Gohman 
460950a13cfSDan Gohman   // Add an operand for each case.
461950a13cfSDan Gohman   for (auto MBB : MBBs)
462950a13cfSDan Gohman     Ops.push_back(DAG.getBasicBlock(MBB));
463950a13cfSDan Gohman 
464950a13cfSDan Gohman   return DAG.getNode(WebAssemblyISD::SWITCH, DL, MVT::Other, Ops);
465950a13cfSDan Gohman }
466950a13cfSDan Gohman 
46710e730a2SDan Gohman //===----------------------------------------------------------------------===//
46810e730a2SDan Gohman //                          WebAssembly Optimization Hooks
46910e730a2SDan Gohman //===----------------------------------------------------------------------===//
47010e730a2SDan Gohman 
47110e730a2SDan Gohman MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
47210e730a2SDan Gohman     const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
47310e730a2SDan Gohman     const TargetMachine &TM) const {
474e51c058eSDan Gohman   // TODO: Be more sophisticated than this.
475e51c058eSDan Gohman   return isa<Function>(GV) ? getTextSection() : getDataSection();
47610e730a2SDan Gohman }
477