#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"
#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) {
// WebAssembly does not produce floating-point exceptions on normal floating
// point operations.
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...
}
//===----------------------------------------------------------------------===//
// 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");
+ if (IsVarArg)
+ fail(DL, DAG, "WebAssembly doesn't support varargs yet");
+
+ SmallVector<SDValue, 4> RetOps(1, Chain);
+ RetOps.append(OutVals.begin(), OutVals.end());
+ const SDValue Ops[] = {Chain, OutVals.front()};
+ Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, Ops);
+
+ 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");
+
+ unsigned ArgNo = 0;
+ for (const ISD::InputArg &In : Ins) {
+ if (In.Flags.isZExt())
+ fail(DL, DAG, "WebAssembly hasn't implemented zext arguments");
+ if (In.Flags.isSExt())
+ fail(DL, DAG, "WebAssembly hasn't implemented sext arguments");
+ if (In.Flags.isInReg())
+ fail(DL, DAG, "WebAssembly hasn't implemented inreg arguments");
+ if (In.Flags.isSRet())
+ fail(DL, DAG, "WebAssembly hasn't implemented sret arguments");
+ if (In.Flags.isByVal())
+ fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
+ if (In.Flags.isInAlloca())
+ fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
+ if (In.Flags.isNest())
+ fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
+ if (In.Flags.isReturned())
+ fail(DL, DAG, "WebAssembly hasn't implemented returned arguments");
+ if (In.Flags.isInConsecutiveRegs())
+ fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
+ if (In.Flags.isInConsecutiveRegsLast())
+ fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
+ if (In.Flags.isSplit())
+ fail(DL, DAG, "WebAssembly hasn't implemented split arguments");
+ if (In.VT != MVT::i32)
+ fail(DL, DAG, "WebAssembly hasn't implemented non-i32 arguments");
+ if (!In.Used)
+ fail(DL, DAG, "WebAssembly hasn't implemented unused arguments");
+ // FIXME Do something with In.getOrigAlign()?
+ InVals.push_back(DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
+ DAG.getTargetConstant(ArgNo++, DL, MVT::i32)));
+ }
+
+ return Chain;
+}
+
//===----------------------------------------------------------------------===//
// Other Lowering Code
//===----------------------------------------------------------------------===//