WebAssembly: basic bitcode → assembly CodeGen test

Summary:
Add a basic CodeGen bitcode test which (for now) only prints out the function name and nothing else. The current code merely implements the basic needed for the test run to not crash / assert. Getting to that point required:

 - Basic InstPrinter.
 - Basic AsmPrinter.
 - DiagnosticInfoUnsupported (not strictly required, but nice to have, duplicated from AMDGPU/BPF's ISelLowering).
 - Some SP and register setup in WebAssemblyTargetLowering.
 - Basic LowerFormalArguments.
 - GenInstrInfo.
 - Placeholder LowerFormalArguments.
 - Placeholder CanLowerReturn and LowerReturn.
 - Basic DAGToDAGISel::Select, which requiresGenDAGISel.inc as well as GET_INSTRINFO_ENUM with GenInstrInfo.inc.
 - Remove WebAssemblyFrameLowering::determineCalleeSaves and rely on default.
 - Implement WebAssemblyFrameLowering::hasFP, same as AArch64's implementation.

Follow-up patches will implement a real AsmPrinter, which will require adding MI opcodes specific to WebAssembly.

Reviewers: sunfish

Subscribers: aemerson, jfb, llvm-commits

Differential Revision: http://reviews.llvm.org/D11369

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242939 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
JF Bastien 2015-07-22 21:28:15 +00:00
parent 6f3ab8dd7b
commit b18e7bdac8
16 changed files with 320 additions and 18 deletions

View File

@ -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

View File

@ -26,6 +26,8 @@ using namespace llvm;
#define DEBUG_TYPE "asm-printer"
#include "WebAssemblyGenAsmWriter.inc"
WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI,
const MCInstrInfo &MII,
const MCRegisterInfo &MRI)
@ -33,11 +35,12 @@ WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI,
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);
}

View File

@ -31,6 +31,10 @@ public:
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

View File

@ -26,6 +26,9 @@ using namespace llvm;
#define DEBUG_TYPE "wasm-mc-target-desc"
#define GET_INSTRINFO_MC_DESC
#include "WebAssemblyGenInstrInfo.inc"
#define GET_SUBTARGETINFO_MC_DESC
#include "WebAssemblyGenSubtargetInfo.inc"

View File

@ -50,6 +50,11 @@ MCAsmBackend *createWebAssemblyAsmBackend(const Target &T,
#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"

View File

@ -12,8 +12,13 @@ LIBRARYNAME = LLVMWebAssemblyCodeGen
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

View File

@ -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<MCStreamer> 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<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32);
RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64);
}

View File

@ -39,7 +39,12 @@ using namespace llvm;
/// 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<const WebAssemblyRegisterInfo *>(
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::eliminateCallFramePseudoInstr(
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");
}

View File

@ -38,9 +38,6 @@ public:
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

View File

@ -56,13 +56,49 @@ public:
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

View File

@ -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 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
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 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
// 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<ISD::OutputArg> &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<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &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<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &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
//===----------------------------------------------------------------------===//

View File

@ -42,6 +42,22 @@ private:
/// 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<ISD::OutputArg> &Outs,
LLVMContext &Context) const override;
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, SDLoc dl,
SelectionDAG &DAG) const override;
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
SDLoc DL, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const override;
};
} // end namespace llvm

View File

@ -24,5 +24,8 @@ using namespace llvm;
#define DEBUG_TYPE "wasm-instr-info"
#define GET_INSTRINFO_CTOR_DTOR
#include "WebAssemblyGenInstrInfo.inc"
WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)
: RI(STI.getTargetTriple()) {}

View File

@ -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:

View File

@ -61,6 +61,12 @@ public:
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; }

View File

@ -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
}