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]

[PATCH] Significantly improve Thumb code quality when the frame pointer is not eliminated


Conventionally it seems that a frame pointer will point directly at the 
saved registers for a function frame and that any local variables on the 
stack will appear below this (assuming a descending stack model).  That 
means the local variables have a negative offset from the frame pointer.

Unfortunately, Thumb has no memory addressing modes that directly support 
negative offsets from a base pointer, and to make matters worse, 
generating even small negative constants in registers takes at least two 
instructions (load a positive constant and negate it).  So the result is 
that code quality when we need a frame pointer is truly horrendous.

This patch changes the model that we use when we need a frame pointer in 
Thumb code so that we point it at the base of the local variables: these 
then have possitive offsets from the frame pointer and can, in general, be 
accessed using base+offset addressing.  The result is that we can reduce 
code size by as much as one third (yes 33%!) in some non-trivial 
subroutines.

Tested on arm-elf, arm-eabi and bootstrapped (compiling the compiler in 
thumb code) on arm-netbsdelf.

R.

2005-08-20  Richard Earnshaw  <richard.earnshaw@arm.com>

	* arm.h (arm_stack_offsets): Add locals_base field.
	* arm.c (arm_get_frame_offsets): Compute it.
	(thumb_compute_initial_elimination offset): Make the Thumb frame
	pointer point to the base of the local variables.
	(thumb_expand_prologue): Update accordingly.
	(thumb_expand_epilogue): Likewise.

	* arm.md (thumb_movhi_clobber): Make this insn a define_expand.  Change
	mode of clobbered scratch to DImode.  Handle a case that's known to
	need this.


Index: arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.475
diff -p -p -r1.475 arm.c
*** arm.c	19 Aug 2005 13:17:03 -0000	1.475
--- arm.c	20 Aug 2005 10:24:43 -0000
*************** thumb_force_lr_save (void)
*** 9992,9998 ****
                              |    | \
                              |    |   local
                              |    |   variables
!                             |    | /
                                --
                              |    | \
                              |    |   outgoing
--- 9992,9998 ----
                              |    | \
                              |    |   local
                              |    |   variables
!      locals base pointer -> |    | /
                                --
                              |    | \
                              |    |   outgoing
*************** arm_get_frame_offsets (void)
*** 10109,10116 ****
        && (offsets->soft_frame & 7))
      offsets->soft_frame += 4;
  
!   offsets->outgoing_args = offsets->soft_frame + frame_size
! 			   + current_function_outgoing_args_size;
  
    if (ARM_DOUBLEWORD_ALIGN)
      {
--- 10109,10117 ----
        && (offsets->soft_frame & 7))
      offsets->soft_frame += 4;
  
!   offsets->locals_base = offsets->soft_frame + frame_size;
!   offsets->outgoing_args = (offsets->locals_base
! 			    + current_function_outgoing_args_size);
  
    if (ARM_DOUBLEWORD_ALIGN)
      {
*************** arm_init_expanders (void)
*** 13158,13165 ****
  }
  
  
! /* Like arm_compute_initial_elimination offset.  Simpler because
!    THUMB_HARD_FRAME_POINTER isn't actually the ABI specified frame pointer.  */
  
  HOST_WIDE_INT
  thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
--- 13159,13168 ----
  }
  
  
! /* Like arm_compute_initial_elimination offset.  Simpler because there
!    isn't an ABI specified frame pointer for Thumb.  Instead, we set it
!    to point at the base of the local variables after static stack
!    space for a function has been allocated.  */
  
  HOST_WIDE_INT
  thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
*************** thumb_compute_initial_elimination_offset
*** 13179,13188 ****
  	case FRAME_POINTER_REGNUM:
  	  return offsets->soft_frame - offsets->saved_args;
  
- 	case THUMB_HARD_FRAME_POINTER_REGNUM:
  	case ARM_HARD_FRAME_POINTER_REGNUM:
  	  return offsets->saved_regs - offsets->saved_args;
  
  	default:
  	  gcc_unreachable ();
  	}
--- 13182,13193 ----
  	case FRAME_POINTER_REGNUM:
  	  return offsets->soft_frame - offsets->saved_args;
  
  	case ARM_HARD_FRAME_POINTER_REGNUM:
  	  return offsets->saved_regs - offsets->saved_args;
  
+ 	case THUMB_HARD_FRAME_POINTER_REGNUM:
+ 	  return offsets->locals_base - offsets->saved_args;
+ 
  	default:
  	  gcc_unreachable ();
  	}
*************** thumb_compute_initial_elimination_offset
*** 13194,13203 ****
  	case STACK_POINTER_REGNUM:
  	  return offsets->outgoing_args - offsets->soft_frame;
  
- 	case THUMB_HARD_FRAME_POINTER_REGNUM:
  	case ARM_HARD_FRAME_POINTER_REGNUM:
  	  return offsets->saved_regs - offsets->soft_frame;
  
  	default:
  	  gcc_unreachable ();
  	}
--- 13199,13210 ----
  	case STACK_POINTER_REGNUM:
  	  return offsets->outgoing_args - offsets->soft_frame;
  
  	case ARM_HARD_FRAME_POINTER_REGNUM:
  	  return offsets->saved_regs - offsets->soft_frame;
  
+ 	case THUMB_HARD_FRAME_POINTER_REGNUM:
+ 	  return offsets->locals_base - offsets->soft_frame;
+ 
  	default:
  	  gcc_unreachable ();
  	}
*************** thumb_expand_prologue (void)
*** 13239,13256 ****
    if (flag_pic)
      arm_load_pic_register (live_regs_mask);
  
!   offsets = arm_get_frame_offsets ();
! 
!   if (frame_pointer_needed)
!     {
!       insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
! 				   stack_pointer_rtx));
!       RTX_FRAME_RELATED_P (insn) = 1;
!     }
!   else if (CALLER_INTERWORKING_SLOT_SIZE > 0)
      emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
  		    stack_pointer_rtx);
  
    amount = offsets->outgoing_args - offsets->saved_regs;
    if (amount)
      {
--- 13246,13256 ----
    if (flag_pic)
      arm_load_pic_register (live_regs_mask);
  
!   if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
      emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
  		    stack_pointer_rtx);
  
+   offsets = arm_get_frame_offsets ();
    amount = offsets->outgoing_args - offsets->saved_regs;
    if (amount)
      {
*************** thumb_expand_prologue (void)
*** 13336,13347 ****
  				     REG_NOTES (insn));
  	    }
  	}
!       /* If the frame pointer is needed, emit a special barrier that
! 	 will prevent the scheduler from moving stores to the frame
! 	 before the stack adjustment.  */
!       if (frame_pointer_needed)
! 	emit_insn (gen_stack_tie (stack_pointer_rtx,
! 				  hard_frame_pointer_rtx));
      }
  
    if (current_function_profile || !TARGET_SCHED_PROLOG)
--- 13336,13364 ----
  				     REG_NOTES (insn));
  	    }
  	}
!     }
! 
!   if (frame_pointer_needed)
!     {
!       amount = offsets->outgoing_args - offsets->locals_base;
!       
!       if (amount < 1024)
! 	insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
! 				      stack_pointer_rtx, GEN_INT (amount)));
!       else
! 	{
! 	  emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
! 	  insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
! 					hard_frame_pointer_rtx,
! 					stack_pointer_rtx));
! 	  dwarf = gen_rtx_SET (SImode, hard_frame_pointer_rtx,
! 			       plus_constant (stack_pointer_rtx, amount));
! 	  RTX_FRAME_RELATED_P (dwarf) = 1;
! 	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
! 						REG_NOTES (insn));
! 	}
! 
!       RTX_FRAME_RELATED_P (insn) = 1;
      }
  
    if (current_function_profile || !TARGET_SCHED_PROLOG)
*************** thumb_expand_epilogue (void)
*** 13373,13380 ****
    amount = offsets->outgoing_args - offsets->saved_regs;
  
    if (frame_pointer_needed)
!     emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
!   else if (amount)
      {
        if (amount < 512)
  	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
--- 13390,13401 ----
    amount = offsets->outgoing_args - offsets->saved_regs;
  
    if (frame_pointer_needed)
!     {
!       emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
!       amount = offsets->locals_base - offsets->saved_regs;
!     }
!   
!   if (amount)
      {
        if (amount < 512)
  	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
Index: arm.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.288
diff -p -p -r1.288 arm.h
*** arm.h	19 Aug 2005 09:20:30 -0000	1.288
--- arm.h	20 Aug 2005 10:24:44 -0000
*************** typedef struct arm_stack_offsets GTY(())
*** 1476,1481 ****
--- 1476,1482 ----
    int frame;		/* ARM_HARD_FRAME_POINTER_REGNUM.  */
    int saved_regs;
    int soft_frame;	/* FRAME_POINTER_REGNUM.  */
+   int locals_base;	/* THUMB_HARD_FRAME_POINTER_REGNUM.  */
    int outgoing_args;	/* STACK_POINTER_REGNUM.  */
  }
  arm_stack_offsets;
Index: arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.204
diff -p -p -r1.204 arm.md
*** arm.md	30 Jul 2005 18:23:51 -0000	1.204
--- arm.md	20 Aug 2005 10:24:46 -0000
***************
*** 4951,4963 ****
    [(set_attr "predicable" "yes")]
  )
  
! (define_insn "thumb_movhi_clobber"
!   [(set (match_operand:HI     0 "memory_operand"   "=m")
! 	(match_operand:HI     1 "register_operand" "l"))
!    (clobber (match_operand:SI 2 "register_operand" "=&l"))]
    "TARGET_THUMB"
!   "*
!   gcc_unreachable ();"
  )
  	
  ;; We use a DImode scratch because we may occasionally need an additional
--- 4951,4971 ----
    [(set_attr "predicable" "yes")]
  )
  
! (define_expand "thumb_movhi_clobber"
!   [(set (match_operand:HI     0 "memory_operand"   "")
! 	(match_operand:HI     1 "register_operand" ""))
!    (clobber (match_operand:DI 2 "register_operand" ""))]
    "TARGET_THUMB"
!   "
!   if (strict_memory_address_p (HImode, XEXP (operands[0], 0))
!       && REGNO (operands[1]) <= LAST_LO_REGNUM)
!     {
!       emit_insn (gen_movhi (operands[0], operands[1]));
!       DONE;
!     }
!   /* XXX Fixme, need to handle other cases here as well.  */
!   gcc_unreachable ();
!   "
  )
  	
  ;; We use a DImode scratch because we may occasionally need an additional

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