//=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==// // // 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 implements the WebAssemblyTargetLowering class. /// //===----------------------------------------------------------------------===// #include "WebAssemblyISelLowering.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyTargetMachine.h" #include "WebAssemblyTargetObjectFile.h" #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/Debug.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) { // Booleans always contain 0 or 1. setBooleanContents(ZeroOrOneBooleanContent); // 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: many setOperationAction are missing... for (auto T : {MVT::f32, MVT::f64}) { // Don't expand the floating-point types to constant pools. setOperationAction(ISD::ConstantFP, T, Legal); // Expand floating-point comparisons. for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) setCondCodeAction(CC, T, Expand); } } MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout &DL, EVT VT) const { return VT.getSimpleVT(); } 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"; } return nullptr; } //===----------------------------------------------------------------------===// // WebAssembly Lowering private implementation. //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // 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"); if (IsVarArg) fail(DL, DAG, "WebAssembly doesn't support varargs yet"); SmallVector RetOps(1, Chain); RetOps.append(OutVals.begin(), OutVals.end()); Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); 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"); 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"); // FIXME Do something with In.getOrigAlign()? InVals.push_back( In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, DAG.getTargetConstant(ArgNo, DL, MVT::i32)) : DAG.getNode(ISD::UNDEF, DL, In.VT)); ++ArgNo; } return Chain; } //===----------------------------------------------------------------------===// // Other Lowering Code //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // WebAssembly Optimization Hooks //===----------------------------------------------------------------------===// MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal( const GlobalValue *GV, SectionKind Kind, Mangler &Mang, const TargetMachine &TM) const { return getDataSection(); }