[2/3,ARC] Refurb eliminate regs.

Message ID 20190325110313.9271-3-claziss@gmail.com
State New
Headers show
Series
  • Improve register elimination, and other LRA
Related show

Commit Message

Claudiu Zissulescu March 25, 2019, 11:03 a.m.
Refurbish eliminable regs howto by introducing a fake
FRAME_POINTER_REGNUM with the purpose to release FP register to be
used freely by the register allocator.

gcc/
xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/arc/arc.c (arc_hard_regno_modes): Add two missing modes
	for last two fake registers.
	(arc_conditional_register_usage): Make sure fake frame and arg
	pointer regs are in general regs class.
	(FRAME_POINTER_MASK): Remove.
	(RETURN_ADDR_MASK): Remove.
	(arc_must_save_register): Use hard frame regnum.
	(frame_restore_reg): Use hard_frame_pointer_rtx.
	(arc_save_callee_saves): Likewise.
	(arc_restore_callee_saves): Likewise.
	(arc_save_callee_enter): Likewise.
	(arc_restore_callee_leave): Likewise.
	(arc_save_callee_milli): Likewise.
	(arc_eh_return_address_location): Likewise.
	(arc_check_multi): Use hard frame regnum.
	(arc_can_eliminate): Likewise.
	* config/arc/arc.h (FIXED_REGISTERS): Make FP register available
	for register allocator.
	(REG_CLASS_CONTENTS): Update GENERAL_REGS.
	(REGNO_OK_FOR_BASE_P): Consider FRAME_POINTER_REGNUM.
	(FRAME_POINTER_REGNUM): Change it to a fake register.
	(HARD_FRAME_POINTER_REGNUM): Defined.
	(ARG_POINTER_REGNUM): Change it to a new fake register.
	(ELIMINABLE_REGS): Update.
	(REGISTER_NAMES): Update names.
	* config/arc/arc.md (LP_START): Remove.
	(LP_END): Likewise.
	(shift_si3_loop): Update pattern.
---
 gcc/config/arc/arc.c  | 173 +++++++++++++++++++++++-------------------
 gcc/config/arc/arc.h  |  31 ++++----
 gcc/config/arc/arc.md |  12 +--
 3 files changed, 115 insertions(+), 101 deletions(-)

-- 
2.20.1

Comments

Andrew Burgess April 10, 2019, 9:54 p.m. | #1
* Claudiu Zissulescu <claziss@gmail.com> [2019-03-25 12:03:12 +0100]:

> Refurbish eliminable regs howto by introducing a fake

> FRAME_POINTER_REGNUM with the purpose to release FP register to be

> used freely by the register allocator.

> 

> gcc/

> xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>

> 

> 	* config/arc/arc.c (arc_hard_regno_modes): Add two missing modes

> 	for last two fake registers.

> 	(arc_conditional_register_usage): Make sure fake frame and arg

> 	pointer regs are in general regs class.

> 	(FRAME_POINTER_MASK): Remove.

> 	(RETURN_ADDR_MASK): Remove.

> 	(arc_must_save_register): Use hard frame regnum.

> 	(frame_restore_reg): Use hard_frame_pointer_rtx.

> 	(arc_save_callee_saves): Likewise.

> 	(arc_restore_callee_saves): Likewise.

> 	(arc_save_callee_enter): Likewise.

> 	(arc_restore_callee_leave): Likewise.

> 	(arc_save_callee_milli): Likewise.

> 	(arc_eh_return_address_location): Likewise.

> 	(arc_check_multi): Use hard frame regnum.

> 	(arc_can_eliminate): Likewise.

> 	* config/arc/arc.h (FIXED_REGISTERS): Make FP register available

> 	for register allocator.

> 	(REG_CLASS_CONTENTS): Update GENERAL_REGS.

> 	(REGNO_OK_FOR_BASE_P): Consider FRAME_POINTER_REGNUM.

> 	(FRAME_POINTER_REGNUM): Change it to a fake register.

> 	(HARD_FRAME_POINTER_REGNUM): Defined.

> 	(ARG_POINTER_REGNUM): Change it to a new fake register.

> 	(ELIMINABLE_REGS): Update.

> 	(REGISTER_NAMES): Update names.

> 	* config/arc/arc.md (LP_START): Remove.

> 	(LP_END): Likewise.

> 	(shift_si3_loop): Update pattern.


This is fine, thanks.

Andrew


> ---

>  gcc/config/arc/arc.c  | 173 +++++++++++++++++++++++-------------------

>  gcc/config/arc/arc.h  |  31 ++++----

>  gcc/config/arc/arc.md |  12 +--

>  3 files changed, 115 insertions(+), 101 deletions(-)

> 

> diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c

> index 62f435b0a1d..9938a774d91 100644

> --- a/gcc/config/arc/arc.c

> +++ b/gcc/config/arc/arc.c

> @@ -1651,7 +1651,8 @@ static unsigned int arc_hard_regno_modes[] = {

>    V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES,

>  

>    S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,

> -  S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES

> +  S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,

> +  S_MODES, S_MODES

>  };

>  

>  static unsigned int arc_mode_class [NUM_MACHINE_MODES];

> @@ -1886,7 +1887,8 @@ arc_conditional_register_usage (void)

>  

>    /* Handle Special Registers.  */

>    arc_regno_reg_class[CC_REG] = NO_REGS;      /* CC_REG: must be NO_REGS.  */

> -  arc_regno_reg_class[62] = GENERAL_REGS;

> +  arc_regno_reg_class[FRAME_POINTER_REGNUM] = GENERAL_REGS;

> +  arc_regno_reg_class[ARG_POINTER_REGNUM] = GENERAL_REGS;

>  

>    if (TARGET_DPFP)

>      for (i = R40_REG; i < R44_REG; ++i)

> @@ -2616,8 +2618,53 @@ arc_compute_function_type (struct function *fun)

>    return fun->machine->fn_type = fn_type;

>  }

>  

> -#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))

> -#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))

> +/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as

> +   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated

> +   Register Allocator) pass, while we want to get the frame size

> +   correct earlier than the IRA pass.

> +

> +   When a function uses eh_return we must ensure that the fp register

> +   is saved and then restored so that the unwinder can restore the

> +   correct value for the frame we are going to jump to.

> +

> +   To do this we force all frames that call eh_return to require a

> +   frame pointer (see arc_frame_pointer_required), this

> +   will ensure that the previous frame pointer is stored on entry to

> +   the function, and will then be reloaded at function exit.

> +

> +   As the frame pointer is handled as a special case in our prologue

> +   and epilogue code it must not be saved and restored using the

> +   MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC

> +   believes that the function is not using a frame pointer and that

> +   the value in the fp register is the frame pointer, while the

> +   prologue and epilogue are busy saving and restoring the fp

> +   register.

> +

> +   During compilation of a function the frame size is evaluated

> +   multiple times, it is not until the reload pass is complete the the

> +   frame size is considered fixed (it is at this point that space for

> +   all spills has been allocated).  However the frame_pointer_needed

> +   variable is not set true until the register allocation pass, as a

> +   result in the early stages the frame size does not include space

> +   for the frame pointer to be spilled.

> +

> +   The problem that this causes is that the rtl generated for

> +   EH_RETURN_HANDLER_RTX uses the details of the frame size to compute

> +   the offset from the frame pointer at which the return address

> +   lives.  However, in early passes GCC has not yet realised we need a

> +   frame pointer, and so has not included space for the frame pointer

> +   in the frame size, and so gets the offset of the return address

> +   wrong.  This should not be an issue as in later passes GCC has

> +   realised that the frame pointer needs to be spilled, and has

> +   increased the frame size.  However, the rtl for the

> +   EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger

> +   offset, and the wrong smaller offset is used.  */

> +

> +static bool

> +arc_frame_pointer_needed (void)

> +{

> +  return (frame_pointer_needed || crtl->calls_eh_return);

> +}

>  

>  /* Tell prologue and epilogue if register REGNO should be saved / restored.

>     The return address and frame pointer are treated separately.

> @@ -2656,16 +2703,28 @@ arc_must_save_register (int regno, struct function *func)

>        break;

>      }

>  

> -  if ((regno) != RETURN_ADDR_REGNUM

> -      && (regno) != FRAME_POINTER_REGNUM

> -      && (regno) != STACK_POINTER_REGNUM

> -      && df_regs_ever_live_p (regno)

> -      && (!call_used_regs[regno]

> -	  || ARC_INTERRUPT_P (fn_type))

> -      /* Do not emit code for auto saved regs.  */

> -      && !irq_auto_save_p

> -      && !firq_auto_save_p)

> -    return true;

> +  switch (regno)

> +    {

> +    case RETURN_ADDR_REGNUM:

> +    case STACK_POINTER_REGNUM:

> +      return false;

> +

> +    case HARD_FRAME_POINTER_REGNUM:

> +      /* If we need FP reg as a frame pointer then don't save it as a

> +	 regular reg.  */

> +      if (arc_frame_pointer_needed ())

> +	return false;

> +

> +      /* FALLTHRU */

> +    default:

> +      if (df_regs_ever_live_p (regno)

> +	  && (!call_used_regs[regno]

> +	      || ARC_INTERRUPT_P (fn_type))

> +	  /* Do not emit code for auto saved regs.  */

> +	  && !irq_auto_save_p

> +	  && !firq_auto_save_p)

> +	return true;

> +    }

>  

>    return false;

>  }

> @@ -2682,54 +2741,6 @@ arc_must_save_return_addr (struct function *func)

>    return false;

>  }

>  

> -/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as

> -   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated

> -   Register Allocator) pass, while we want to get the frame size

> -   correct earlier than the IRA pass.

> -

> -   When a function uses eh_return we must ensure that the fp register

> -   is saved and then restored so that the unwinder can restore the

> -   correct value for the frame we are going to jump to.

> -

> -   To do this we force all frames that call eh_return to require a

> -   frame pointer (see arc_frame_pointer_required), this

> -   will ensure that the previous frame pointer is stored on entry to

> -   the function, and will then be reloaded at function exit.

> -

> -   As the frame pointer is handled as a special case in our prologue

> -   and epilogue code it must not be saved and restored using the

> -   MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC

> -   believes that the function is not using a frame pointer and that

> -   the value in the fp register is the frame pointer, while the

> -   prologue and epilogue are busy saving and restoring the fp

> -   register.

> -

> -   During compilation of a function the frame size is evaluated

> -   multiple times, it is not until the reload pass is complete the the

> -   frame size is considered fixed (it is at this point that space for

> -   all spills has been allocated).  However the frame_pointer_needed

> -   variable is not set true until the register allocation pass, as a

> -   result in the early stages the frame size does not include space

> -   for the frame pointer to be spilled.

> -

> -   The problem that this causes is that the rtl generated for

> -   EH_RETURN_HANDLER_RTX uses the details of the frame size to compute

> -   the offset from the frame pointer at which the return address

> -   lives.  However, in early passes GCC has not yet realised we need a

> -   frame pointer, and so has not included space for the frame pointer

> -   in the frame size, and so gets the offset of the return address

> -   wrong.  This should not be an issue as in later passes GCC has

> -   realised that the frame pointer needs to be spilled, and has

> -   increased the frame size.  However, the rtl for the

> -   EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger

> -   offset, and the wrong smaller offset is used.  */

> -

> -static bool

> -arc_frame_pointer_needed (void)

> -{

> -  return (frame_pointer_needed || crtl->calls_eh_return);

> -}

> -

>  /* Return non-zero if there are registers to be saved or loaded using

>     millicode thunks.  We can only use consecutive sequences starting

>     with r13, and not going beyond r25.

> @@ -2991,7 +3002,7 @@ frame_restore_reg (rtx reg, HOST_WIDE_INT offset)

>    insn = frame_move_inc (reg, addr, stack_pointer_rtx, 0);

>    add_reg_note (insn, REG_CFA_RESTORE, reg);

>  

> -  if (reg == frame_pointer_rtx)

> +  if (reg == hard_frame_pointer_rtx)

>      add_reg_note (insn, REG_CFA_DEF_CFA,

>  		  plus_constant (Pmode, stack_pointer_rtx,

>  				 GET_MODE_SIZE (GET_MODE (reg)) + offset));

> @@ -3077,13 +3088,13 @@ arc_save_callee_saves (unsigned int gmask,

>       registers are saved.  */

>    if (save_fp)

>      {

> -      frame_allocated += frame_save_reg (frame_pointer_rtx, offset);

> +      frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);

>        offset = 0;

>      }

>  

>    /* Emit mov fp,sp.  */

>    if (arc_frame_pointer_needed ())

> -    frame_move (frame_pointer_rtx, stack_pointer_rtx);

> +    frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);

>  

>    return frame_allocated;

>  }

> @@ -3106,7 +3117,7 @@ arc_restore_callee_saves (unsigned int gmask,

>    /* Emit mov fp,sp.  */

>    if (arc_frame_pointer_needed () && offset)

>      {

> -      frame_move (stack_pointer_rtx, frame_pointer_rtx);

> +      frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);

>        frame_deallocated += offset;

>        offset = 0;

>      }

> @@ -3115,7 +3126,7 @@ arc_restore_callee_saves (unsigned int gmask,

>      {

>        /* Any offset is taken care by previous if-statement.  */

>        gcc_assert (offset == 0);

> -      frame_deallocated += frame_restore_reg (frame_pointer_rtx, 0);

> +      frame_deallocated += frame_restore_reg (hard_frame_pointer_rtx, 0);

>      }

>  

>    if (offset)

> @@ -3260,11 +3271,11 @@ arc_save_callee_enter (unsigned int gmask,

>        mem = gen_frame_mem (Pmode, plus_constant (Pmode,

>  						 stack_pointer_rtx,

>  						 off));

> -      XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, frame_pointer_rtx);

> +      XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, hard_frame_pointer_rtx);

>        RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;

>        off -= UNITS_PER_WORD;

>  

> -      XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx,

> +      XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx,

>  					     stack_pointer_rtx);

>        RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;

>        save_fp = false;

> @@ -3368,7 +3379,7 @@ arc_restore_callee_leave (unsigned int gmask,

>        mem = gen_frame_mem (Pmode, plus_constant (Pmode,

>  						 stack_pointer_rtx,

>  						 off));

> -      XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx, mem);

> +      XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx, mem);

>        RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;

>        off -= UNITS_PER_WORD;

>      }

> @@ -3387,7 +3398,7 @@ arc_restore_callee_leave (unsigned int gmask,

>    /* Dwarf related info.  */

>    if (restore_fp)

>      {

> -      add_reg_note (insn, REG_CFA_RESTORE, frame_pointer_rtx);

> +      add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);

>        add_reg_note (insn, REG_CFA_DEF_CFA,

>  		    plus_constant (Pmode, stack_pointer_rtx,

>  				   offset + nregs * UNITS_PER_WORD));

> @@ -3525,11 +3536,11 @@ arc_save_callee_milli (unsigned int gmask,

>       above loop to save fp because our ABI states fp goes aftert all

>       registers are saved.  */

>    if (save_fp)

> -    frame_allocated += frame_save_reg (frame_pointer_rtx, offset);

> +    frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);

>  

>    /* Emit mov fp,sp.  */

>    if (arc_frame_pointer_needed ())

> -    frame_move (frame_pointer_rtx, stack_pointer_rtx);

> +    frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);

>  

>    return frame_allocated;

>  }

> @@ -3559,13 +3570,13 @@ arc_restore_callee_milli (unsigned int gmask,

>    /* Emit mov fp,sp.  */

>    if (arc_frame_pointer_needed () && offset)

>      {

> -      frame_move (stack_pointer_rtx, frame_pointer_rtx);

> +      frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);

>        frame_allocated = offset;

>        offset = 0;

>      }

>  

>    if (restore_fp)

> -    frame_allocated += frame_restore_reg (frame_pointer_rtx, 0);

> +    frame_allocated += frame_restore_reg (hard_frame_pointer_rtx, 0);

>  

>    if (offset)

>      {

> @@ -3875,7 +3886,7 @@ arc_check_multi (rtx op, bool push_p)

>        if (REGNO (reg) == RETURN_ADDR_REGNUM

>  	  && i == start)

>  	regno = 12;

> -      else if (REGNO (reg) == FRAME_POINTER_REGNUM)

> +      else if (REGNO (reg) == HARD_FRAME_POINTER_REGNUM)

>  	++i;

>        else if (REGNO (reg) != regno)

>  	return false;

> @@ -3922,7 +3933,7 @@ arc_eh_return_address_location (rtx source)

>       included in the 'extra_size' field.  */

>    offset = afi->reg_size + afi->extra_size - 4;

>    mem = gen_frame_mem (Pmode,

> -		       plus_constant (Pmode, frame_pointer_rtx, offset));

> +		       plus_constant (Pmode, hard_frame_pointer_rtx, offset));

>  

>    /* The following should not be needed, and is, really a hack.  The

>       issue being worked around here is that the DSE (Dead Store

> @@ -5396,7 +5407,7 @@ arc_final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED,

>  static bool

>  arc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)

>  {

> -  return ((to == FRAME_POINTER_REGNUM) || !arc_frame_pointer_needed ());

> +  return ((to == HARD_FRAME_POINTER_REGNUM) || (to == STACK_POINTER_REGNUM));

>  }

>  

>  /* Define the offset between two registers, one to be eliminated, and

> @@ -5408,7 +5419,7 @@ arc_initial_elimination_offset (int from, int to)

>    if (!cfun->machine->frame_info.initialized)

>      arc_compute_frame_size ();

>  

> -  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)

> +  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)

>      {

>        return (cfun->machine->frame_info.extra_size

>  	      + cfun->machine->frame_info.reg_size);

> @@ -5427,6 +5438,8 @@ arc_initial_elimination_offset (int from, int to)

>  	      + cfun->machine->frame_info.extra_size

>  	      + cfun->machine->frame_info.reg_size));

>      }

> +  if ((from == FRAME_POINTER_REGNUM) && (to == HARD_FRAME_POINTER_REGNUM))

> +    return 0;

>  

>    gcc_unreachable ();

>  }

> @@ -11024,7 +11037,7 @@ arc_builtin_setjmp_frame_value (void)

>       frame pointer value for this frame (if the use of the frame pointer

>       had not been removed).  We really do want the raw frame pointer

>       register value.  */

> -  return gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);

> +  return gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM);

>  }

>  

>  /* Return nonzero if a jli call should be generated for a call from

> diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h

> index 6a77869b58c..fbe71278346 100644

> --- a/gcc/config/arc/arc.h

> +++ b/gcc/config/arc/arc.h

> @@ -325,7 +325,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT		\

>     argument pointer.  */

>  

>  /* r63 is pc, r64-r127 = simd vregs, r128-r143 = simd dma config regs

> -   r144, r145 = lp_start, lp_end

> +   r144, r145 = ARG_POINTER, FRAME_POINTER

>     and therefore the pseudo registers start from r146. */

>  #define FIRST_PSEUDO_REGISTER 146

>  

> @@ -366,7 +366,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT		\

>  { 0, 0, 0, 0, 0, 0, 0, 0,	\

>    0, 0, 0, 0, 0, 0, 0, 0,	\

>    0, 0, 0, 0, 0, 0, 0, 0,	\

> -  0, 0, 1, 1, 1, 1, 1, 1,	\

> +  0, 0, 1, 0, 1, 1, 1, 1,	\

>  				\

>    1, 1, 1, 1, 1, 1, 1, 1,	\

>    0, 0, 0, 0, 1, 1, 1, 1,	\

> @@ -398,7 +398,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT		\

>    1, 1, 1, 1, 1, 1, 1, 1,	\

>    1, 1, 1, 1, 1, 0, 0, 0,	\

>    0, 0, 0, 0, 0, 0, 0, 0,	\

> -  0, 0, 1, 1, 1, 1, 1, 1,	\

> +  0, 0, 1, 0, 1, 1, 1, 1,	\

>  				\

>    1, 1, 1, 1, 1, 1, 1, 1,	\

>    1, 1, 1, 1, 1, 1, 1, 1,	\

> @@ -511,10 +511,10 @@ enum reg_class

>    {0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsd'.  */ \

>    {0x0000000f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rcd'.  */ \

>    {0x0000f00f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'q'.  */ \

> -  {0x1c001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'.  */ \

> +  {0x00001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'.  */ \

>    {0x9fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'h'.  */ \

>    {0x00000000, 0x00000f00, 0x00000000, 0x00000000, 0x00000000}, /* 'D'.  */ \

> -  {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00000000}, /* 'r'.  */ \

> +  {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00030000}, /* 'r'.  */ \

>    {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000}, /* 'v'.  */ \

>    {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000ffff}, /* 'd'.  */ \

>    {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0003ffff} /* ALL_REGS.  */\

> @@ -562,11 +562,14 @@ extern enum reg_class arc_regno_reg_class[];

>     Since they use reg_renumber, they are safe only once reg_renumber

>     has been allocated, which happens in local-alloc.c.  */

>  #define REGNO_OK_FOR_BASE_P(REGNO)					\

> -  ((REGNO) < 29 || ((REGNO) == ARG_POINTER_REGNUM) || ((REGNO) == 63)	\

> +  ((REGNO) < 29								\

> +   || ((REGNO) == ARG_POINTER_REGNUM)					\

> +   || ((REGNO) == FRAME_POINTER_REGNUM)					\

> +   || ((REGNO) == PCL_REG)						\

>     || ((unsigned) reg_renumber[REGNO] < 29)				\

>     || ((unsigned) (REGNO) == (unsigned) arc_tp_regno)			\

>     || (fixed_regs[REGNO] == 0 && IN_RANGE (REGNO, 32, 59))		\

> -   || ((REGNO) == 30 && fixed_regs[REGNO] == 0))

> +   || (fixed_regs[REGNO] == 0 && (REGNO) == R30_REG))

>  

>  #define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)

>  

> @@ -652,11 +655,12 @@ arc_return_addr_rtx(COUNT,FRAME)

>  #define STACK_POINTER_REGNUM 28

>  

>  /* Base register for access to local variables of the function.  */

> -#define FRAME_POINTER_REGNUM 27

> +#define FRAME_POINTER_REGNUM 145

> +#define HARD_FRAME_POINTER_REGNUM 27

>  

>  /* Base register for access to arguments of the function. This register

>     will be eliminated into either fp or sp.  */

> -#define ARG_POINTER_REGNUM 62

> +#define ARG_POINTER_REGNUM 144

>  

>  #define RETURN_ADDR_REGNUM 31

>  

> @@ -766,8 +770,9 @@ arc_return_addr_rtx(COUNT,FRAME)

>  

>  #define ELIMINABLE_REGS					\

>  {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},		\

> - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},		\

> - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}

> + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},	\

> + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},	\

> + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}

>  

>  /* Define the offset between two registers, one to be eliminated, and the other

>     its replacement, at the start of a routine.  */

> @@ -1161,7 +1166,7 @@ extern char rname56[], rname57[], rname58[], rname59[];

>    "r32",  "r33",  "r34",  "r35",      "r36",    "r37",    "r38",   "r39",	\

>     "d1",   "d1",   "d2",   "d2",      "r44",    "r45",    "r46",   "r47",	\

>    "r48",  "r49",  "r50",  "r51",      "r52",    "r53",    "r54",   "r55",	\

> -  rname56,rname57,rname58,rname59,"lp_count",    "cc",     "ap",   "pcl",	\

> +  rname56,rname57,rname58,rname59,"lp_count",    "cc",   "limm",   "pcl",	\

>    "vr0",  "vr1",  "vr2",  "vr3",      "vr4",    "vr5",    "vr6",   "vr7",       \

>    "vr8",  "vr9", "vr10", "vr11",     "vr12",   "vr13",   "vr14",  "vr15",	\

>   "vr16", "vr17", "vr18", "vr19",     "vr20",   "vr21",   "vr22",  "vr23",	\

> @@ -1172,7 +1177,7 @@ extern char rname56[], rname57[], rname58[], rname59[];

>   "vr56", "vr57", "vr58", "vr59",     "vr60",   "vr61",   "vr62",  "vr63",	\

>    "dr0",  "dr1",  "dr2",  "dr3",      "dr4",    "dr5",    "dr6",   "dr7",	\

>    "dr0",  "dr1",  "dr2",  "dr3",      "dr4",    "dr5",    "dr6",   "dr7",	\

> -  "lp_start", "lp_end" \

> +  "arg", "frame" \

>  }

>  

>  #define ADDITIONAL_REGISTER_NAMES		\

> diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md

> index 3a903d4224a..7ac5a1b5785 100644

> --- a/gcc/config/arc/arc.md

> +++ b/gcc/config/arc/arc.md

> @@ -202,8 +202,6 @@

>     (LP_COUNT 60)

>     (CC_REG 61)

>     (PCL_REG 63)

> -   (LP_START 144)

> -   (LP_END 145)

>    ]

>  )

>  

> @@ -3467,8 +3465,6 @@ core_3, archs4x, archs4xd, archs4xd_slow"

>  			    (match_operand:SI 2 "nonmemory_operand" "rn,Cal")]))

>     (clobber (match_scratch:SI 4 "=X,X"))

>     (clobber (reg:SI LP_COUNT))

> -   (clobber (reg:SI LP_START))

> -   (clobber (reg:SI LP_END))

>     (clobber (reg:CC CC_REG))

>    ]

>    "!TARGET_BARREL_SHIFTER"

> @@ -6508,7 +6504,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

>    {

>     int len = XVECLEN (operands[0], 0);

>     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

>       {

>        operands[3] = XEXP (tmp, 0);

>        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> @@ -6538,7 +6534,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

>    {

>     int len = XVECLEN (operands[0], 0);

>     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

>       {

>        operands[3] = XEXP (tmp, 0);

>        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> @@ -6569,7 +6565,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

>    {

>     int len = XVECLEN (operands[0], 0);

>     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

>       {

>        operands[3] = XEXP (tmp, 0);

>        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> @@ -6600,7 +6596,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

>    {

>     int len = XVECLEN (operands[0], 0);

>     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

>       {

>        operands[3] = XEXP (tmp, 0);

>        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> -- 

> 2.20.1

>
Claudiu Zissulescu April 16, 2019, 10:22 a.m. | #2
Committed. Thank you,
Claudiu

On Thu, Apr 11, 2019 at 12:54 AM Andrew Burgess
<andrew.burgess@embecosm.com> wrote:
>

> * Claudiu Zissulescu <claziss@gmail.com> [2019-03-25 12:03:12 +0100]:

>

> > Refurbish eliminable regs howto by introducing a fake

> > FRAME_POINTER_REGNUM with the purpose to release FP register to be

> > used freely by the register allocator.

> >

> > gcc/

> > xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>

> >

> >       * config/arc/arc.c (arc_hard_regno_modes): Add two missing modes

> >       for last two fake registers.

> >       (arc_conditional_register_usage): Make sure fake frame and arg

> >       pointer regs are in general regs class.

> >       (FRAME_POINTER_MASK): Remove.

> >       (RETURN_ADDR_MASK): Remove.

> >       (arc_must_save_register): Use hard frame regnum.

> >       (frame_restore_reg): Use hard_frame_pointer_rtx.

> >       (arc_save_callee_saves): Likewise.

> >       (arc_restore_callee_saves): Likewise.

> >       (arc_save_callee_enter): Likewise.

> >       (arc_restore_callee_leave): Likewise.

> >       (arc_save_callee_milli): Likewise.

> >       (arc_eh_return_address_location): Likewise.

> >       (arc_check_multi): Use hard frame regnum.

> >       (arc_can_eliminate): Likewise.

> >       * config/arc/arc.h (FIXED_REGISTERS): Make FP register available

> >       for register allocator.

> >       (REG_CLASS_CONTENTS): Update GENERAL_REGS.

> >       (REGNO_OK_FOR_BASE_P): Consider FRAME_POINTER_REGNUM.

> >       (FRAME_POINTER_REGNUM): Change it to a fake register.

> >       (HARD_FRAME_POINTER_REGNUM): Defined.

> >       (ARG_POINTER_REGNUM): Change it to a new fake register.

> >       (ELIMINABLE_REGS): Update.

> >       (REGISTER_NAMES): Update names.

> >       * config/arc/arc.md (LP_START): Remove.

> >       (LP_END): Likewise.

> >       (shift_si3_loop): Update pattern.

>

> This is fine, thanks.

>

> Andrew

>

>

> > ---

> >  gcc/config/arc/arc.c  | 173 +++++++++++++++++++++++-------------------

> >  gcc/config/arc/arc.h  |  31 ++++----

> >  gcc/config/arc/arc.md |  12 +--

> >  3 files changed, 115 insertions(+), 101 deletions(-)

> >

> > diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c

> > index 62f435b0a1d..9938a774d91 100644

> > --- a/gcc/config/arc/arc.c

> > +++ b/gcc/config/arc/arc.c

> > @@ -1651,7 +1651,8 @@ static unsigned int arc_hard_regno_modes[] = {

> >    V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES,

> >

> >    S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,

> > -  S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES

> > +  S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,

> > +  S_MODES, S_MODES

> >  };

> >

> >  static unsigned int arc_mode_class [NUM_MACHINE_MODES];

> > @@ -1886,7 +1887,8 @@ arc_conditional_register_usage (void)

> >

> >    /* Handle Special Registers.  */

> >    arc_regno_reg_class[CC_REG] = NO_REGS;      /* CC_REG: must be NO_REGS.  */

> > -  arc_regno_reg_class[62] = GENERAL_REGS;

> > +  arc_regno_reg_class[FRAME_POINTER_REGNUM] = GENERAL_REGS;

> > +  arc_regno_reg_class[ARG_POINTER_REGNUM] = GENERAL_REGS;

> >

> >    if (TARGET_DPFP)

> >      for (i = R40_REG; i < R44_REG; ++i)

> > @@ -2616,8 +2618,53 @@ arc_compute_function_type (struct function *fun)

> >    return fun->machine->fn_type = fn_type;

> >  }

> >

> > -#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))

> > -#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))

> > +/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as

> > +   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated

> > +   Register Allocator) pass, while we want to get the frame size

> > +   correct earlier than the IRA pass.

> > +

> > +   When a function uses eh_return we must ensure that the fp register

> > +   is saved and then restored so that the unwinder can restore the

> > +   correct value for the frame we are going to jump to.

> > +

> > +   To do this we force all frames that call eh_return to require a

> > +   frame pointer (see arc_frame_pointer_required), this

> > +   will ensure that the previous frame pointer is stored on entry to

> > +   the function, and will then be reloaded at function exit.

> > +

> > +   As the frame pointer is handled as a special case in our prologue

> > +   and epilogue code it must not be saved and restored using the

> > +   MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC

> > +   believes that the function is not using a frame pointer and that

> > +   the value in the fp register is the frame pointer, while the

> > +   prologue and epilogue are busy saving and restoring the fp

> > +   register.

> > +

> > +   During compilation of a function the frame size is evaluated

> > +   multiple times, it is not until the reload pass is complete the the

> > +   frame size is considered fixed (it is at this point that space for

> > +   all spills has been allocated).  However the frame_pointer_needed

> > +   variable is not set true until the register allocation pass, as a

> > +   result in the early stages the frame size does not include space

> > +   for the frame pointer to be spilled.

> > +

> > +   The problem that this causes is that the rtl generated for

> > +   EH_RETURN_HANDLER_RTX uses the details of the frame size to compute

> > +   the offset from the frame pointer at which the return address

> > +   lives.  However, in early passes GCC has not yet realised we need a

> > +   frame pointer, and so has not included space for the frame pointer

> > +   in the frame size, and so gets the offset of the return address

> > +   wrong.  This should not be an issue as in later passes GCC has

> > +   realised that the frame pointer needs to be spilled, and has

> > +   increased the frame size.  However, the rtl for the

> > +   EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger

> > +   offset, and the wrong smaller offset is used.  */

> > +

> > +static bool

> > +arc_frame_pointer_needed (void)

> > +{

> > +  return (frame_pointer_needed || crtl->calls_eh_return);

> > +}

> >

> >  /* Tell prologue and epilogue if register REGNO should be saved / restored.

> >     The return address and frame pointer are treated separately.

> > @@ -2656,16 +2703,28 @@ arc_must_save_register (int regno, struct function *func)

> >        break;

> >      }

> >

> > -  if ((regno) != RETURN_ADDR_REGNUM

> > -      && (regno) != FRAME_POINTER_REGNUM

> > -      && (regno) != STACK_POINTER_REGNUM

> > -      && df_regs_ever_live_p (regno)

> > -      && (!call_used_regs[regno]

> > -       || ARC_INTERRUPT_P (fn_type))

> > -      /* Do not emit code for auto saved regs.  */

> > -      && !irq_auto_save_p

> > -      && !firq_auto_save_p)

> > -    return true;

> > +  switch (regno)

> > +    {

> > +    case RETURN_ADDR_REGNUM:

> > +    case STACK_POINTER_REGNUM:

> > +      return false;

> > +

> > +    case HARD_FRAME_POINTER_REGNUM:

> > +      /* If we need FP reg as a frame pointer then don't save it as a

> > +      regular reg.  */

> > +      if (arc_frame_pointer_needed ())

> > +     return false;

> > +

> > +      /* FALLTHRU */

> > +    default:

> > +      if (df_regs_ever_live_p (regno)

> > +       && (!call_used_regs[regno]

> > +           || ARC_INTERRUPT_P (fn_type))

> > +       /* Do not emit code for auto saved regs.  */

> > +       && !irq_auto_save_p

> > +       && !firq_auto_save_p)

> > +     return true;

> > +    }

> >

> >    return false;

> >  }

> > @@ -2682,54 +2741,6 @@ arc_must_save_return_addr (struct function *func)

> >    return false;

> >  }

> >

> > -/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as

> > -   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated

> > -   Register Allocator) pass, while we want to get the frame size

> > -   correct earlier than the IRA pass.

> > -

> > -   When a function uses eh_return we must ensure that the fp register

> > -   is saved and then restored so that the unwinder can restore the

> > -   correct value for the frame we are going to jump to.

> > -

> > -   To do this we force all frames that call eh_return to require a

> > -   frame pointer (see arc_frame_pointer_required), this

> > -   will ensure that the previous frame pointer is stored on entry to

> > -   the function, and will then be reloaded at function exit.

> > -

> > -   As the frame pointer is handled as a special case in our prologue

> > -   and epilogue code it must not be saved and restored using the

> > -   MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC

> > -   believes that the function is not using a frame pointer and that

> > -   the value in the fp register is the frame pointer, while the

> > -   prologue and epilogue are busy saving and restoring the fp

> > -   register.

> > -

> > -   During compilation of a function the frame size is evaluated

> > -   multiple times, it is not until the reload pass is complete the the

> > -   frame size is considered fixed (it is at this point that space for

> > -   all spills has been allocated).  However the frame_pointer_needed

> > -   variable is not set true until the register allocation pass, as a

> > -   result in the early stages the frame size does not include space

> > -   for the frame pointer to be spilled.

> > -

> > -   The problem that this causes is that the rtl generated for

> > -   EH_RETURN_HANDLER_RTX uses the details of the frame size to compute

> > -   the offset from the frame pointer at which the return address

> > -   lives.  However, in early passes GCC has not yet realised we need a

> > -   frame pointer, and so has not included space for the frame pointer

> > -   in the frame size, and so gets the offset of the return address

> > -   wrong.  This should not be an issue as in later passes GCC has

> > -   realised that the frame pointer needs to be spilled, and has

> > -   increased the frame size.  However, the rtl for the

> > -   EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger

> > -   offset, and the wrong smaller offset is used.  */

> > -

> > -static bool

> > -arc_frame_pointer_needed (void)

> > -{

> > -  return (frame_pointer_needed || crtl->calls_eh_return);

> > -}

> > -

> >  /* Return non-zero if there are registers to be saved or loaded using

> >     millicode thunks.  We can only use consecutive sequences starting

> >     with r13, and not going beyond r25.

> > @@ -2991,7 +3002,7 @@ frame_restore_reg (rtx reg, HOST_WIDE_INT offset)

> >    insn = frame_move_inc (reg, addr, stack_pointer_rtx, 0);

> >    add_reg_note (insn, REG_CFA_RESTORE, reg);

> >

> > -  if (reg == frame_pointer_rtx)

> > +  if (reg == hard_frame_pointer_rtx)

> >      add_reg_note (insn, REG_CFA_DEF_CFA,

> >                 plus_constant (Pmode, stack_pointer_rtx,

> >                                GET_MODE_SIZE (GET_MODE (reg)) + offset));

> > @@ -3077,13 +3088,13 @@ arc_save_callee_saves (unsigned int gmask,

> >       registers are saved.  */

> >    if (save_fp)

> >      {

> > -      frame_allocated += frame_save_reg (frame_pointer_rtx, offset);

> > +      frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);

> >        offset = 0;

> >      }

> >

> >    /* Emit mov fp,sp.  */

> >    if (arc_frame_pointer_needed ())

> > -    frame_move (frame_pointer_rtx, stack_pointer_rtx);

> > +    frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);

> >

> >    return frame_allocated;

> >  }

> > @@ -3106,7 +3117,7 @@ arc_restore_callee_saves (unsigned int gmask,

> >    /* Emit mov fp,sp.  */

> >    if (arc_frame_pointer_needed () && offset)

> >      {

> > -      frame_move (stack_pointer_rtx, frame_pointer_rtx);

> > +      frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);

> >        frame_deallocated += offset;

> >        offset = 0;

> >      }

> > @@ -3115,7 +3126,7 @@ arc_restore_callee_saves (unsigned int gmask,

> >      {

> >        /* Any offset is taken care by previous if-statement.  */

> >        gcc_assert (offset == 0);

> > -      frame_deallocated += frame_restore_reg (frame_pointer_rtx, 0);

> > +      frame_deallocated += frame_restore_reg (hard_frame_pointer_rtx, 0);

> >      }

> >

> >    if (offset)

> > @@ -3260,11 +3271,11 @@ arc_save_callee_enter (unsigned int gmask,

> >        mem = gen_frame_mem (Pmode, plus_constant (Pmode,

> >                                                stack_pointer_rtx,

> >                                                off));

> > -      XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, frame_pointer_rtx);

> > +      XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, hard_frame_pointer_rtx);

> >        RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;

> >        off -= UNITS_PER_WORD;

> >

> > -      XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx,

> > +      XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx,

> >                                            stack_pointer_rtx);

> >        RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;

> >        save_fp = false;

> > @@ -3368,7 +3379,7 @@ arc_restore_callee_leave (unsigned int gmask,

> >        mem = gen_frame_mem (Pmode, plus_constant (Pmode,

> >                                                stack_pointer_rtx,

> >                                                off));

> > -      XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx, mem);

> > +      XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx, mem);

> >        RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;

> >        off -= UNITS_PER_WORD;

> >      }

> > @@ -3387,7 +3398,7 @@ arc_restore_callee_leave (unsigned int gmask,

> >    /* Dwarf related info.  */

> >    if (restore_fp)

> >      {

> > -      add_reg_note (insn, REG_CFA_RESTORE, frame_pointer_rtx);

> > +      add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);

> >        add_reg_note (insn, REG_CFA_DEF_CFA,

> >                   plus_constant (Pmode, stack_pointer_rtx,

> >                                  offset + nregs * UNITS_PER_WORD));

> > @@ -3525,11 +3536,11 @@ arc_save_callee_milli (unsigned int gmask,

> >       above loop to save fp because our ABI states fp goes aftert all

> >       registers are saved.  */

> >    if (save_fp)

> > -    frame_allocated += frame_save_reg (frame_pointer_rtx, offset);

> > +    frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);

> >

> >    /* Emit mov fp,sp.  */

> >    if (arc_frame_pointer_needed ())

> > -    frame_move (frame_pointer_rtx, stack_pointer_rtx);

> > +    frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);

> >

> >    return frame_allocated;

> >  }

> > @@ -3559,13 +3570,13 @@ arc_restore_callee_milli (unsigned int gmask,

> >    /* Emit mov fp,sp.  */

> >    if (arc_frame_pointer_needed () && offset)

> >      {

> > -      frame_move (stack_pointer_rtx, frame_pointer_rtx);

> > +      frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);

> >        frame_allocated = offset;

> >        offset = 0;

> >      }

> >

> >    if (restore_fp)

> > -    frame_allocated += frame_restore_reg (frame_pointer_rtx, 0);

> > +    frame_allocated += frame_restore_reg (hard_frame_pointer_rtx, 0);

> >

> >    if (offset)

> >      {

> > @@ -3875,7 +3886,7 @@ arc_check_multi (rtx op, bool push_p)

> >        if (REGNO (reg) == RETURN_ADDR_REGNUM

> >         && i == start)

> >       regno = 12;

> > -      else if (REGNO (reg) == FRAME_POINTER_REGNUM)

> > +      else if (REGNO (reg) == HARD_FRAME_POINTER_REGNUM)

> >       ++i;

> >        else if (REGNO (reg) != regno)

> >       return false;

> > @@ -3922,7 +3933,7 @@ arc_eh_return_address_location (rtx source)

> >       included in the 'extra_size' field.  */

> >    offset = afi->reg_size + afi->extra_size - 4;

> >    mem = gen_frame_mem (Pmode,

> > -                    plus_constant (Pmode, frame_pointer_rtx, offset));

> > +                    plus_constant (Pmode, hard_frame_pointer_rtx, offset));

> >

> >    /* The following should not be needed, and is, really a hack.  The

> >       issue being worked around here is that the DSE (Dead Store

> > @@ -5396,7 +5407,7 @@ arc_final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED,

> >  static bool

> >  arc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)

> >  {

> > -  return ((to == FRAME_POINTER_REGNUM) || !arc_frame_pointer_needed ());

> > +  return ((to == HARD_FRAME_POINTER_REGNUM) || (to == STACK_POINTER_REGNUM));

> >  }

> >

> >  /* Define the offset between two registers, one to be eliminated, and

> > @@ -5408,7 +5419,7 @@ arc_initial_elimination_offset (int from, int to)

> >    if (!cfun->machine->frame_info.initialized)

> >      arc_compute_frame_size ();

> >

> > -  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)

> > +  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)

> >      {

> >        return (cfun->machine->frame_info.extra_size

> >             + cfun->machine->frame_info.reg_size);

> > @@ -5427,6 +5438,8 @@ arc_initial_elimination_offset (int from, int to)

> >             + cfun->machine->frame_info.extra_size

> >             + cfun->machine->frame_info.reg_size));

> >      }

> > +  if ((from == FRAME_POINTER_REGNUM) && (to == HARD_FRAME_POINTER_REGNUM))

> > +    return 0;

> >

> >    gcc_unreachable ();

> >  }

> > @@ -11024,7 +11037,7 @@ arc_builtin_setjmp_frame_value (void)

> >       frame pointer value for this frame (if the use of the frame pointer

> >       had not been removed).  We really do want the raw frame pointer

> >       register value.  */

> > -  return gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);

> > +  return gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM);

> >  }

> >

> >  /* Return nonzero if a jli call should be generated for a call from

> > diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h

> > index 6a77869b58c..fbe71278346 100644

> > --- a/gcc/config/arc/arc.h

> > +++ b/gcc/config/arc/arc.h

> > @@ -325,7 +325,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT             \

> >     argument pointer.  */

> >

> >  /* r63 is pc, r64-r127 = simd vregs, r128-r143 = simd dma config regs

> > -   r144, r145 = lp_start, lp_end

> > +   r144, r145 = ARG_POINTER, FRAME_POINTER

> >     and therefore the pseudo registers start from r146. */

> >  #define FIRST_PSEUDO_REGISTER 146

> >

> > @@ -366,7 +366,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT             \

> >  { 0, 0, 0, 0, 0, 0, 0, 0,    \

> >    0, 0, 0, 0, 0, 0, 0, 0,    \

> >    0, 0, 0, 0, 0, 0, 0, 0,    \

> > -  0, 0, 1, 1, 1, 1, 1, 1,    \

> > +  0, 0, 1, 0, 1, 1, 1, 1,    \

> >                               \

> >    1, 1, 1, 1, 1, 1, 1, 1,    \

> >    0, 0, 0, 0, 1, 1, 1, 1,    \

> > @@ -398,7 +398,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT             \

> >    1, 1, 1, 1, 1, 1, 1, 1,    \

> >    1, 1, 1, 1, 1, 0, 0, 0,    \

> >    0, 0, 0, 0, 0, 0, 0, 0,    \

> > -  0, 0, 1, 1, 1, 1, 1, 1,    \

> > +  0, 0, 1, 0, 1, 1, 1, 1,    \

> >                               \

> >    1, 1, 1, 1, 1, 1, 1, 1,    \

> >    1, 1, 1, 1, 1, 1, 1, 1,    \

> > @@ -511,10 +511,10 @@ enum reg_class

> >    {0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsd'.  */ \

> >    {0x0000000f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rcd'.  */ \

> >    {0x0000f00f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'q'.  */ \

> > -  {0x1c001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'.  */ \

> > +  {0x00001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'.  */ \

> >    {0x9fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'h'.  */ \

> >    {0x00000000, 0x00000f00, 0x00000000, 0x00000000, 0x00000000}, /* 'D'.  */ \

> > -  {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00000000}, /* 'r'.  */ \

> > +  {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00030000}, /* 'r'.  */ \

> >    {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000}, /* 'v'.  */ \

> >    {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000ffff}, /* 'd'.  */ \

> >    {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0003ffff} /* ALL_REGS.  */\

> > @@ -562,11 +562,14 @@ extern enum reg_class arc_regno_reg_class[];

> >     Since they use reg_renumber, they are safe only once reg_renumber

> >     has been allocated, which happens in local-alloc.c.  */

> >  #define REGNO_OK_FOR_BASE_P(REGNO)                                   \

> > -  ((REGNO) < 29 || ((REGNO) == ARG_POINTER_REGNUM) || ((REGNO) == 63)        \

> > +  ((REGNO) < 29                                                              \

> > +   || ((REGNO) == ARG_POINTER_REGNUM)                                        \

> > +   || ((REGNO) == FRAME_POINTER_REGNUM)                                      \

> > +   || ((REGNO) == PCL_REG)                                           \

> >     || ((unsigned) reg_renumber[REGNO] < 29)                          \

> >     || ((unsigned) (REGNO) == (unsigned) arc_tp_regno)                        \

> >     || (fixed_regs[REGNO] == 0 && IN_RANGE (REGNO, 32, 59))           \

> > -   || ((REGNO) == 30 && fixed_regs[REGNO] == 0))

> > +   || (fixed_regs[REGNO] == 0 && (REGNO) == R30_REG))

> >

> >  #define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)

> >

> > @@ -652,11 +655,12 @@ arc_return_addr_rtx(COUNT,FRAME)

> >  #define STACK_POINTER_REGNUM 28

> >

> >  /* Base register for access to local variables of the function.  */

> > -#define FRAME_POINTER_REGNUM 27

> > +#define FRAME_POINTER_REGNUM 145

> > +#define HARD_FRAME_POINTER_REGNUM 27

> >

> >  /* Base register for access to arguments of the function. This register

> >     will be eliminated into either fp or sp.  */

> > -#define ARG_POINTER_REGNUM 62

> > +#define ARG_POINTER_REGNUM 144

> >

> >  #define RETURN_ADDR_REGNUM 31

> >

> > @@ -766,8 +770,9 @@ arc_return_addr_rtx(COUNT,FRAME)

> >

> >  #define ELIMINABLE_REGS                                      \

> >  {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},         \

> > - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},         \

> > - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}

> > + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},    \

> > + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},       \

> > + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}

> >

> >  /* Define the offset between two registers, one to be eliminated, and the other

> >     its replacement, at the start of a routine.  */

> > @@ -1161,7 +1166,7 @@ extern char rname56[], rname57[], rname58[], rname59[];

> >    "r32",  "r33",  "r34",  "r35",      "r36",    "r37",    "r38",   "r39",    \

> >     "d1",   "d1",   "d2",   "d2",      "r44",    "r45",    "r46",   "r47",    \

> >    "r48",  "r49",  "r50",  "r51",      "r52",    "r53",    "r54",   "r55",    \

> > -  rname56,rname57,rname58,rname59,"lp_count",    "cc",     "ap",   "pcl",    \

> > +  rname56,rname57,rname58,rname59,"lp_count",    "cc",   "limm",   "pcl",    \

> >    "vr0",  "vr1",  "vr2",  "vr3",      "vr4",    "vr5",    "vr6",   "vr7",       \

> >    "vr8",  "vr9", "vr10", "vr11",     "vr12",   "vr13",   "vr14",  "vr15",    \

> >   "vr16", "vr17", "vr18", "vr19",     "vr20",   "vr21",   "vr22",  "vr23",    \

> > @@ -1172,7 +1177,7 @@ extern char rname56[], rname57[], rname58[], rname59[];

> >   "vr56", "vr57", "vr58", "vr59",     "vr60",   "vr61",   "vr62",  "vr63",    \

> >    "dr0",  "dr1",  "dr2",  "dr3",      "dr4",    "dr5",    "dr6",   "dr7",    \

> >    "dr0",  "dr1",  "dr2",  "dr3",      "dr4",    "dr5",    "dr6",   "dr7",    \

> > -  "lp_start", "lp_end" \

> > +  "arg", "frame" \

> >  }

> >

> >  #define ADDITIONAL_REGISTER_NAMES            \

> > diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md

> > index 3a903d4224a..7ac5a1b5785 100644

> > --- a/gcc/config/arc/arc.md

> > +++ b/gcc/config/arc/arc.md

> > @@ -202,8 +202,6 @@

> >     (LP_COUNT 60)

> >     (CC_REG 61)

> >     (PCL_REG 63)

> > -   (LP_START 144)

> > -   (LP_END 145)

> >    ]

> >  )

> >

> > @@ -3467,8 +3465,6 @@ core_3, archs4x, archs4xd, archs4xd_slow"

> >                           (match_operand:SI 2 "nonmemory_operand" "rn,Cal")]))

> >     (clobber (match_scratch:SI 4 "=X,X"))

> >     (clobber (reg:SI LP_COUNT))

> > -   (clobber (reg:SI LP_START))

> > -   (clobber (reg:SI LP_END))

> >     (clobber (reg:CC CC_REG))

> >    ]

> >    "!TARGET_BARREL_SHIFTER"

> > @@ -6508,7 +6504,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

> >    {

> >     int len = XVECLEN (operands[0], 0);

> >     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> > -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> > +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

> >       {

> >        operands[3] = XEXP (tmp, 0);

> >        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> > @@ -6538,7 +6534,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

> >    {

> >     int len = XVECLEN (operands[0], 0);

> >     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> > -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> > +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

> >       {

> >        operands[3] = XEXP (tmp, 0);

> >        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> > @@ -6569,7 +6565,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

> >    {

> >     int len = XVECLEN (operands[0], 0);

> >     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> > -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> > +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

> >       {

> >        operands[3] = XEXP (tmp, 0);

> >        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> > @@ -6600,7 +6596,7 @@ core_3, archs4x, archs4xd, archs4xd_slow"

> >    {

> >     int len = XVECLEN (operands[0], 0);

> >     rtx tmp = XVECEXP (operands[0], 0, len - 1);

> > -   if (XEXP (tmp, 0) != frame_pointer_rtx)

> > +   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)

> >       {

> >        operands[3] = XEXP (tmp, 0);

> >        gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));

> > --

> > 2.20.1

> >

Patch

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 62f435b0a1d..9938a774d91 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -1651,7 +1651,8 @@  static unsigned int arc_hard_regno_modes[] = {
   V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES,
 
   S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
-  S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES
+  S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
+  S_MODES, S_MODES
 };
 
 static unsigned int arc_mode_class [NUM_MACHINE_MODES];
@@ -1886,7 +1887,8 @@  arc_conditional_register_usage (void)
 
   /* Handle Special Registers.  */
   arc_regno_reg_class[CC_REG] = NO_REGS;      /* CC_REG: must be NO_REGS.  */
-  arc_regno_reg_class[62] = GENERAL_REGS;
+  arc_regno_reg_class[FRAME_POINTER_REGNUM] = GENERAL_REGS;
+  arc_regno_reg_class[ARG_POINTER_REGNUM] = GENERAL_REGS;
 
   if (TARGET_DPFP)
     for (i = R40_REG; i < R44_REG; ++i)
@@ -2616,8 +2618,53 @@  arc_compute_function_type (struct function *fun)
   return fun->machine->fn_type = fn_type;
 }
 
-#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
-#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
+/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as
+   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
+   Register Allocator) pass, while we want to get the frame size
+   correct earlier than the IRA pass.
+
+   When a function uses eh_return we must ensure that the fp register
+   is saved and then restored so that the unwinder can restore the
+   correct value for the frame we are going to jump to.
+
+   To do this we force all frames that call eh_return to require a
+   frame pointer (see arc_frame_pointer_required), this
+   will ensure that the previous frame pointer is stored on entry to
+   the function, and will then be reloaded at function exit.
+
+   As the frame pointer is handled as a special case in our prologue
+   and epilogue code it must not be saved and restored using the
+   MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC
+   believes that the function is not using a frame pointer and that
+   the value in the fp register is the frame pointer, while the
+   prologue and epilogue are busy saving and restoring the fp
+   register.
+
+   During compilation of a function the frame size is evaluated
+   multiple times, it is not until the reload pass is complete the the
+   frame size is considered fixed (it is at this point that space for
+   all spills has been allocated).  However the frame_pointer_needed
+   variable is not set true until the register allocation pass, as a
+   result in the early stages the frame size does not include space
+   for the frame pointer to be spilled.
+
+   The problem that this causes is that the rtl generated for
+   EH_RETURN_HANDLER_RTX uses the details of the frame size to compute
+   the offset from the frame pointer at which the return address
+   lives.  However, in early passes GCC has not yet realised we need a
+   frame pointer, and so has not included space for the frame pointer
+   in the frame size, and so gets the offset of the return address
+   wrong.  This should not be an issue as in later passes GCC has
+   realised that the frame pointer needs to be spilled, and has
+   increased the frame size.  However, the rtl for the
+   EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger
+   offset, and the wrong smaller offset is used.  */
+
+static bool
+arc_frame_pointer_needed (void)
+{
+  return (frame_pointer_needed || crtl->calls_eh_return);
+}
 
 /* Tell prologue and epilogue if register REGNO should be saved / restored.
    The return address and frame pointer are treated separately.
@@ -2656,16 +2703,28 @@  arc_must_save_register (int regno, struct function *func)
       break;
     }
 
-  if ((regno) != RETURN_ADDR_REGNUM
-      && (regno) != FRAME_POINTER_REGNUM
-      && (regno) != STACK_POINTER_REGNUM
-      && df_regs_ever_live_p (regno)
-      && (!call_used_regs[regno]
-	  || ARC_INTERRUPT_P (fn_type))
-      /* Do not emit code for auto saved regs.  */
-      && !irq_auto_save_p
-      && !firq_auto_save_p)
-    return true;
+  switch (regno)
+    {
+    case RETURN_ADDR_REGNUM:
+    case STACK_POINTER_REGNUM:
+      return false;
+
+    case HARD_FRAME_POINTER_REGNUM:
+      /* If we need FP reg as a frame pointer then don't save it as a
+	 regular reg.  */
+      if (arc_frame_pointer_needed ())
+	return false;
+
+      /* FALLTHRU */
+    default:
+      if (df_regs_ever_live_p (regno)
+	  && (!call_used_regs[regno]
+	      || ARC_INTERRUPT_P (fn_type))
+	  /* Do not emit code for auto saved regs.  */
+	  && !irq_auto_save_p
+	  && !firq_auto_save_p)
+	return true;
+    }
 
   return false;
 }
@@ -2682,54 +2741,6 @@  arc_must_save_return_addr (struct function *func)
   return false;
 }
 
-/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as
-   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
-   Register Allocator) pass, while we want to get the frame size
-   correct earlier than the IRA pass.
-
-   When a function uses eh_return we must ensure that the fp register
-   is saved and then restored so that the unwinder can restore the
-   correct value for the frame we are going to jump to.
-
-   To do this we force all frames that call eh_return to require a
-   frame pointer (see arc_frame_pointer_required), this
-   will ensure that the previous frame pointer is stored on entry to
-   the function, and will then be reloaded at function exit.
-
-   As the frame pointer is handled as a special case in our prologue
-   and epilogue code it must not be saved and restored using the
-   MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC
-   believes that the function is not using a frame pointer and that
-   the value in the fp register is the frame pointer, while the
-   prologue and epilogue are busy saving and restoring the fp
-   register.
-
-   During compilation of a function the frame size is evaluated
-   multiple times, it is not until the reload pass is complete the the
-   frame size is considered fixed (it is at this point that space for
-   all spills has been allocated).  However the frame_pointer_needed
-   variable is not set true until the register allocation pass, as a
-   result in the early stages the frame size does not include space
-   for the frame pointer to be spilled.
-
-   The problem that this causes is that the rtl generated for
-   EH_RETURN_HANDLER_RTX uses the details of the frame size to compute
-   the offset from the frame pointer at which the return address
-   lives.  However, in early passes GCC has not yet realised we need a
-   frame pointer, and so has not included space for the frame pointer
-   in the frame size, and so gets the offset of the return address
-   wrong.  This should not be an issue as in later passes GCC has
-   realised that the frame pointer needs to be spilled, and has
-   increased the frame size.  However, the rtl for the
-   EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger
-   offset, and the wrong smaller offset is used.  */
-
-static bool
-arc_frame_pointer_needed (void)
-{
-  return (frame_pointer_needed || crtl->calls_eh_return);
-}
-
 /* Return non-zero if there are registers to be saved or loaded using
    millicode thunks.  We can only use consecutive sequences starting
    with r13, and not going beyond r25.
@@ -2991,7 +3002,7 @@  frame_restore_reg (rtx reg, HOST_WIDE_INT offset)
   insn = frame_move_inc (reg, addr, stack_pointer_rtx, 0);
   add_reg_note (insn, REG_CFA_RESTORE, reg);
 
-  if (reg == frame_pointer_rtx)
+  if (reg == hard_frame_pointer_rtx)
     add_reg_note (insn, REG_CFA_DEF_CFA,
 		  plus_constant (Pmode, stack_pointer_rtx,
 				 GET_MODE_SIZE (GET_MODE (reg)) + offset));
@@ -3077,13 +3088,13 @@  arc_save_callee_saves (unsigned int gmask,
      registers are saved.  */
   if (save_fp)
     {
-      frame_allocated += frame_save_reg (frame_pointer_rtx, offset);
+      frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);
       offset = 0;
     }
 
   /* Emit mov fp,sp.  */
   if (arc_frame_pointer_needed ())
-    frame_move (frame_pointer_rtx, stack_pointer_rtx);
+    frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);
 
   return frame_allocated;
 }
@@ -3106,7 +3117,7 @@  arc_restore_callee_saves (unsigned int gmask,
   /* Emit mov fp,sp.  */
   if (arc_frame_pointer_needed () && offset)
     {
-      frame_move (stack_pointer_rtx, frame_pointer_rtx);
+      frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);
       frame_deallocated += offset;
       offset = 0;
     }
@@ -3115,7 +3126,7 @@  arc_restore_callee_saves (unsigned int gmask,
     {
       /* Any offset is taken care by previous if-statement.  */
       gcc_assert (offset == 0);
-      frame_deallocated += frame_restore_reg (frame_pointer_rtx, 0);
+      frame_deallocated += frame_restore_reg (hard_frame_pointer_rtx, 0);
     }
 
   if (offset)
@@ -3260,11 +3271,11 @@  arc_save_callee_enter (unsigned int gmask,
       mem = gen_frame_mem (Pmode, plus_constant (Pmode,
 						 stack_pointer_rtx,
 						 off));
-      XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, frame_pointer_rtx);
+      XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, hard_frame_pointer_rtx);
       RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;
       off -= UNITS_PER_WORD;
 
-      XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx,
+      XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx,
 					     stack_pointer_rtx);
       RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;
       save_fp = false;
@@ -3368,7 +3379,7 @@  arc_restore_callee_leave (unsigned int gmask,
       mem = gen_frame_mem (Pmode, plus_constant (Pmode,
 						 stack_pointer_rtx,
 						 off));
-      XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx, mem);
+      XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx, mem);
       RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;
       off -= UNITS_PER_WORD;
     }
@@ -3387,7 +3398,7 @@  arc_restore_callee_leave (unsigned int gmask,
   /* Dwarf related info.  */
   if (restore_fp)
     {
-      add_reg_note (insn, REG_CFA_RESTORE, frame_pointer_rtx);
+      add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
       add_reg_note (insn, REG_CFA_DEF_CFA,
 		    plus_constant (Pmode, stack_pointer_rtx,
 				   offset + nregs * UNITS_PER_WORD));
@@ -3525,11 +3536,11 @@  arc_save_callee_milli (unsigned int gmask,
      above loop to save fp because our ABI states fp goes aftert all
      registers are saved.  */
   if (save_fp)
-    frame_allocated += frame_save_reg (frame_pointer_rtx, offset);
+    frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);
 
   /* Emit mov fp,sp.  */
   if (arc_frame_pointer_needed ())
-    frame_move (frame_pointer_rtx, stack_pointer_rtx);
+    frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);
 
   return frame_allocated;
 }
@@ -3559,13 +3570,13 @@  arc_restore_callee_milli (unsigned int gmask,
   /* Emit mov fp,sp.  */
   if (arc_frame_pointer_needed () && offset)
     {
-      frame_move (stack_pointer_rtx, frame_pointer_rtx);
+      frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);
       frame_allocated = offset;
       offset = 0;
     }
 
   if (restore_fp)
-    frame_allocated += frame_restore_reg (frame_pointer_rtx, 0);
+    frame_allocated += frame_restore_reg (hard_frame_pointer_rtx, 0);
 
   if (offset)
     {
@@ -3875,7 +3886,7 @@  arc_check_multi (rtx op, bool push_p)
       if (REGNO (reg) == RETURN_ADDR_REGNUM
 	  && i == start)
 	regno = 12;
-      else if (REGNO (reg) == FRAME_POINTER_REGNUM)
+      else if (REGNO (reg) == HARD_FRAME_POINTER_REGNUM)
 	++i;
       else if (REGNO (reg) != regno)
 	return false;
@@ -3922,7 +3933,7 @@  arc_eh_return_address_location (rtx source)
      included in the 'extra_size' field.  */
   offset = afi->reg_size + afi->extra_size - 4;
   mem = gen_frame_mem (Pmode,
-		       plus_constant (Pmode, frame_pointer_rtx, offset));
+		       plus_constant (Pmode, hard_frame_pointer_rtx, offset));
 
   /* The following should not be needed, and is, really a hack.  The
      issue being worked around here is that the DSE (Dead Store
@@ -5396,7 +5407,7 @@  arc_final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED,
 static bool
 arc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
 {
-  return ((to == FRAME_POINTER_REGNUM) || !arc_frame_pointer_needed ());
+  return ((to == HARD_FRAME_POINTER_REGNUM) || (to == STACK_POINTER_REGNUM));
 }
 
 /* Define the offset between two registers, one to be eliminated, and
@@ -5408,7 +5419,7 @@  arc_initial_elimination_offset (int from, int to)
   if (!cfun->machine->frame_info.initialized)
     arc_compute_frame_size ();
 
-  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
     {
       return (cfun->machine->frame_info.extra_size
 	      + cfun->machine->frame_info.reg_size);
@@ -5427,6 +5438,8 @@  arc_initial_elimination_offset (int from, int to)
 	      + cfun->machine->frame_info.extra_size
 	      + cfun->machine->frame_info.reg_size));
     }
+  if ((from == FRAME_POINTER_REGNUM) && (to == HARD_FRAME_POINTER_REGNUM))
+    return 0;
 
   gcc_unreachable ();
 }
@@ -11024,7 +11037,7 @@  arc_builtin_setjmp_frame_value (void)
      frame pointer value for this frame (if the use of the frame pointer
      had not been removed).  We really do want the raw frame pointer
      register value.  */
-  return gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
+  return gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM);
 }
 
 /* Return nonzero if a jli call should be generated for a call from
diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h
index 6a77869b58c..fbe71278346 100644
--- a/gcc/config/arc/arc.h
+++ b/gcc/config/arc/arc.h
@@ -325,7 +325,7 @@  if (GET_MODE_CLASS (MODE) == MODE_INT		\
    argument pointer.  */
 
 /* r63 is pc, r64-r127 = simd vregs, r128-r143 = simd dma config regs
-   r144, r145 = lp_start, lp_end
+   r144, r145 = ARG_POINTER, FRAME_POINTER
    and therefore the pseudo registers start from r146. */
 #define FIRST_PSEUDO_REGISTER 146
 
@@ -366,7 +366,7 @@  if (GET_MODE_CLASS (MODE) == MODE_INT		\
 { 0, 0, 0, 0, 0, 0, 0, 0,	\
   0, 0, 0, 0, 0, 0, 0, 0,	\
   0, 0, 0, 0, 0, 0, 0, 0,	\
-  0, 0, 1, 1, 1, 1, 1, 1,	\
+  0, 0, 1, 0, 1, 1, 1, 1,	\
 				\
   1, 1, 1, 1, 1, 1, 1, 1,	\
   0, 0, 0, 0, 1, 1, 1, 1,	\
@@ -398,7 +398,7 @@  if (GET_MODE_CLASS (MODE) == MODE_INT		\
   1, 1, 1, 1, 1, 1, 1, 1,	\
   1, 1, 1, 1, 1, 0, 0, 0,	\
   0, 0, 0, 0, 0, 0, 0, 0,	\
-  0, 0, 1, 1, 1, 1, 1, 1,	\
+  0, 0, 1, 0, 1, 1, 1, 1,	\
 				\
   1, 1, 1, 1, 1, 1, 1, 1,	\
   1, 1, 1, 1, 1, 1, 1, 1,	\
@@ -511,10 +511,10 @@  enum reg_class
   {0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsd'.  */ \
   {0x0000000f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rcd'.  */ \
   {0x0000f00f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'q'.  */ \
-  {0x1c001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'.  */ \
+  {0x00001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'.  */ \
   {0x9fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'h'.  */ \
   {0x00000000, 0x00000f00, 0x00000000, 0x00000000, 0x00000000}, /* 'D'.  */ \
-  {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00000000}, /* 'r'.  */ \
+  {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00030000}, /* 'r'.  */ \
   {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000}, /* 'v'.  */ \
   {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000ffff}, /* 'd'.  */ \
   {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0003ffff} /* ALL_REGS.  */\
@@ -562,11 +562,14 @@  extern enum reg_class arc_regno_reg_class[];
    Since they use reg_renumber, they are safe only once reg_renumber
    has been allocated, which happens in local-alloc.c.  */
 #define REGNO_OK_FOR_BASE_P(REGNO)					\
-  ((REGNO) < 29 || ((REGNO) == ARG_POINTER_REGNUM) || ((REGNO) == 63)	\
+  ((REGNO) < 29								\
+   || ((REGNO) == ARG_POINTER_REGNUM)					\
+   || ((REGNO) == FRAME_POINTER_REGNUM)					\
+   || ((REGNO) == PCL_REG)						\
    || ((unsigned) reg_renumber[REGNO] < 29)				\
    || ((unsigned) (REGNO) == (unsigned) arc_tp_regno)			\
    || (fixed_regs[REGNO] == 0 && IN_RANGE (REGNO, 32, 59))		\
-   || ((REGNO) == 30 && fixed_regs[REGNO] == 0))
+   || (fixed_regs[REGNO] == 0 && (REGNO) == R30_REG))
 
 #define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)
 
@@ -652,11 +655,12 @@  arc_return_addr_rtx(COUNT,FRAME)
 #define STACK_POINTER_REGNUM 28
 
 /* Base register for access to local variables of the function.  */
-#define FRAME_POINTER_REGNUM 27
+#define FRAME_POINTER_REGNUM 145
+#define HARD_FRAME_POINTER_REGNUM 27
 
 /* Base register for access to arguments of the function. This register
    will be eliminated into either fp or sp.  */
-#define ARG_POINTER_REGNUM 62
+#define ARG_POINTER_REGNUM 144
 
 #define RETURN_ADDR_REGNUM 31
 
@@ -766,8 +770,9 @@  arc_return_addr_rtx(COUNT,FRAME)
 
 #define ELIMINABLE_REGS					\
 {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},		\
- {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},		\
- {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+ {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},	\
+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},	\
+ {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
 
 /* Define the offset between two registers, one to be eliminated, and the other
    its replacement, at the start of a routine.  */
@@ -1161,7 +1166,7 @@  extern char rname56[], rname57[], rname58[], rname59[];
   "r32",  "r33",  "r34",  "r35",      "r36",    "r37",    "r38",   "r39",	\
    "d1",   "d1",   "d2",   "d2",      "r44",    "r45",    "r46",   "r47",	\
   "r48",  "r49",  "r50",  "r51",      "r52",    "r53",    "r54",   "r55",	\
-  rname56,rname57,rname58,rname59,"lp_count",    "cc",     "ap",   "pcl",	\
+  rname56,rname57,rname58,rname59,"lp_count",    "cc",   "limm",   "pcl",	\
   "vr0",  "vr1",  "vr2",  "vr3",      "vr4",    "vr5",    "vr6",   "vr7",       \
   "vr8",  "vr9", "vr10", "vr11",     "vr12",   "vr13",   "vr14",  "vr15",	\
  "vr16", "vr17", "vr18", "vr19",     "vr20",   "vr21",   "vr22",  "vr23",	\
@@ -1172,7 +1177,7 @@  extern char rname56[], rname57[], rname58[], rname59[];
  "vr56", "vr57", "vr58", "vr59",     "vr60",   "vr61",   "vr62",  "vr63",	\
   "dr0",  "dr1",  "dr2",  "dr3",      "dr4",    "dr5",    "dr6",   "dr7",	\
   "dr0",  "dr1",  "dr2",  "dr3",      "dr4",    "dr5",    "dr6",   "dr7",	\
-  "lp_start", "lp_end" \
+  "arg", "frame" \
 }
 
 #define ADDITIONAL_REGISTER_NAMES		\
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 3a903d4224a..7ac5a1b5785 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -202,8 +202,6 @@ 
    (LP_COUNT 60)
    (CC_REG 61)
    (PCL_REG 63)
-   (LP_START 144)
-   (LP_END 145)
   ]
 )
 
@@ -3467,8 +3465,6 @@  core_3, archs4x, archs4xd, archs4xd_slow"
 			    (match_operand:SI 2 "nonmemory_operand" "rn,Cal")]))
    (clobber (match_scratch:SI 4 "=X,X"))
    (clobber (reg:SI LP_COUNT))
-   (clobber (reg:SI LP_START))
-   (clobber (reg:SI LP_END))
    (clobber (reg:CC CC_REG))
   ]
   "!TARGET_BARREL_SHIFTER"
@@ -6508,7 +6504,7 @@  core_3, archs4x, archs4xd, archs4xd_slow"
   {
    int len = XVECLEN (operands[0], 0);
    rtx tmp = XVECEXP (operands[0], 0, len - 1);
-   if (XEXP (tmp, 0) != frame_pointer_rtx)
+   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
      {
       operands[3] = XEXP (tmp, 0);
       gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));
@@ -6538,7 +6534,7 @@  core_3, archs4x, archs4xd, archs4xd_slow"
   {
    int len = XVECLEN (operands[0], 0);
    rtx tmp = XVECEXP (operands[0], 0, len - 1);
-   if (XEXP (tmp, 0) != frame_pointer_rtx)
+   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
      {
       operands[3] = XEXP (tmp, 0);
       gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));
@@ -6569,7 +6565,7 @@  core_3, archs4x, archs4xd, archs4xd_slow"
   {
    int len = XVECLEN (operands[0], 0);
    rtx tmp = XVECEXP (operands[0], 0, len - 1);
-   if (XEXP (tmp, 0) != frame_pointer_rtx)
+   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
      {
       operands[3] = XEXP (tmp, 0);
       gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));
@@ -6600,7 +6596,7 @@  core_3, archs4x, archs4xd, archs4xd_slow"
   {
    int len = XVECLEN (operands[0], 0);
    rtx tmp = XVECEXP (operands[0], 0, len - 1);
-   if (XEXP (tmp, 0) != frame_pointer_rtx)
+   if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
      {
       operands[3] = XEXP (tmp, 0);
       gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));