This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] PR 38052 part 2: mips_save_reg_p mishandling $gp


This patch fixes the underlying problem in PR 38052: that mips_save_reg_p
was sometimes testing call_really_used_regs rather than TARGET_CALL_SAVED_GP
when handling $28.

The model we use for MIPS is that _all_ call_insns preserve $28 by default.
Thus on o32 abicalls targets, where $28 is call-clobbered, call_insns
represent a call followed an instruction to restore $28.  (This is also
what the JAL assembler macro does.)

When using explicit relocations, we split such calls into two after
reload.  The first instruction is a JALR or pic0 JAL, and its pattern
explicitly clobbers $28.  The second instruction is an explicit restore
of $28.

But mips_save_reg_p wants the ABI property rather than the call_insn
property, so it should always use TARGET_CALL_SAVED_GP over
call_really_used_regs[28].

The patch is based on an idea I suggested here:

  http://gcc.gnu.org/ml/gcc-patches/2008-10/msg00660.html

It splits out the "is this register call-saved?" logic and the
"does this function clobber this register?" logic into two separate
functions.  This avoids inappropriate uses of call_really_used_regs
and IMO makes the logic clearer.  It should also make it easier to
include Chao-Ying's patch in GCC 4.5.

Tested on mips64el-linux-gnu and applied.

Richard


gcc/
	PR target/38052
	* config/mips/mips.c (mips_cfun_call_saved_reg_p)
	(mips_cfun_might_clobber_call_saved_reg_p): New functions,
	split out from...
	(mips_save_reg_p): ...here.  Always consult TARGET_CALL_SAVED_GP
	rather than call_really_used_regs when handling $gp.

Index: gcc/config/mips/mips.c
===================================================================
*** gcc/config/mips/mips.c	2008-11-16 20:18:43.000000000 +0000
--- gcc/config/mips/mips.c	2008-11-16 20:20:16.000000000 +0000
*************** mips_global_pointer (void)
*** 8433,8480 ****
    return GLOBAL_POINTER_REGNUM;
  }
  
! /* Return true if the current function must save register REGNO.  */
  
  static bool
! mips_save_reg_p (unsigned int regno)
  {
!   /* We need to save $gp if TARGET_CALL_SAVED_GP and if we have not
!      chosen a call-clobbered substitute.  */
!   if (TARGET_CALL_SAVED_GP
!       && regno == GLOBAL_POINTER_REGNUM
!       && cfun->machine->global_pointer == regno)
      return true;
  
!   /* Check call-saved registers.  */
!   if ((crtl->saves_all_registers || df_regs_ever_live_p (regno))
!       && !call_really_used_regs[regno])
      return true;
  
!   /* Save both registers in an FPR pair if either one is used.  This is
!      needed for the case when MIN_FPRS_PER_FMT == 1, which allows the odd
!      register to be used without the even register.  */
!   if (FP_REG_P (regno)
!       && MAX_FPRS_PER_FMT == 2
!       && df_regs_ever_live_p (regno + 1)
!       && !call_really_used_regs[regno + 1])
      return true;
  
!   /* We need to save the old frame pointer before setting up a new one.  */
    if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
      return true;
  
!   /* Check for registers that must be saved for FUNCTION_PROFILER.  */
!   if (crtl->profile && MIPS_SAVE_REG_FOR_PROFILING_P (regno))
      return true;
  
!   /* We need to save the incoming return address if it is ever clobbered
!      within the function, if __builtin_eh_return is being used to set a
!      different return address, or if a stub is being used to return a
!      value in FPRs.  */
!   if (regno == GP_REG_FIRST + 31
!       && (df_regs_ever_live_p (regno)
! 	  || crtl->calls_eh_return
! 	  || mips16_cfun_returns_in_fpr_p ()))
      return true;
  
    return false;
--- 8433,8517 ----
    return GLOBAL_POINTER_REGNUM;
  }
  
! /* Return true if the current function should treat register REGNO
!    as call-saved.  */
  
  static bool
! mips_cfun_call_saved_reg_p (unsigned int regno)
! {
!   /* call_insns preserve $28 unless they explicitly say otherwise,
!      so call_really_used_regs[] treats $28 as call-saved.  However,
!      we want the ABI property rather than the default call_insn
!      property here.  */
!   return (regno == GLOBAL_POINTER_REGNUM
! 	  ? TARGET_CALL_SAVED_GP
! 	  : !call_really_used_regs[regno]);
! }
! 
! /* Return true if the function body might clobber register REGNO.
!    We know that REGNO is call-saved.  */
! 
! static bool
! mips_cfun_might_clobber_call_saved_reg_p (unsigned int regno)
  {
!   /* Some functions should be treated as clobbering all call-saved
!      registers.  */
!   if (crtl->saves_all_registers)
      return true;
  
!   /* DF handles cases where a register is explicitly referenced in
!      the rtl.  Incoming values are passed in call-clobbered registers,
!      so we can assume that any live call-saved register is set within
!      the function.  */
!   if (df_regs_ever_live_p (regno))
      return true;
  
!   /* Check for registers that are clobbered by FUNCTION_PROFILER.
!      These clobbers are not explicit in the rtl.  */
!   if (crtl->profile && MIPS_SAVE_REG_FOR_PROFILING_P (regno))
      return true;
  
!   /* If we're using a call-saved global pointer, the function's
!      prologue will need to set it up.  */
!   if (cfun->machine->global_pointer == regno)
!     return true;
! 
!   /* The function's prologue will need to set the frame pointer if
!      frame_pointer_needed.  */
    if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
      return true;
  
!   /* If a MIPS16 function returns a value in FPRs, its epilogue
!      will need to call an external libgcc routine.  This yet-to-be
!      generated call_insn will clobber $31.  */
!   if (regno == GP_REG_FIRST + 31 && mips16_cfun_returns_in_fpr_p ())
      return true;
  
!   return false;
! }
! 
! /* Return true if the current function must save register REGNO.  */
! 
! static bool
! mips_save_reg_p (unsigned int regno)
! {
!   if (mips_cfun_call_saved_reg_p (regno))
!     {
!       if (mips_cfun_might_clobber_call_saved_reg_p (regno))
! 	return true;
! 
!       /* Save both registers in an FPR pair if either one is used.  This is
! 	 needed for the case when MIN_FPRS_PER_FMT == 1, which allows the odd
! 	 register to be used without the even register.  */
!       if (FP_REG_P (regno)
! 	  && MAX_FPRS_PER_FMT == 2
! 	  && mips_cfun_might_clobber_call_saved_reg_p (regno + 1))
! 	return true;
!     }
! 
!   /* We need to save the incoming return address if __builtin_eh_return
!      is being used to set a different return address.  */
!   if (regno == GP_REG_FIRST + 31 && crtl->calls_eh_return)
      return true;
  
    return false;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]