2015-06-30 07:51:55 +08:00
|
|
|
//=- 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"
|
2015-07-23 05:28:15 +08:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2015-06-30 07:51:55 +08:00
|
|
|
#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"
|
2015-07-23 05:28:15 +08:00
|
|
|
|
2015-06-30 07:51:55 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "wasm-lower"
|
|
|
|
|
2015-07-23 05:28:15 +08:00
|
|
|
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
|
|
|
|
|
2015-06-30 07:51:55 +08:00
|
|
|
WebAssemblyTargetLowering::WebAssemblyTargetLowering(
|
|
|
|
const TargetMachine &TM, const WebAssemblySubtarget &STI)
|
2015-07-03 05:36:25 +08:00
|
|
|
: TargetLowering(TM), Subtarget(&STI) {
|
2015-08-13 01:53:29 +08:00
|
|
|
// Booleans always contain 0 or 1.
|
|
|
|
setBooleanContents(ZeroOrOneBooleanContent);
|
2015-07-03 05:36:25 +08:00
|
|
|
// WebAssembly does not produce floating-point exceptions on normal floating
|
|
|
|
// point operations.
|
|
|
|
setHasFloatingPointExceptions(false);
|
2015-07-08 06:38:06 +08:00
|
|
|
// We don't know the microarchitecture here, so just reduce register pressure.
|
|
|
|
setSchedulingPreference(Sched::RegPressure);
|
2015-07-23 05:28:15 +08:00
|
|
|
// 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());
|
|
|
|
|
2015-08-11 06:36:48 +08:00
|
|
|
// FIXME: many setOperationAction are missing...
|
|
|
|
|
2015-08-12 05:02:46 +08:00
|
|
|
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);
|
2015-08-21 06:57:13 +08:00
|
|
|
// Expand floating-point library function operators.
|
|
|
|
for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOWI, ISD::FPOW,
|
|
|
|
ISD::FLOG, ISD::FLOG2, ISD::FLOG10, ISD::FEXP, ISD::FEXP2,
|
|
|
|
ISD::FMINNAN, ISD::FMAXNAN})
|
|
|
|
setOperationAction(Op, T, Expand);
|
2015-08-12 05:02:46 +08:00
|
|
|
}
|
2015-08-21 06:57:13 +08:00
|
|
|
|
|
|
|
for (auto T : {MVT::i32, MVT::i64}) {
|
|
|
|
// Expand unavailable integer operations.
|
|
|
|
for (auto Op : {ISD::BSWAP, ISD::ROTL, ISD::ROTR,
|
|
|
|
ISD::SMUL_LOHI, ISD::UMUL_LOHI,
|
|
|
|
ISD::MULHS, ISD::MULHU, ISD::SDIVREM, ISD::UDIVREM,
|
|
|
|
ISD::SHL_PARTS, ISD::SRA_PARTS, ISD::SRL_PARTS,
|
|
|
|
ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
|
|
|
|
setOperationAction(Op, T, Expand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// As a special case, these operators use the type to mean the type to
|
|
|
|
// sign-extend from.
|
|
|
|
for (auto T : {MVT::i1, MVT::i8, MVT::i16})
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
|
|
|
|
|
|
|
|
// Dynamic stack allocation: use the default expansion.
|
|
|
|
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
|
2015-07-03 05:36:25 +08:00
|
|
|
}
|
2015-06-30 07:51:55 +08:00
|
|
|
|
2015-08-03 08:00:11 +08:00
|
|
|
MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout &DL,
|
|
|
|
EVT VT) const {
|
|
|
|
return VT.getSimpleVT();
|
|
|
|
}
|
|
|
|
|
2015-08-12 04:13:18 +08:00
|
|
|
const char *
|
|
|
|
WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|
|
|
switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
|
|
|
|
case WebAssemblyISD::FIRST_NUMBER: break;
|
|
|
|
case WebAssemblyISD::RETURN: return "WebAssemblyISD::RETURN";
|
|
|
|
case WebAssemblyISD::ARGUMENT: return "WebAssemblyISD::ARGUMENT";
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-06-30 07:51:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// WebAssembly Lowering private implementation.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Lowering Code
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-07-23 05:28:15 +08:00
|
|
|
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");
|
2015-08-01 01:53:38 +08:00
|
|
|
if (IsVarArg)
|
|
|
|
fail(DL, DAG, "WebAssembly doesn't support varargs yet");
|
2015-07-23 05:28:15 +08:00
|
|
|
|
2015-08-01 01:53:38 +08:00
|
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
|
|
|
RetOps.append(OutVals.begin(), OutVals.end());
|
2015-08-01 05:04:18 +08:00
|
|
|
Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
|
2015-07-23 05:28:15 +08:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
2015-08-01 01:53:38 +08:00
|
|
|
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()?
|
2015-08-01 02:13:27 +08:00
|
|
|
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;
|
2015-08-01 01:53:38 +08:00
|
|
|
}
|
2015-07-23 05:28:15 +08:00
|
|
|
|
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
2015-06-30 07:51:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Other Lowering Code
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// WebAssembly Optimization Hooks
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
|
|
|
|
const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
|
|
|
|
const TargetMachine &TM) const {
|
|
|
|
return getDataSection();
|
|
|
|
}
|