Index: lib/Target/X86/X86.td =================================================================== --- lib/Target/X86/X86.td (revision 301500) +++ lib/Target/X86/X86.td (working copy) @@ -235,6 +235,9 @@ "LEA instruction with certain arguments is slow">; def FeatureSlowIncDec : SubtargetFeature<"slow-incdec", "SlowIncDec", "true", "INC and DEC instructions are slower than ADD and SUB">; +def FeatureSaveArgs + : SubtargetFeature<"save-args", "SaveArgs", "true", + "Save register arguments on the stack.">; def FeatureSoftFloat : SubtargetFeature<"soft-float", "UseSoftFloat", "true", "Use software floating point features.">; Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp (revision 301500) +++ lib/Target/X86/X86FrameLowering.cpp (working copy) @@ -47,6 +47,7 @@ // standard x86_64 and NaCl use 64-bit frame/stack pointers, x32 - 32-bit. Uses64BitFramePtr = STI.isTarget64BitLP64() || STI.isTargetNaCl64(); StackPtr = TRI->getStackRegister(); + SaveArgs = STI.getSaveArgs(); } bool X86FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { @@ -83,7 +84,7 @@ /// or if frame pointer elimination is disabled. bool X86FrameLowering::hasFP(const MachineFunction &MF) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); - return (MF.getTarget().Options.DisableFramePointerElim(MF) || + return (MF.getTarget().Options.DisableFramePointerElim(MF) || SaveArgs || TRI->needsStackRealignment(MF) || MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() || MFI.hasOpaqueSPAdjustment() || @@ -850,6 +851,25 @@ MI->getOperand(3).setIsDead(); } +// FIXME: Get this from tablegen. +static ArrayRef get64BitArgumentGPRs(CallingConv::ID CallConv, + const X86Subtarget &Subtarget) { + assert(Subtarget.is64Bit()); + + if (Subtarget.isCallingConvWin64(CallConv)) { + static const MCPhysReg GPR64ArgRegsWin64[] = { + X86::RCX, X86::RDX, X86::R8, X86::R9 + }; + return makeArrayRef(std::begin(GPR64ArgRegsWin64), std::end(GPR64ArgRegsWin64)); + } + + static const MCPhysReg GPR64ArgRegs64Bit[] = { + X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9 + }; + return makeArrayRef(std::begin(GPR64ArgRegs64Bit), std::end(GPR64ArgRegs64Bit)); +} + + /// emitPrologue - Push callee-saved registers onto the stack, which /// automatically adjust the stack pointer. Adjust the stack pointer to allocate /// space for local variables. Also emit labels used by the exception handler to @@ -1123,6 +1143,36 @@ BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfaRegister( nullptr, DwarfFramePtr)); } + + if (SaveArgs) { + ArrayRef GPRs = + get64BitArgumentGPRs(Fn->getCallingConv(), STI); + unsigned arg_size = Fn->arg_size(); + unsigned RI = 0; + int64_t SaveSize = 0; + + for (MCPhysReg Reg : GPRs) { + if (++RI > arg_size) + break; + + SaveSize += SlotSize; + +#if 1 + BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r)) + .addReg(Reg) + .setMIFlag(MachineInstr::FrameSetup); +#else + // MOV64mr Reg, -SaveSize(%rbp) + addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64mr)), + FramePtr, true, -SaveSize) + .addReg(Reg) + .setMIFlag(MachineInstr::FrameSetup); +#endif + } + + StackSize += SaveSize; + MFI.setStackSize(StackSize); + } } // Mark the FramePtr as live-in in every block. Don't do this again for Index: lib/Target/X86/X86FrameLowering.h =================================================================== --- lib/Target/X86/X86FrameLowering.h (revision 301500) +++ lib/Target/X86/X86FrameLowering.h (working copy) @@ -36,6 +36,8 @@ unsigned SlotSize; + bool SaveArgs; + /// Is64Bit implies that x86_64 instructions are available. bool Is64Bit; Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp (revision 301500) +++ lib/Target/X86/X86Subtarget.cpp (working copy) @@ -312,6 +312,7 @@ SlowLEA = false; SlowIncDec = false; stackAlignment = 4; + SaveArgs = false; // FIXME: this is a known good value for Yonah. How about others? MaxInlineSizeThreshold = 128; UseSoftFloat = false; Index: lib/Target/X86/X86Subtarget.h =================================================================== --- lib/Target/X86/X86Subtarget.h (revision 301500) +++ lib/Target/X86/X86Subtarget.h (working copy) @@ -293,6 +293,9 @@ /// entry to the function and which must be maintained by every function. unsigned stackAlignment; + /// Whether function prologues should save register arguments on the stack. + bool SaveArgs; + /// Max. memset / memcpy size that is turned into rep/movs, rep/stos ops. /// unsigned MaxInlineSizeThreshold; @@ -356,6 +359,8 @@ return &getInstrInfo()->getRegisterInfo(); } + bool getSaveArgs() const { return SaveArgs; } + /// Returns the minimum alignment known to hold of the /// stack frame on entry to the function and which must be maintained by every /// function for this subtarget.