[WebAssembly] Insert COPY_LOCAL between CopyToReg and FrameIndex DAG nodes

CopyToReg nodes don't support FrameIndex operands. Other targets select
the FI to some LEA-like instruction, but since we don't have that, we
need to insert some kind of instruction that can take an FI operand and
produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
copy_local between Op and its FI operand. This results in a redundant
copy which we should optimize away later (maybe in the post-FI-lowering
peephole pass).

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

llvm-svn: 260987
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 436494e..2027e8b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -114,6 +114,7 @@
   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
 
   setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
+  setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
 
   // Expand these forms; we pattern-match the forms that we can handle in isel.
   for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
@@ -544,9 +545,34 @@
     case ISD::FRAMEADDR: // TODO: Make this return the userspace frame address
       fail(DL, DAG, "WebAssembly hasn't implemented __builtin_frame_address");
       return SDValue();
+    case ISD::CopyToReg:
+      return LowerCopyToReg(Op, DAG);
   }
 }
 
+SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
+                                                  SelectionDAG &DAG) const {
+  SDValue Src = Op.getOperand(2);
+  if (isa<FrameIndexSDNode>(Src.getNode())) {
+    // CopyToReg nodes don't support FrameIndex operands. Other targets select
+    // the FI to some LEA-like instruction, but since we don't have that, we
+    // need to insert some kind of instruction that can take an FI operand and
+    // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
+    // copy_local between Op and its FI operand.
+    SDLoc DL(Op);
+    EVT VT = Src.getValueType();
+    SDValue Copy(
+        DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_LOCAL_I32
+                                          : WebAssembly::COPY_LOCAL_I64,
+                           DL, VT, Src),
+        0);
+    return DAG.getCopyToReg(Op.getOperand(0), DL,
+                            cast<RegisterSDNode>(Op.getOperand(1))->getReg(),
+                            Copy);
+  }
+  return SDValue();
+}
+
 SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
                                                    SelectionDAG &DAG) const {
   int FI = cast<FrameIndexSDNode>(Op)->getIndex();
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
index a2fbfea..4aed2b1 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
@@ -83,6 +83,7 @@
   SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerCopyToReg(SDValue Op, SelectionDAG &DAG) const;
 };
 
 namespace WebAssembly {
diff --git a/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt b/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt
index 108ba6a..480c2c9 100644
--- a/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt
+++ b/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt
@@ -1,32 +1,9 @@
 # Tests which are known to fail from the GCC torture test suite.
 
-# InstrEmitter.cpp:302: unsigned int llvm::InstrEmitter::getVR(llvm::SDValue, DenseMap<llvm::SDValue, unsigned int> &): Assertion `I != VRBaseMap.end() && "Node emitted out of order - late"' failed.
-20000801-2.c
-20000815-1.c
-20011126-2.c
-20030916-1.c
-20050826-2.c
-20090113-1.c
-920501-6.c
-930518-1.c
-980707-1.c
-990127-1.c
-loop-15.c
-loop-ivopts-2.c
-pr20466-1.c
-pr28778.c
-pr33870-1.c
-pr33870.c
-pr38051.c
-pr39100.c
-pr49390.c
-pr53645-2.c
-pr53645.c
-pr59643.c
-
 # WebAssemblyCFGStackify.cpp:458: void PlaceMarkers(llvm::MachineFunction &, const llvm::MachineLoopInfo &, const llvm::WebAssemblyInstrInfo &, llvm::MachineDominatorTree &, llvm::WebAssemblyFunctionInfo &): Assertion `Stack.back() == &MBB && "Loop top should be balanced"' failed.
 20090113-2.c
 20090113-3.c
+loop-15.c
 930628-1.c
 
 
@@ -53,6 +30,12 @@
 # include/llvm/CodeGen/SelectionDAGNodes.h:800: llvm::SDNode::SDNode(unsigned int, unsigned int, llvm::DebugLoc, llvm::SDVTList, ArrayRef<llvm::SDValue>): Assertion `NumOperands == Ops.size() && "NumOperands wasn't wide enough for its operands!"' failed.
 pr28982b.c
 
+# SelectionDAGNodes.h:943: llvm::SDValue::SDValue(llvm::SDNode *, unsigned int): Assertion `(!Node || ResNo < Node->getNumValues()) && "Invalid result number for the given node!"' failed.
+pr53645.c
+pr53645-2.c
+
+# multiple-entry loops are not supported yet.
+pr38051.c
 
 # Computed gotos are not supported (Cannot select BlockAddress/BRIND)
 20040302-1.c