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]

rename x86 pic register


This avoids saving and restoring the canonical call-saved pic register
when there are call-clobbered registers available to the function.
Naturally, this only applies to leaf functions.

The optimization hits 294 times building cc1 with -fpic, and hits
70 times building glibc.  So it's not entirely unusual to have a 
function that is small enough for this to apply.


r~


        * config/i386/i386.c (ix86_output_function_epilogue): New.
        (TARGET_ASM_FUNCTION_EPILOGUE): New.
        (pic_label_name): Remove.
        (pic_labels_used): New.
        (ix86_asm_file_end): Emit one pc load stub for each register used.
        (output_set_got): Generate deep pc load to any register.
        (ix86_select_alt_pic_regnum): New.
        (ix86_save_reg): Don't save pic register if we can find a valid
        call-clobbered replacement.
        (ix86_expand_prologue): If we found a valid replacement, renumber
        pic_offset_table_rtx.
        * config/i386/i386.h (PIC_OFFSET_TABLE_REGNUM): Look at 
        pic_offset_table_rtx after reload.
        (REAL_PIC_OFFSET_TABLE_REGNUM): New.
        * config/i386/i386.md (set_got): Make insn, not expander.
        (set_got_nopic, set_got_deep, set_got_nodeep): Remove.

Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.413
diff -c -p -d -r1.413 i386.c
*** config/i386/i386.c	29 May 2002 20:29:18 -0000	1.413
--- config/i386/i386.c	29 May 2002 20:51:52 -0000
*************** static int ix86_nsaved_regs PARAMS ((voi
*** 687,692 ****
--- 687,693 ----
  static void ix86_emit_save_regs PARAMS ((void));
  static void ix86_emit_save_regs_using_mov PARAMS ((rtx, HOST_WIDE_INT));
  static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int, int));
+ static void ix86_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
  static void ix86_set_move_mem_attrs_1 PARAMS ((rtx, rtx, rtx, rtx, rtx));
  static void ix86_sched_reorder_ppro PARAMS ((rtx *, rtx *));
  static HOST_WIDE_INT ix86_GOT_alias_set PARAMS ((void));
*************** static int ix86_fp_comparison_arithmetic
*** 737,742 ****
--- 738,744 ----
  static int ix86_fp_comparison_fcomi_cost PARAMS ((enum rtx_code code));
  static int ix86_fp_comparison_sahf_cost PARAMS ((enum rtx_code code));
  static int ix86_fp_comparison_cost PARAMS ((enum rtx_code code));
+ static unsigned int ix86_select_alt_pic_regnum PARAMS ((void));
  static int ix86_save_reg PARAMS ((unsigned int, int));
  static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *));
  static int ix86_comp_type_attributes PARAMS ((tree, tree));
*************** static enum x86_64_reg_class merge_class
*** 806,811 ****
--- 808,815 ----
  #  undef TARGET_ASM_FUNCTION_PROLOGUE
  #  define TARGET_ASM_FUNCTION_PROLOGUE ix86_osf_output_function_prologue
  #endif
+ #undef TARGET_ASM_FUNCTION_EPILOGUE
+ #define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue
  
  #undef TARGET_ASM_OPEN_PAREN
  #define TARGET_ASM_OPEN_PAREN ""
*************** ix86_setup_frame_addresses ()
*** 3894,3900 ****
    cfun->machine->accesses_prev_frame = 1;
  }
  
! static char pic_label_name[32];
  
  /* This function generates code for -fpic that loads %ebx with
     the return address of the caller and then returns.  */
--- 3898,3904 ----
    cfun->machine->accesses_prev_frame = 1;
  }
  
! static int pic_labels_used;
  
  /* This function generates code for -fpic that loads %ebx with
     the return address of the caller and then returns.  */
*************** ix86_asm_file_end (file)
*** 3904,3951 ****
       FILE *file;
  {
    rtx xops[2];
  
!   if (pic_label_name[0] == 0)
!     return;
! 
!   /* ??? Binutils 2.10 and earlier has a linkonce elimination bug related
!      to updating relocations to a section being discarded such that this
!      doesn't work.  Ought to detect this at configure time.  */
! #if 0
!   /* The trick here is to create a linkonce section containing the
!      pic label thunk, but to refer to it with an internal label.
!      Because the label is internal, we don't have inter-dso name
!      binding issues on hosts that don't support ".hidden".
! 
!      In order to use these macros, however, we must create a fake
!      function decl.  */
!   if (targetm.have_named_sections)
      {
!       tree decl = build_decl (FUNCTION_DECL,
! 			      get_identifier ("i686.get_pc_thunk"),
! 			      error_mark_node);
!       DECL_ONE_ONLY (decl) = 1;
!       (*targetm.asm_out.unique_section) (decl, 0);
!       named_section (decl, NULL);
!     }
!   else
! #else
!     text_section ();
! #endif
  
!   /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
!      internal (non-global) label that's being emitted, it didn't make
!      sense to have .type information for local labels.   This caused
!      the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving
!      me debug info for a label that you're declaring non-global?) this
!      was changed to call ASM_OUTPUT_LABEL() instead.  */
  
!   ASM_OUTPUT_LABEL (file, pic_label_name);
  
!   xops[0] = pic_offset_table_rtx;
!   xops[1] = gen_rtx_MEM (SImode, stack_pointer_rtx);
!   output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", xops);
!   output_asm_insn ("ret", xops);
  }
  
  /* Emit code for the SET_GOT patterns.  */
--- 3908,3935 ----
       FILE *file;
  {
    rtx xops[2];
+   int regno;
  
!   for (regno = 0; regno < 8; ++regno)
      {
!       if (! ((pic_labels_used >> regno) & 1))
! 	continue;
  
!       text_section ();
  
!       /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
! 	 internal (non-global) label that's being emitted, it didn't make
! 	 sense to have .type information for local labels.   This caused
! 	 the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving
! 	 me debug info for a label that you're declaring non-global?) this
! 	 was changed to call ASM_OUTPUT_LABEL() instead.  */
!       ASM_OUTPUT_INTERNAL_LABEL (file, "LPR", regno);
  
!       xops[0] = gen_rtx_REG (SImode, regno);
!       xops[1] = gen_rtx_MEM (SImode, stack_pointer_rtx);
!       output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", xops);
!       output_asm_insn ("ret", xops);
!     }
  }
  
  /* Emit code for the SET_GOT patterns.  */
*************** output_set_got (dest)
*** 3976,3985 ****
      }
    else
      {
!       if (! pic_label_name[0])
! 	ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
  
!       xops[2] = gen_rtx_SYMBOL_REF (Pmode, pic_label_name);
        xops[2] = gen_rtx_MEM (QImode, xops[2]);
        output_asm_insn ("call\t%X2", xops);
      }
--- 3960,3970 ----
      }
    else
      {
!       char pic_label_name[32];
!       ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", REGNO (dest));
!       pic_labels_used |= 1 << REGNO (dest);
  
!       xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (pic_label_name));
        xops[2] = gen_rtx_MEM (QImode, xops[2]);
        output_asm_insn ("call\t%X2", xops);
      }
*************** gen_push (arg)
*** 4005,4021 ****
  		      arg);
  }
  
  /* Return 1 if we need to save REGNO.  */
  static int
  ix86_save_reg (regno, maybe_eh_return)
       unsigned int regno;
       int maybe_eh_return;
  {
!   if (regno == PIC_OFFSET_TABLE_REGNUM
!       && (regs_ever_live[regno]
  	  || current_function_profile
  	  || current_function_calls_eh_return))
!     return 1;
  
    if (current_function_calls_eh_return && maybe_eh_return)
      {
--- 3990,4028 ----
  		      arg);
  }
  
+ /* Return >= 0 if there is an unused call-clobbered register available
+    for the entire function.  */
+ 
+ static unsigned int
+ ix86_select_alt_pic_regnum ()
+ {
+   if (current_function_is_leaf && !current_function_profile)
+     {
+       int i;
+       for (i = 2; i >= 0; --i)
+         if (!regs_ever_live[i])
+ 	  return i;
+     }
+ 
+   return INVALID_REGNUM;
+ }
+   
  /* Return 1 if we need to save REGNO.  */
  static int
  ix86_save_reg (regno, maybe_eh_return)
       unsigned int regno;
       int maybe_eh_return;
  {
!   if (pic_offset_table_rtx
!       && regno == REAL_PIC_OFFSET_TABLE_REGNUM
!       && (regs_ever_live[REAL_PIC_OFFSET_TABLE_REGNUM]
  	  || current_function_profile
  	  || current_function_calls_eh_return))
!     {
!       if (ix86_select_alt_pic_regnum () != INVALID_REGNUM)
! 	return 0;
!       return 1;
!     }
  
    if (current_function_calls_eh_return && maybe_eh_return)
      {
*************** void
*** 4236,4244 ****
  ix86_expand_prologue ()
  {
    rtx insn;
!   int pic_reg_used = (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
! 		      && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
! 			  || current_function_profile));
    struct ix86_frame frame;
    int use_mov = 0;
    HOST_WIDE_INT allocate;
--- 4243,4249 ----
  ix86_expand_prologue ()
  {
    rtx insn;
!   bool pic_reg_used;
    struct ix86_frame frame;
    int use_mov = 0;
    HOST_WIDE_INT allocate;
*************** ix86_expand_prologue ()
*** 4317,4322 ****
--- 4322,4340 ----
    SUBTARGET_PROLOGUE;
  #endif
  
+   pic_reg_used = false;
+   if (pic_offset_table_rtx
+       && (regs_ever_live[REAL_PIC_OFFSET_TABLE_REGNUM]
+ 	  || current_function_profile))
+     {
+       unsigned int alt_pic_reg_used = ix86_select_alt_pic_regnum ();
+ 
+       if (alt_pic_reg_used != INVALID_REGNUM)
+ 	REGNO (pic_offset_table_rtx) = alt_pic_reg_used;
+ 
+       pic_reg_used = true;
+     }
+ 
    if (pic_reg_used)
      {
        insn = emit_insn (gen_set_got (pic_offset_table_rtx));
*************** ix86_expand_epilogue (style)
*** 4521,4526 ****
--- 4539,4555 ----
      }
    else
      emit_jump_insn (gen_return_internal ());
+ }
+ 
+ /* Reset from the function's potential modifications.  */
+ 
+ static void
+ ix86_output_function_epilogue (file, size)
+      FILE *file ATTRIBUTE_UNUSED;
+      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
+ {
+   if (pic_offset_table_rtx)
+     REGNO (pic_offset_table_rtx) = REAL_PIC_OFFSET_TABLE_REGNUM;
  }
  
  /* Extract the parts of an RTL expression that is a valid memory address
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.264
diff -c -p -d -r1.264 i386.h
*** config/i386/i386.h	29 May 2002 01:37:21 -0000	1.264
--- config/i386/i386.h	29 May 2002 20:51:52 -0000
*************** do {									\
*** 1086,1094 ****
  /* Register to hold the addressing base for position independent
     code access to data items.  We don't use PIC pointer for 64bit
     mode.  Define the regnum to dummy value to prevent gcc from
!    pessimizing code dealing with EBX.  */
! #define PIC_OFFSET_TABLE_REGNUM \
!   (TARGET_64BIT || !flag_pic ? INVALID_REGNUM : 3)
  
  /* Register in which address to store a structure value
     arrives in the function.  On the 386, the prologue
--- 1086,1103 ----
  /* Register to hold the addressing base for position independent
     code access to data items.  We don't use PIC pointer for 64bit
     mode.  Define the regnum to dummy value to prevent gcc from
!    pessimizing code dealing with EBX. 
! 
!    To avoid clobbering a call-saved register unnecessarily, we renumber
!    the pic register when possible.  The change is visible after the
!    prologue has been emitted.  */
! 
! #define REAL_PIC_OFFSET_TABLE_REGNUM  3
! 
! #define PIC_OFFSET_TABLE_REGNUM				\
!   (TARGET_64BIT || !flag_pic ? INVALID_REGNUM		\
!    : reload_completed ? REGNO (pic_offset_table_rtx)	\
!    : REAL_PIC_OFFSET_TABLE_REGNUM)
  
  /* Register in which address to store a structure value
     arrives in the function.  On the 386, the prologue
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.368
diff -c -p -d -r1.368 i386.md
*** config/i386/i386.md	29 May 2002 01:37:22 -0000	1.368
--- config/i386/i386.md	29 May 2002 20:51:52 -0000
***************
*** 13137,13168 ****
    ""
    "ix86_expand_prologue (); DONE;")
  
! (define_expand "set_got"
!   [(parallel [(set (match_operand:SI 0 "register_operand" "")
! 		   (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
! 	      (clobber (reg:CC 17))])]
!   "!TARGET_64BIT"
!   "")
! 
! (define_insn "*set_got_nopic"
!   [(set (match_operand:SI 0 "register_operand" "=r")
! 	(unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
!    (clobber (reg:CC 17))]
!   "!TARGET_64BIT && !flag_pic"
!   { return output_set_got (operands[0]); }
!   [(set_attr "type" "multi")
!    (set_attr "length" "11")])
! 
! (define_insn "*set_got_deep"
!   [(set (match_operand:SI 0 "register_operand" "=b")
! 	(unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
!    (clobber (reg:CC 17))]
!   "!TARGET_64BIT && TARGET_DEEP_BRANCH_PREDICTION"
!   { return output_set_got (operands[0]); }
!   [(set_attr "type" "multi")
!    (set_attr "length" "11")])
! 
! (define_insn "*set_got_nodeep"
    [(set (match_operand:SI 0 "register_operand" "=r")
  	(unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
     (clobber (reg:CC 17))]
--- 13137,13143 ----
    ""
    "ix86_expand_prologue (); DONE;")
  
! (define_insn "set_got"
    [(set (match_operand:SI 0 "register_operand" "=r")
  	(unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
     (clobber (reg:CC 17))]


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