Index: lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp =================================================================== --- lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -146,11 +146,6 @@ if (OpNo < MII.get(MI->getOpcode()).getNumDefs()) O << '='; } else if (Op.isImm()) { - assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() || - (MII.get(MI->getOpcode()).TSFlags & - WebAssemblyII::VariableOpIsImmediate)) && - "WebAssemblyII::VariableOpIsImmediate should be set for " - "variable_ops immediate ops"); // TODO: (MII.get(MI->getOpcode()).TSFlags & // WebAssemblyII::VariableOpImmediateIsLabel) // can tell us whether this is an immediate referencing a label in the Index: lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -46,9 +46,8 @@ const MachineFrameInfo *MFI = MF.getFrameInfo(); const auto *RegInfo = MF.getSubtarget().getRegisterInfo(); - return MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() || - MFI->hasStackMap() || MFI->hasPatchPoint() || - RegInfo->needsStackRealignment(MF); + return MFI->hasVarSizedObjects() || MFI->hasStackMap() || + MFI->hasPatchPoint() || RegInfo->needsStackRealignment(MF); } /// Under normal circumstances, when a frame pointer is not required, we reserve @@ -61,68 +60,11 @@ return !MF.getFrameInfo()->hasVarSizedObjects(); } - -/// Adjust the stack pointer by a constant amount. -static void adjustStackPointer(unsigned StackSize, - bool AdjustUp, - MachineFunction& MF, - MachineBasicBlock& MBB, - const TargetInstrInfo* TII, - MachineBasicBlock::iterator InsertPt, - const DebugLoc& DL) { - assert((StackSize || !AdjustUp) && "Adjusting up by 0"); - auto &MRI = MF.getRegInfo(); - unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); - auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer"); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPReg) - .addExternalSymbol(SPSymbol); - // This MachinePointerInfo should reference __stack_pointer as well but - // doesn't because MachinePointerInfo() takes a GV which we don't have for - // __stack_pointer. TODO: check if PseudoSourceValue::ExternalSymbolCallEntry - // is appropriate instead. (likewise for EmitEpologue below) - auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(), - MachineMemOperand::MOLoad, 4, 4); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg) - .addImm(0) // offset - .addReg(SPReg) // addr - .addImm(2) // p2align - .addMemOperand(LoadMMO); - // Add/Subtract the frame size - unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) - .addImm(StackSize); - BuildMI(MBB, InsertPt, DL, - TII->get(AdjustUp ? WebAssembly::ADD_I32 : WebAssembly::SUB_I32), - WebAssembly::SP32) - .addReg(SPReg) - .addReg(OffsetReg); - // The SP32 register now has the new stacktop. Also write it back to memory. - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) - .addExternalSymbol(SPSymbol); - auto *MMO = new MachineMemOperand(MachinePointerInfo(), - MachineMemOperand::MOStore, 4, 4); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), WebAssembly::SP32) - .addImm(0) - .addReg(OffsetReg) - .addImm(2) // p2align - .addReg(WebAssembly::SP32) - .addMemOperand(MMO); -} - void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { - const auto *TII = MF.getSubtarget().getInstrInfo(); - DebugLoc DL = I->getDebugLoc(); - unsigned Opc = I->getOpcode(); - bool IsDestroy = Opc == TII->getCallFrameDestroyOpcode(); - unsigned Amount = I->getOperand(0).getImm(); - // TODO(dschuff): After we switch varargs to passing an explicit pointer - // rather than using an implicit call frame, assert here that Amount is 0 - // and remove adjustStackPointer altogether. - if (Amount) - adjustStackPointer(Amount, IsDestroy, MF, MBB, - TII, I, DL); + // TODO: can we avoid using call frame pseudos altogether? + assert(!I->getOperand(0).getImm()); MBB.erase(I); } @@ -132,10 +74,10 @@ auto *MFI = MF.getFrameInfo(); assert(MFI->getCalleeSavedInfo().empty() && "WebAssembly should not have callee-saved registers"); + assert(!MFI->isFrameAddressTaken()); uint64_t StackSize = MFI->getStackSize(); - if (!StackSize && !MFI->adjustsStack()) - return; + if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return; const auto *TII = MF.getSubtarget().getInstrInfo(); auto &MRI = MF.getRegInfo(); @@ -201,8 +143,7 @@ MachineBasicBlock &MBB) const { auto *MFI = MF.getFrameInfo(); uint64_t StackSize = MFI->getStackSize(); - if (!StackSize && !MFI->adjustsStack()) - return; + if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return; const auto *TII = MF.getSubtarget().getInstrInfo(); auto &MRI = MF.getRegInfo(); unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); Index: lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -339,9 +339,8 @@ CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); if (IsVarArg) { - // Outgoing non-fixed arguments are placed at the top of the stack. First - // compute their offsets and the total amount of argument stack space - // needed. + // Outgoing non-fixed arguments are placed in a buffer. First + // compute their offsets and the total amount of buffer space needed. for (SDValue Arg : make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) { EVT VT = Arg.getValueType(); @@ -358,17 +357,12 @@ unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); - SDValue NB; - if (NumBytes) { - NB = DAG.getConstant(NumBytes, DL, PtrVT, true); - Chain = DAG.getCALLSEQ_START(Chain, NB, DL); - } - - if (IsVarArg) { + SDValue FINode; + if (IsVarArg && NumBytes) { // For non-fixed arguments, next emit stores to store the argument values - // to the stack at the offsets computed above. - SDValue SP = DAG.getCopyFromReg( - Chain, DL, getStackPointerRegisterToSaveRestore(), PtrVT); + // to the stack buffer at the offsets computed above. + int FI = MF.getFrameInfo()->CreateStackObject(NumBytes, 16, + /*isSS=*/false); unsigned ValNo = 0; SmallVector Chains; for (SDValue Arg : @@ -376,14 +370,17 @@ assert(ArgLocs[ValNo].getValNo() == ValNo && "ArgLocs should remain in order and only hold varargs args"); unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); - SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, SP, + FINode = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode, DAG.getConstant(Offset, DL, PtrVT)); - Chains.push_back(DAG.getStore(Chain, DL, Arg, Add, - MachinePointerInfo::getStack(MF, Offset), - false, false, 0)); + Chains.push_back(DAG.getStore( + Chain, DL, Arg, Add, + MachinePointerInfo::getFixedStack(MF, FI, Offset), false, false, 0)); } if (!Chains.empty()) Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); + } else if (IsVarArg) { + FINode = DAG.getIntPtrConstant(0, DL); } // Compute the operands for the CALLn node. @@ -396,7 +393,7 @@ Ops.append(OutVals.begin(), IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); - SmallVector Tys; + SmallVector InTys; for (const auto &In : Ins) { assert(!In.Flags.isByVal() && "byval is not valid for return values"); assert(!In.Flags.isNest() && "nest is not valid for return values"); @@ -409,13 +406,17 @@ "WebAssembly hasn't implemented cons regs last return values"); // Ignore In.getOrigAlign() because all our arguments are passed in // registers. - Tys.push_back(In.VT); + InTys.push_back(In.VT); + } + // Add the pointer arg. its type is already + if (IsVarArg) { + Ops.push_back(FINode); } - Tys.push_back(MVT::Other); - SDVTList TyList = DAG.getVTList(Tys); + InTys.push_back(MVT::Other); + SDVTList InTyList = DAG.getVTList(InTys); SDValue Res = DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1, - DL, TyList, Ops); + DL, InTyList, Ops); if (Ins.empty()) { Chain = Res; } else { @@ -423,11 +424,6 @@ Chain = Res.getValue(1); } - if (NumBytes) { - SDValue Unused = DAG.getTargetConstant(0, DL, PtrVT); - Chain = DAG.getCALLSEQ_END(Chain, NB, Unused, SDValue(), DL); - } - return Chain; } @@ -469,7 +465,7 @@ } SDValue WebAssemblyTargetLowering::LowerFormalArguments( - SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Ins, SDLoc DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); @@ -502,8 +498,11 @@ MF.getInfo()->addParam(In.VT); } - // Incoming varargs arguments are on the stack and will be accessed through - // va_arg, so we don't need to do anything for them here. + // Varargs are copied into a buffer allocated by the caller, and a pointer to + // the buffer is passed as an argument. + if (IsVarArg) + MF.getInfo()->addParam( + getPointerTy(MF.getDataLayout())); return Chain; } @@ -613,15 +612,18 @@ SDLoc DL(Op); EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); - // The incoming non-fixed arguments are placed on the top of the stack, with - // natural alignment, at the point of the call, so the base pointer is just - // the current frame pointer. - DAG.getMachineFunction().getFrameInfo()->setFrameAddressIsTaken(true); - unsigned FP = - Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); - SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FP, PtrVT); + unsigned ArgNum = DAG.getMachineFunction() + .getInfo() + ->getParams() + .size() - + 1; + + // XXX if ARGUMENTS is not live-in to the block already this doesn't make it + // live in. const Value *SV = cast(Op.getOperand(2))->getValue(); - return DAG.getStore(Op.getOperand(0), DL, FrameAddr, Op.getOperand(1), + SDValue ArgN = DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT, + DAG.getTargetConstant(ArgNum, DL, MVT::i32)); + return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1), MachinePointerInfo(SV), false, false, 0); } Index: lib/Target/WebAssembly/known_gcc_test_failures.txt =================================================================== --- lib/Target/WebAssembly/known_gcc_test_failures.txt +++ lib/Target/WebAssembly/known_gcc_test_failures.txt @@ -54,7 +54,6 @@ 980709-1.c 990127-1.c -991216-2.c frame-address.c loop-15.c @@ -83,6 +82,12 @@ va-arg-10.c va-arg-pack-1.c +# live-in ARGUMENTS + 980716-1.c + va-arg-13.c + va-arg-14.c + va-arg-4.c + # Cannot select brind. 20071210-1.c 920501-4.c Index: test/CodeGen/WebAssembly/varargs.ll =================================================================== --- test/CodeGen/WebAssembly/varargs.ll +++ test/CodeGen/WebAssembly/varargs.ll @@ -8,13 +8,17 @@ ; Test va_start. ; TODO: Test va_start. - -;define void @start(i8** %ap, ...) { -;entry: -; %0 = bitcast i8** %ap to i8* -; call void @llvm.va_start(i8* %0) -; ret void -;} +; CHECK-LABEL: start: +; CHECK-NEXT: .param i32, i32 +; CHECK-NOT: __stack_pointer +define void @start(i8** %ap, ...) { +entry: + %0 = bitcast i8** %ap to i8* +; Store the second argument (the hidden vararg buffer pointer) into ap +; CHECK: i32.store $discard=, 0($0), $1 + call void @llvm.va_start(i8* %0) + ret void +} ; Test va_end. @@ -105,7 +109,8 @@ declare void @callee(...) ; CHECK-LABEL: caller_none: -; CHECK-NEXT: call callee@FUNCTION{{$}} +; CHECK-NEXT: i32.const $push0=, 0 +; CHECK-NEXT: call callee@FUNCTION, $pop0 ; CHECK-NEXT: return{{$}} define void @caller_none() { call void (...) @callee() @@ -125,6 +130,20 @@ ret void } +define void @startbb(i1 %cond, i8** %ap, ...) { +entry: + br i1 %cond, label %bb1, label %bb1 +bb0: + ret void +bb1: + %0 = bitcast i8** %ap to i8* +; Store the second argument (the hidden vararg buffer pointer) into ap +; CHEC K: i32.store $discard=, 0($0), $1 + %1 = va_arg i8** %ap, i32 + ret void +} + + declare void @llvm.va_start(i8*) declare void @llvm.va_end(i8*) declare void @llvm.va_copy(i8*, i8*)