From: JF Bastien Date: Mon, 24 Aug 2015 21:59:51 +0000 (+0000) Subject: call X-Git-Tag: android-x86-7.1-r4~44273 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=03685a9bf419e19ada39c9df4dc8a58c36eeee00;p=android-x86%2Fexternal-llvm.git call git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245882 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp index 0c5792c6b51..cbd2f7dc748 100644 --- a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -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); + } +} diff --git a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h index 4c54a525577..80fe29d56f7 100644 --- a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h +++ b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h @@ -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 index 00000000000..3b5d82eed9d --- /dev/null +++ b/lib/Target/WebAssembly/WebAssemblyISD.def @@ -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) diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index dfeec770d5a..d9efc190b5b 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -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(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 &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 &Outs = CLI.Outs; + SmallVectorImpl &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 &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 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 Ops; + Ops.push_back(Chain); + Ops.push_back(CLI.Callee); + Ops.append(CLI.OutVals.begin(), CLI.OutVals.end()); + + SmallVector 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 &Outs, LLVMContext &Context) const { diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/lib/Target/WebAssembly/WebAssemblyISelLowering.h index ea845cd4031..d82bfa61555 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -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 &InVals) const override; + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg, const SmallVectorImpl &Outs, diff --git a/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/lib/Target/WebAssembly/WebAssemblyInstrCall.td index 6b5b6cd5417..3b9c015fb18 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -12,6 +12,29 @@ /// //===----------------------------------------------------------------------===// +// 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. * diff --git a/lib/Target/WebAssembly/WebAssemblyInstrFormats.td b/lib/Target/WebAssembly/WebAssemblyInstrFormats.td index f4d16d39e64..9228be7dea3 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrFormats.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrFormats.td @@ -12,7 +12,7 @@ /// //===----------------------------------------------------------------------===// -// WebAssembly Instruction Format +// WebAssembly Instruction Format. class WebAssemblyInst : Instruction { field bits<0> Inst; // Instruction encoding. let Namespace = "WebAssembly"; @@ -20,7 +20,7 @@ class WebAssemblyInst : Instruction { let Constraints = cstr; } -// Normal instructions +// Normal instructions. class I pattern, string cstr = ""> : WebAssemblyInst { dag OutOperandList = oops; @@ -28,6 +28,14 @@ class I pattern, string cstr = ""> let Pattern = pattern; } +// Pseudo instructions. +class Pseudo pattern, string asmstr, + string cstr = ""> + : I { + let isPseudo = 1; + let AsmString = asmstr; +} + // Unary and binary instructions, for the local types that WebAssembly supports. multiclass UnaryInt { 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 index 00000000000..e5d468b3cd1 --- /dev/null +++ b/test/CodeGen/WebAssembly/call.ll @@ -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