[WebAssembly] Inline asm support.
[oota-llvm.git] / lib / Target / WebAssembly / WebAssemblyISelLowering.cpp
index c9be0b3f2df7a9861c5256e36d212627dcc09354..b79cbb18f5708fa31dd3bcc07f8c2ec952e01f60 100644 (file)
@@ -132,6 +132,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
     for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
                     ISD::FRINT})
       setOperationAction(Op, T, Legal);
+    // Support minnan and maxnan, which otherwise default to expand.
+    setOperationAction(ISD::FMINNAN, T, Legal);
+    setOperationAction(ISD::FMAXNAN, T, Legal);
   }
 
   for (auto T : {MVT::i32, MVT::i64}) {
@@ -172,6 +175,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
   for (auto T : MVT::integer_valuetypes())
     for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
       setLoadExtAction(Ext, T, MVT::i1, Promote);
+
+  // Trap lowers to wasm unreachable
+  setOperationAction(ISD::TRAP, MVT::Other, Legal);
 }
 
 FastISel *WebAssemblyTargetLowering::createFastISel(
@@ -205,6 +211,23 @@ WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
   return nullptr;
 }
 
+std::pair<unsigned, const TargetRegisterClass *>
+WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
+    const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
+  // First, see if this is a constraint that directly corresponds to a
+  // WebAssembly register class.
+  if (Constraint.size() == 1) {
+    switch (Constraint[0]) {
+    case 'r':
+      return std::make_pair(0U, &WebAssembly::I32RegClass);
+    default:
+      break;
+    }
+  }
+
+  return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
+}
+
 //===----------------------------------------------------------------------===//
 // WebAssembly Lowering private implementation.
 //===----------------------------------------------------------------------===//
@@ -229,19 +252,24 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
   MachineFunction &MF = DAG.getMachineFunction();
 
   CallingConv::ID CallConv = CLI.CallConv;
-  if (CallConv != CallingConv::C)
-    fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
-  if (CLI.IsTailCall || MF.getTarget().Options.GuaranteedTailCallOpt)
-    fail(DL, DAG, "WebAssembly doesn't support tail call yet");
+  if (CallConv != CallingConv::C &&
+      CallConv != CallingConv::Fast &&
+      CallConv != CallingConv::Cold)
+    fail(DL, DAG,
+         "WebAssembly doesn't support language-specific or target-specific "
+         "calling conventions yet");
   if (CLI.IsPatchPoint)
     fail(DL, DAG, "WebAssembly doesn't support patch point yet");
 
-  SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
-  SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
+  // WebAssembly doesn't currently support explicit tail calls. If they are
+  // required, fail. Otherwise, just disable them.
+  if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
+       MF.getTarget().Options.GuaranteedTailCallOpt) ||
+      (CLI.CS && CLI.CS->isMustTailCall()))
+    fail(DL, DAG, "WebAssembly doesn't support tail call yet");
+  CLI.IsTailCall = false;
 
-  bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet();
-  if (IsStructRet)
-    fail(DL, DAG, "WebAssembly doesn't support struct return yet");
+  SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
 
   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
   if (Ins.size() > 1)
@@ -300,6 +328,7 @@ SDValue WebAssemblyTargetLowering::LowerReturn(
     const SmallVectorImpl<ISD::OutputArg> &Outs,
     const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
     SelectionDAG &DAG) const {
+  MachineFunction &MF = DAG.getMachineFunction();
 
   assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
   if (CallConv != CallingConv::C)
@@ -311,6 +340,33 @@ SDValue WebAssemblyTargetLowering::LowerReturn(
   RetOps.append(OutVals.begin(), OutVals.end());
   Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
 
+  // Record the number and types of the return values.
+  for (const ISD::OutputArg &Out : Outs) {
+    if (Out.Flags.isZExt())
+      fail(DL, DAG, "WebAssembly hasn't implemented zext results");
+    if (Out.Flags.isSExt())
+      fail(DL, DAG, "WebAssembly hasn't implemented sext results");
+    if (Out.Flags.isInReg())
+      fail(DL, DAG, "WebAssembly hasn't implemented inreg results");
+    if (Out.Flags.isSRet())
+      fail(DL, DAG, "WebAssembly hasn't implemented sret results");
+    if (Out.Flags.isByVal())
+      fail(DL, DAG, "WebAssembly hasn't implemented byval results");
+    if (Out.Flags.isInAlloca())
+      fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
+    if (Out.Flags.isNest())
+      fail(DL, DAG, "WebAssembly hasn't implemented nest results");
+    if (Out.Flags.isReturned())
+      fail(DL, DAG, "WebAssembly hasn't implemented returned results");
+    if (Out.Flags.isInConsecutiveRegs())
+      fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
+    if (Out.Flags.isInConsecutiveRegsLast())
+      fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
+    if (!Out.IsFixed)
+      fail(DL, DAG, "WebAssembly doesn't support non-fixed results yet");
+    MF.getInfo<WebAssemblyFunctionInfo>()->addResult(Out.VT);
+  }
+
   return Chain;
 }
 
@@ -324,8 +380,6 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
     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) {
@@ -349,14 +403,15 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
       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));
+
+    // Record the number and types of arguments.
+    MF.getInfo<WebAssemblyFunctionInfo>()->addParam(In.VT);
     ++ArgNo;
   }
 
@@ -440,5 +495,6 @@ SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
 MCSection *WebAssemblyTargetObjectFile::SelectSectionForGlobal(
     const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
     const TargetMachine &TM) const {
-  return getDataSection();
+  // TODO: Be more sophisticated than this.
+  return isa<Function>(GV) ? getTextSection() : getDataSection();
 }