Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -581,6 +581,11 @@ const ISD::ArgFlagsTy &Flags, bool isLittle, const CCValAssign &VA) const; + bool passArgUsingMemcpy(SDValue &Chain, const SDLoc &DL, SDValue StackPtr, + SelectionDAG &DAG, SDValue Arg, unsigned FirstReg, + unsigned LastReg, const ISD::ArgFlagsTy &Flags, + const CCValAssign &VA) const; + /// writeVarArgRegs - Write variable function arguments passed in registers /// to the stack. Also create a stack frame object for the first variable /// argument. Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -2986,6 +2986,38 @@ if (IsTailCall) ++NumTailCalls; + // Before initiation of function call, prepare args that need memcpy + CCInfo.rewindByValRegsInfo(); + SDValue StackPtr; + + // This pre-pass is to try to copy an argument to stack using memcpy. + // We use copyArgUsingMemcpy to keep track of which args are copied by memcpy. + SmallVector copyArgUsingMemcpy; + copyArgUsingMemcpy.resize(ArgLocs.size()); + unsigned byValCounter = 0; + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + ISD::ArgFlagsTy Flags = Outs[i].Flags; + SDValue Arg = OutVals[i]; + CCValAssign &VA = ArgLocs[i]; + if(Flags.isByVal()){ + StackPtr = + DAG.getCopyFromReg(Chain, DL, ABI.IsN64() ? Mips::SP_64 : Mips::SP, + getPointerTy(DAG.getDataLayout())); + unsigned FirstByValReg, LastByValReg; + unsigned ByValIdx = CCInfo.getInRegsParamsProcessed(); + CCInfo.getInRegsParamInfo(ByValIdx, FirstByValReg, LastByValReg); + // Here we call passArgUsingMemcpy which will try to + // copy an argument using memcpy, and if memcpy is used + // it retuns true. + bool useMemcpy = passArgUsingMemcpy(Chain, DL, StackPtr, DAG, Arg, + FirstByValReg, LastByValReg, Flags, + VA); + copyArgUsingMemcpy[byValCounter++] = useMemcpy; + + CCInfo.nextInRegsParam(); + } + } + // Chain is the output chain of the last Load/Store or CopyToReg node. // ByValChain is the output chain of the last Memcpy node created for copying // byval arguments to the stack. @@ -2996,7 +3028,7 @@ if (!IsTailCall) Chain = DAG.getCALLSEQ_START(Chain, NextStackOffset, 0, DL); - SDValue StackPtr = + StackPtr = DAG.getCopyFromReg(Chain, DL, ABI.IsN64() ? Mips::SP_64 : Mips::SP, getPointerTy(DAG.getDataLayout())); @@ -3004,6 +3036,7 @@ SmallVector MemOpChains; CCInfo.rewindByValRegsInfo(); + byValCounter = 0; // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { @@ -3015,6 +3048,11 @@ // ByVal Arg. if (Flags.isByVal()) { + // Check if argument is already copied using memcpy. + if (copyArgUsingMemcpy[byValCounter++]) { + CCInfo.nextInRegsParam(); + continue; + } unsigned FirstByValReg, LastByValReg; unsigned ByValIdx = CCInfo.getInRegsParamsProcessed(); CCInfo.getInRegsParamInfo(ByValIdx, FirstByValReg, LastByValReg); @@ -4091,6 +4129,49 @@ } } +// Try to copy byVal arg using memcpy +bool MipsTargetLowering::passArgUsingMemcpy( + SDValue &Chain, const SDLoc &DL, SDValue StackPtr, + SelectionDAG &DAG, SDValue Arg, unsigned FirstReg, + unsigned LastReg, const ISD::ArgFlagsTy &Flags, + const CCValAssign &VA) const { + unsigned ByValSizeInBytes = Flags.getByValSize(); + unsigned OffsetInBytes = 0; // From beginning of struct + unsigned RegSizeInBytes = Subtarget.getGPRSizeInBytes(); + unsigned Alignment = std::min(Flags.getByValAlign(), RegSizeInBytes); + EVT PtrTy = getPointerTy(DAG.getDataLayout()); + unsigned NumRegs = LastReg - FirstReg; + bool LeftoverBytes = (NumRegs * RegSizeInBytes > ByValSizeInBytes); + unsigned MemCpySize = ByValSizeInBytes - OffsetInBytes; + OffsetInBytes = (NumRegs - LeftoverBytes) * RegSizeInBytes; + + if (NumRegs) { + if (LeftoverBytes || OffsetInBytes == ByValSizeInBytes) { + return false; + } + } + + SDValue MemCpyCall; + SDValue Src = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(OffsetInBytes, DL, PtrTy)); + SDValue Dst = DAG.getNode(ISD::ADD, DL, PtrTy, StackPtr, + DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); + MemCpyCall = DAG.getMemcpy(Chain, DL, Dst, Src, + DAG.getConstant(MemCpySize, DL, PtrTy), + Alignment, /*isVolatile=*/false, + /*AlwaysInline=*/false, + /*isTailCall=*/false, + MachinePointerInfo(), MachinePointerInfo()); + // If the first node in returned MemCpyCall is CopyFromReg, + // it means that memcpy is used to copy an argument. + if (MemCpyCall.getNode()->getOpcode() == ISD::CopyFromReg) { + Chain = MemCpyCall; + return true; + } + + return false; +} + // Copy byVal arg to registers and stack. void MipsTargetLowering::passByValArg( SDValue Chain, const SDLoc &DL, @@ -4174,7 +4255,7 @@ } } - // Copy remainder of byval arg to it with memcpy. + // Copy remainder of byval arg to it with memcpy lowered to loads and stores. unsigned MemCpySize = ByValSizeInBytes - OffsetInBytes; SDValue Src = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, DAG.getConstant(OffsetInBytes, DL, PtrTy));