Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ llvm/trunk/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 { Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ llvm/trunk/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(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(Op.getOperand(1))->getReg(), + Copy); + } + return SDValue(); +} + SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, SelectionDAG &DAG) const { int FI = cast(Op)->getIndex(); Index: llvm/trunk/lib/Target/WebAssembly/known_gcc_test_failures.txt =================================================================== --- llvm/trunk/lib/Target/WebAssembly/known_gcc_test_failures.txt +++ llvm/trunk/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 &): 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): 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 Index: llvm/trunk/test/CodeGen/WebAssembly/userstack.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/userstack.ll +++ llvm/trunk/test/CodeGen/WebAssembly/userstack.ll @@ -160,4 +160,25 @@ ret void } +; The use of the alloca in a phi causes a CopyToReg DAG node to be generated, +; which has to have special handling because CopyToReg can't have a FI operand +; CHECK-LABEL: copytoreg_fi: +define void @copytoreg_fi(i1 %cond, i32* %b) { +entry: + ; CHECK: i32.const [[L2:.+]]=, 16 + ; CHECK-NEXT: i32.sub [[SP:.+]]=, {{.+}}, [[L2]] + %addr = alloca i32 + ; CHECK: i32.const [[OFF:.+]]=, 12 + ; CHECK-NEXT: i32.add [[ADDR:.+]]=, [[SP]], [[OFF]] + ; CHECK-NEXT: copy_local [[COPY:.+]]=, [[ADDR]] + br label %body +body: + %a = phi i32* [%addr, %entry], [%b, %body] + store i32 1, i32* %a + ; CHECK: i32.store {{.*}}, 0([[COPY]]), + br i1 %cond, label %body, label %exit +exit: + ret void +} + ; TODO: test over-aligned alloca