call
authorJF Bastien <jfb@google.com>
Mon, 24 Aug 2015 21:59:51 +0000 (21:59 +0000)
committerJF Bastien <jfb@google.com>
Mon, 24 Aug 2015 21:59:51 +0000 (21:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245882 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h
lib/Target/WebAssembly/WebAssemblyISD.def [new file with mode: 0644]
lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
lib/Target/WebAssembly/WebAssemblyISelLowering.h
lib/Target/WebAssembly/WebAssemblyInstrCall.td
lib/Target/WebAssembly/WebAssemblyInstrFormats.td
test/CodeGen/WebAssembly/call.ll [new file with mode: 0644]

index 0c5792c6b51a656344cd0695f60cfd681905bd32..cbd2f7dc748a717dc7f02357352110f15db11587 100644 (file)
@@ -44,3 +44,16 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
   printInstruction(MI, OS);
   printAnnotation(OS, Annot);
 }
+
+void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
+                                          raw_ostream &O) {
+  const MCOperand &Op = MI->getOperand(OpNo);
+  if (Op.isReg())
+    O << getRegisterName(Op.getReg());
+  else if (Op.isImm())
+    O << '#' << Op.getImm();
+  else {
+    assert(Op.isExpr() && "unknown operand kind in printOperand");
+    Op.getExpr()->print(O, &MAI);
+  }
+}
index 4c54a525577de1c757a341f594e7837e521385aa..80fe29d56f71576c2cb850ec7452c287f8943af3 100644 (file)
@@ -32,6 +32,9 @@ public:
   void printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot,
                  const MCSubtargetInfo &STI) override;
 
+  // Used by tblegen code.
+  void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+
   // Autogenerated by tblgen.
   void printInstruction(const MCInst *MI, raw_ostream &O);
   static const char *getRegisterName(unsigned RegNo);
diff --git a/lib/Target/WebAssembly/WebAssemblyISD.def b/lib/Target/WebAssembly/WebAssemblyISD.def
new file mode 100644 (file)
index 0000000..3b5d82e
--- /dev/null
@@ -0,0 +1,19 @@
+//- WebAssemblyISD.def - WebAssembly ISD ---------------------------*- C++ -*-//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file describes the various WebAssembly ISD node types.
+///
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+HANDLE_NODETYPE(CALL)
+HANDLE_NODETYPE(RETURN)
+HANDLE_NODETYPE(ARGUMENT)
index dfeec770d5a013d511e4a1cf997812d148e84b22..d9efc190b5bb6f998d5697804284533291ac3405 100644 (file)
@@ -19,6 +19,7 @@
 #include "WebAssemblyTargetMachine.h"
 #include "WebAssemblyTargetObjectFile.h"
 #include "llvm/CodeGen/Analysis.h"
+#include "llvm/CodeGen/CallingConvLower.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/IR/DiagnosticInfo.h"
@@ -164,9 +165,13 @@ MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout &DL,
 const char *
 WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
-  case WebAssemblyISD::FIRST_NUMBER: break;
-  case WebAssemblyISD::RETURN: return "WebAssemblyISD::RETURN";
-  case WebAssemblyISD::ARGUMENT: return "WebAssemblyISD::ARGUMENT";
+  case WebAssemblyISD::FIRST_NUMBER:
+    break;
+#define HANDLE_NODETYPE(NODE)                                                  \
+  case WebAssemblyISD::NODE:                                                   \
+    return "WebAssemblyISD::" #NODE;
+#include "WebAssemblyISD.def"
+#undef HANDLE_NODETYPE
   }
   return nullptr;
 }
@@ -185,6 +190,68 @@ static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) {
       DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue()));
 }
 
+SDValue
+WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
+                                     SmallVectorImpl<SDValue> &InVals) const {
+  SelectionDAG &DAG = CLI.DAG;
+  SDLoc DL = CLI.DL;
+  SDValue Chain = CLI.Chain;
+  SDValue Callee = CLI.Callee;
+  MachineFunction &MF = DAG.getMachineFunction();
+
+  CallingConv::ID CallConv = CLI.CallConv;
+  if (CallConv != CallingConv::C)
+    fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
+  if (CLI.IsTailCall || MF.getTarget().Options.GuaranteedTailCallOpt)
+    fail(DL, DAG, "WebAssembly doesn't support tail call yet");
+  if (CLI.IsPatchPoint)
+    fail(DL, DAG, "WebAssembly doesn't support patch point yet");
+
+  SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
+  SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
+  Type *retTy = CLI.RetTy;
+  bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet();
+  if (IsStructRet)
+    fail(DL, DAG, "WebAssembly doesn't support struct return yet");
+  if (Outs.size() > 1)
+    fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
+
+  SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
+  ArgListTy &Args = CLI.getArgs();
+  bool IsVarArg = CLI.IsVarArg;
+  if (IsVarArg)
+    fail(DL, DAG, "WebAssembly doesn't support varargs yet");
+  // Analyze operands of the call, assigning locations to each operand.
+  SmallVector<CCValAssign, 16> ArgLocs;
+  CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
+  unsigned NumBytes = CCInfo.getNextStackOffset();
+
+  auto PtrVT = getPointerTy(MF.getDataLayout());
+  auto Zero = DAG.getConstant(0, CLI.DL, PtrVT, true);
+  auto NB = DAG.getConstant(NumBytes, CLI.DL, PtrVT, true);
+  Chain = DAG.getCALLSEQ_START(Chain, NB, CLI.DL);
+
+  SmallVector<SDValue, 16> Ops;
+  Ops.push_back(Chain);
+  Ops.push_back(CLI.Callee);
+  Ops.append(CLI.OutVals.begin(), CLI.OutVals.end());
+
+  SmallVector<EVT, 8> Tys;
+  for (const auto &In : CLI.Ins)
+    Tys.push_back(In.VT);
+  Tys.push_back(MVT::Other);
+  SDVTList TyList = CLI.DAG.getVTList(Tys);
+  SDValue Res = CLI.DAG.getNode(WebAssemblyISD::CALL, CLI.DL, TyList, Ops);
+  InVals.push_back(Res);
+  Chain = Res.getValue(1);
+
+  // FIXME: handle CLI.RetSExt and CLI.RetZExt?
+
+  Chain = CLI.DAG.getCALLSEQ_END(Chain, NB, Zero, SDValue(), CLI.DL);
+
+  return Chain;
+}
+
 bool WebAssemblyTargetLowering::CanLowerReturn(
     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
index ea845cd4031c5e5158515d39f0db6549144874d2..d82bfa61555696ae6a9072a292d7e9fd6cd31acc 100644 (file)
@@ -24,9 +24,9 @@ namespace WebAssemblyISD {
 
 enum NodeType : unsigned {
   FIRST_NUMBER = ISD::BUILTIN_OP_END,
-  RETURN,
-  ARGUMENT,
-
+#define HANDLE_NODETYPE(NODE) NODE,
+#include "WebAssemblyISD.def"
+#undef HANDLE_NODETYPE
   // add memory opcodes starting at ISD::FIRST_TARGET_MEMORY_OPCODE here...
 };
 
@@ -52,6 +52,9 @@ private:
 
   const char *getTargetNodeName(unsigned Opcode) const override;
 
+  SDValue LowerCall(CallLoweringInfo &CLI,
+                    SmallVectorImpl<SDValue> &InVals) const override;
+
   bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF,
                       bool isVarArg,
                       const SmallVectorImpl<ISD::OutputArg> &Outs,
index 6b5b6cd5417334623b1f62b91230ad4afd4f0a52..3b9c015fb18c69c10c711e74afdd8942b3cc2865 100644 (file)
 ///
 //===----------------------------------------------------------------------===//
 
+// The call sequence start/end LLVM-isms isn't useful to WebAssembly since it's
+// a virtual ISA.
+
+// FIXME make noop?
+//def : Pat<(WebAssemblycallseq_start timm), (i32 (IMPLICIT_DEF))>;
+//def : Pat<(WebAssemblycallseq_end timm, timm), (i32 (IMPLICIT_DEF))>;
+
+def SDT_WebAssemblyCallSeqStart : SDCallSeqStart<[SDTCisVT<0, iPTR>]>;
+def SDT_WebAssemblyCallSeqEnd :
+    SDCallSeqEnd<[SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>;
+def WebAssemblycallseq_start :
+    SDNode<"ISD::CALLSEQ_START", SDT_WebAssemblyCallSeqStart,
+           [SDNPHasChain, SDNPOutGlue]>;
+def WebAssemblycallseq_end :
+    SDNode<"ISD::CALLSEQ_END", SDT_WebAssemblyCallSeqEnd,
+           [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
+def : Pseudo<(outs), (ins i64imm:$amt),
+             [(WebAssemblycallseq_start timm:$amt)],
+             "#ADJCALLSTACKDOWN $amt">;
+def : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2),
+             [(WebAssemblycallseq_end timm:$amt1, timm:$amt2)],
+            "#ADJCALLSTACKUP $amt1 $amt2">;
+
 /*
  * TODO(jfb): Add the following.
  *
index f4d16d39e646172f5763ea0df05751600b8abcad..9228be7dea347ae806be44c344ab9b3a36d93c75 100644 (file)
@@ -12,7 +12,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
-// WebAssembly Instruction Format
+// WebAssembly Instruction Format.
 class WebAssemblyInst<string cstr> : Instruction {
   field bits<0> Inst; // Instruction encoding.
   let Namespace   = "WebAssembly";
@@ -20,7 +20,7 @@ class WebAssemblyInst<string cstr> : Instruction {
   let Constraints = cstr;
 }
 
-// Normal instructions
+// Normal instructions.
 class I<dag oops, dag iops, list<dag> pattern, string cstr = "">
     : WebAssemblyInst<cstr> {
   dag OutOperandList = oops;
@@ -28,6 +28,14 @@ class I<dag oops, dag iops, list<dag> pattern, string cstr = "">
   let Pattern        = pattern;
 }
 
+// Pseudo instructions.
+class Pseudo<dag oops, dag iops, list<dag> pattern, string asmstr,
+             string cstr = "">
+  : I<oops, iops, pattern, cstr> {
+  let isPseudo  = 1;
+  let AsmString = asmstr;
+}
+
 // Unary and binary instructions, for the local types that WebAssembly supports.
 multiclass UnaryInt<SDNode node> {
   def _I32 : I<(outs Int32:$dst), (ins Int32:$src),
diff --git a/test/CodeGen/WebAssembly/call.ll b/test/CodeGen/WebAssembly/call.ll
new file mode 100644 (file)
index 0000000..e5d468b
--- /dev/null
@@ -0,0 +1,22 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck %s
+
+; Test that basic call operations assemble as expected.
+
+target datalayout = "e-p:32:32-i64:64-v128:8:128-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @nullary()
+
+; CHECK-LABEL: call_nullary:
+; CHECK-NEXT: (call @foo)
+; CHECK-NEXT: (return)
+define void @call_nullary() {
+  call void @nullary()
+  ret void
+}
+
+
+; tail call
+; multiple args
+; interesting returns (int, float, struct, multiple)
+; vararg