Index: llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt +++ llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt @@ -1,15 +1,19 @@ set(LLVM_TARGET_DEFINITIONS WebAssembly.td) +tablegen(LLVM WebAssemblyGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM WebAssemblyGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM WebAssemblyGenInstrInfo.inc -gen-instr-info) tablegen(LLVM WebAssemblyGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM WebAssemblyGenRegisterInfo.inc -gen-register-info) tablegen(LLVM WebAssemblyGenSubtargetInfo.inc -gen-subtarget) add_public_tablegen_target(WebAssemblyCommonTableGen) add_llvm_target(WebAssemblyCodeGen + WebAssemblyAsmPrinter.cpp WebAssemblyFrameLowering.cpp - WebAssemblyInstrInfo.cpp WebAssemblyISelDAGToDAG.cpp WebAssemblyISelLowering.cpp + WebAssemblyInstrInfo.cpp WebAssemblyMachineFunctionInfo.cpp WebAssemblyRegisterInfo.cpp WebAssemblySelectionDAGInfo.cpp Index: llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h +++ llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h @@ -31,6 +31,10 @@ void printRegName(raw_ostream &OS, unsigned RegNo) const override; void printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot, const MCSubtargetInfo &STI) override; + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); }; } // end namespace llvm Index: llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -26,6 +26,8 @@ #define DEBUG_TYPE "asm-printer" +#include "WebAssemblyGenAsmWriter.inc" + WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI) @@ -33,11 +35,12 @@ void WebAssemblyInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { - llvm_unreachable("TODO: implement printRegName"); + OS << getRegisterName(RegNo); } void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot, const MCSubtargetInfo &STI) { - llvm_unreachable("TODO: implement printInst"); + printInstruction(MI, OS); + printAnnotation(OS, Annot); } Index: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -50,6 +50,11 @@ #define GET_REGINFO_ENUM #include "WebAssemblyGenRegisterInfo.inc" +// Defines symbolic names for the WebAssembly instructions. +// +#define GET_INSTRINFO_ENUM +#include "WebAssemblyGenInstrInfo.inc" + #define GET_SUBTARGETINFO_ENUM #include "WebAssemblyGenSubtargetInfo.inc" Index: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp +++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp @@ -26,6 +26,9 @@ #define DEBUG_TYPE "wasm-mc-target-desc" +#define GET_INSTRINFO_MC_DESC +#include "WebAssemblyGenInstrInfo.inc" + #define GET_SUBTARGETINFO_MC_DESC #include "WebAssemblyGenSubtargetInfo.inc" Index: llvm/trunk/lib/Target/WebAssembly/Makefile =================================================================== --- llvm/trunk/lib/Target/WebAssembly/Makefile +++ llvm/trunk/lib/Target/WebAssembly/Makefile @@ -12,8 +12,13 @@ TARGET = WebAssembly # Make sure that tblgen is run, first thing. -BUILT_SOURCES = WebAssemblyGenRegisterInfo.inc WebAssemblyGenSubtargetInfo.inc \ - WebAssemblyGenMCCodeEmitter.inc +BUILT_SOURCES = \ + WebAssemblyGenAsmWriter.inc \ + WebAssemblyGenDAGISel.inc \ + WebAssemblyGenInstrInfo.inc \ + WebAssemblyGenMCCodeEmitter.inc \ + WebAssemblyGenRegisterInfo.inc \ + WebAssemblyGenSubtargetInfo.inc DIRS = InstPrinter TargetInfo MCTargetDesc Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -0,0 +1,91 @@ +//===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===// +// +// 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 contains a printer that converts from our internal +/// representation of machine-dependent LLVM code to the WebAssembly assembly +/// language. +/// +//===----------------------------------------------------------------------===// + +#include "WebAssembly.h" +#include "WebAssemblyMachineFunctionInfo.h" +#include "WebAssemblyRegisterInfo.h" +#include "WebAssemblySubtarget.h" +#include "InstPrinter/WebAssemblyInstPrinter.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +namespace { + +class WebAssemblyAsmPrinter final : public AsmPrinter { +public: + WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) + : AsmPrinter(TM, std::move(Streamer)) {} + +private: + const char *getPassName() const override { + return "WebAssembly Assembly Printer"; + } + + //===------------------------------------------------------------------===// + // MachineFunctionPass Implementation. + //===------------------------------------------------------------------===// + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AsmPrinter::getAnalysisUsage(AU); + } + + bool runOnMachineFunction(MachineFunction &F) override { + return AsmPrinter::runOnMachineFunction(F); + } + + //===------------------------------------------------------------------===// + // AsmPrinter Implementation. + //===------------------------------------------------------------------===// + + void EmitInstruction(const MachineInstr *MI) override; +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// + +void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + + switch (MI->getOpcode()) { + default: + DEBUG(MI->print(dbgs())); + llvm_unreachable("Unhandled instruction"); + break; + } + + OutStreamer->EmitRawText(OS.str()); +} + +// Force static initialization. +extern "C" void LLVMInitializeWebAssemblyAsmPrinter() { + RegisterAsmPrinter X(TheWebAssemblyTarget32); + RegisterAsmPrinter Y(TheWebAssemblyTarget64); +} Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h @@ -38,9 +38,6 @@ bool hasFP(const MachineFunction &MF) const override; bool hasReservedCallFrame(const MachineFunction &MF) const override; - - void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, - RegScavenger *RS = nullptr) const override; }; } // end namespace llvm Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -39,7 +39,12 @@ /// Return true if the specified function should have a dedicated frame pointer /// register. bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const { - llvm_unreachable("TODO: implement hasFP"); + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const auto *RegInfo = static_cast( + MF.getSubtarget().getRegisterInfo()); + return MFI->hasCalls() || MFI->hasVarSizedObjects() || + MFI->isFrameAddressTaken() || MFI->hasStackMap() || + MFI->hasPatchPoint() || RegInfo->needsStackRealignment(MF); } /// Under normal circumstances, when a frame pointer is not required, we reserve @@ -60,16 +65,10 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { - llvm_unreachable("TODO: implement emitPrologue"); + // FIXME: Implement WebAssemblyFrameLowering::emitPrologue. } void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { llvm_unreachable("TODO: implement emitEpilogue"); } - -void WebAssemblyFrameLowering::determineCalleeSaves(MachineFunction &MF, - BitVector &SavedRegs, - RegScavenger *RS) const { - llvm_unreachable("TODO: implement determineCalleeSaves"); -} Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -56,13 +56,49 @@ SDNode *Select(SDNode *Node) override; +// Include the pieces autogenerated from the target description. +#include "WebAssemblyGenDAGISel.inc" + private: // add select functions here... }; } // end anonymous namespace SDNode *WebAssemblyDAGToDAGISel::Select(SDNode *Node) { - llvm_unreachable("TODO: implement Select"); + // Dump information about the Node being selected. + DEBUG(errs() << "Selecting: "); + DEBUG(Node->dump(CurDAG)); + DEBUG(errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); + Node->setNodeId(-1); + return nullptr; + } + + // Few custom selection stuff. + SDNode *ResNode = nullptr; + EVT VT = Node->getValueType(0); + + switch (Node->getOpcode()) { + default: + break; + // FIXME: Implement WebAssembly-specific selection. + (void)VT; + } + + // Select the default instruction. + ResNode = SelectCode(Node); + + DEBUG(errs() << "=> "); + if (ResNode == nullptr || ResNode == Node) + DEBUG(Node->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DEBUG(errs() << "\n"); + + return ResNode; } /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -42,6 +42,22 @@ /// Keep a pointer to the WebAssemblySubtarget around so that we can make the /// right decision when generating code for different targets. const WebAssemblySubtarget *Subtarget; + + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool isVarArg, + const SmallVectorImpl &Outs, + LLVMContext &Context) const override; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, SDLoc dl, + SelectionDAG &DAG) const override; + + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; }; } // end namespace llvm Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -21,6 +21,8 @@ #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Function.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Support/CommandLine.h" @@ -28,10 +30,65 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetOptions.h" + using namespace llvm; #define DEBUG_TYPE "wasm-lower" +namespace { +// Diagnostic information for unimplemented or unsupported feature reporting. +// FIXME copied from BPF and AMDGPU. +class DiagnosticInfoUnsupported : public DiagnosticInfo { +private: + // Debug location where this diagnostic is triggered. + DebugLoc DLoc; + const Twine &Description; + const Function &Fn; + SDValue Value; + + static int KindID; + + static int getKindID() { + if (KindID == 0) + KindID = llvm::getNextAvailablePluginDiagnosticKind(); + return KindID; + } + +public: + DiagnosticInfoUnsupported(SDLoc DLoc, const Function &Fn, const Twine &Desc, + SDValue Value) + : DiagnosticInfo(getKindID(), DS_Error), DLoc(DLoc.getDebugLoc()), + Description(Desc), Fn(Fn), Value(Value) {} + + void print(DiagnosticPrinter &DP) const override { + std::string Str; + raw_string_ostream OS(Str); + + if (DLoc) { + auto DIL = DLoc.get(); + StringRef Filename = DIL->getFilename(); + unsigned Line = DIL->getLine(); + unsigned Column = DIL->getColumn(); + OS << Filename << ':' << Line << ':' << Column << ' '; + } + + OS << "in function " << Fn.getName() << ' ' << *Fn.getFunctionType() << '\n' + << Description; + if (Value) + Value->print(OS); + OS << '\n'; + OS.flush(); + DP << Str; + } + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == getKindID(); + } +}; + +int DiagnosticInfoUnsupported::KindID = 0; +} // end anonymous namespace + WebAssemblyTargetLowering::WebAssemblyTargetLowering( const TargetMachine &TM, const WebAssemblySubtarget &STI) : TargetLowering(TM), Subtarget(&STI) { @@ -40,6 +97,18 @@ setHasFloatingPointExceptions(false); // We don't know the microarchitecture here, so just reduce register pressure. setSchedulingPreference(Sched::RegPressure); + // Tell ISel that we have a stack pointer. + setStackPointerRegisterToSaveRestore( + Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); + // Set up the register classes. + addRegisterClass(MVT::i32, &WebAssembly::Int32RegClass); + addRegisterClass(MVT::i64, &WebAssembly::Int64RegClass); + addRegisterClass(MVT::f32, &WebAssembly::Float32RegClass); + addRegisterClass(MVT::f64, &WebAssembly::Float64RegClass); + // Compute derived properties from the register classes. + computeRegisterProperties(Subtarget->getRegisterInfo()); + + // FIXME: setOperationAction... } //===----------------------------------------------------------------------===// @@ -50,6 +119,54 @@ // Lowering Code //===----------------------------------------------------------------------===// +static void fail(SDLoc DL, SelectionDAG &DAG, const char *msg) { + MachineFunction &MF = DAG.getMachineFunction(); + DAG.getContext()->diagnose( + DiagnosticInfoUnsupported(DL, *MF.getFunction(), msg, SDValue())); +} + +bool WebAssemblyTargetLowering::CanLowerReturn( + CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl &Outs, LLVMContext &Context) const { + // WebAssembly can't currently handle returning tuples. + return Outs.size() <= 1; +} + +SDValue WebAssemblyTargetLowering::LowerReturn( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, SDLoc DL, + SelectionDAG &DAG) const { + + assert(Outs.size() <= 1 && "WebAssembly can only return up to one value"); + if (CallConv != CallingConv::C) + fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); + + // FIXME: Implement LowerReturn. + + return Chain; +} + +SDValue WebAssemblyTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + + if (CallConv != CallingConv::C) + fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); + if (IsVarArg) + fail(DL, DAG, "WebAssembly doesn't support varargs yet"); + if (MF.getFunction()->hasStructRetAttr()) + fail(DL, DAG, "WebAssembly doesn't support struct return yet"); + + // FIXME: Implement LowerFormalArguments. + for (const ISD::InputArg &In : Ins) + InVals.push_back(DAG.getNode(ISD::UNDEF, DL, In.VT)); + + return Chain; +} + //===----------------------------------------------------------------------===// // Other Lowering Code //===----------------------------------------------------------------------===// Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.h +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.h @@ -19,11 +19,14 @@ #include "WebAssemblyRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" +#define GET_INSTRINFO_HEADER +#include "WebAssemblyGenInstrInfo.inc" + namespace llvm { class WebAssemblySubtarget; -class WebAssemblyInstrInfo final { +class WebAssemblyInstrInfo final : public WebAssemblyGenInstrInfo { const WebAssemblyRegisterInfo RI; public: Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -24,5 +24,8 @@ #define DEBUG_TYPE "wasm-instr-info" +#define GET_INSTRINFO_CTOR_DTOR +#include "WebAssemblyGenInstrInfo.inc" + WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI) : RI(STI.getTargetTriple()) {} Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -61,6 +61,12 @@ const WebAssemblyTargetLowering *getTargetLowering() const override { return &TLInfo; } + const WebAssemblyInstrInfo *getInstrInfo() const override { + return &InstrInfo; + } + const WebAssemblyRegisterInfo *getRegisterInfo() const override { + return &getInstrInfo()->getRegisterInfo(); + } const Triple &getTargetTriple() const { return TargetTriple; } bool enableMachineScheduler() const override; bool useAA() const override { return true; } Index: llvm/trunk/test/CodeGen/WebAssembly/integer.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/integer.ll +++ llvm/trunk/test/CodeGen/WebAssembly/integer.ll @@ -0,0 +1,10 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +target datalayout = "e-p:32:32-i64:64-v128:8:128-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; CHECK-LABEL: add32: +define i32 @add32(i32 %x, i32 %y) { + %a = add i32 %x, %y + ret i32 %a +}