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] S/390: Determine clobbered regs in a function


Hi,

on S/390 we have been using regs_ever_live exclusivly for figuring out which call
saved registers have to be saved. This brought two disadvantages with it:

(1) The S/390 ABI defines register 6 to be an argument register as well as a
    call saved register. Asking regs_ever_live we always saved it if it was used for
    argument passing even if the argument was only read within the function but 
    never clobbered. This is especially unfortunate because we always save the 
    registers as a block. So this often causes r7, r8, r9 ... to be saved unnecessarily.

(2) builtin_return_address (0) should simply return r14 (return address register)
    whenever it is possible. Returning r14 makes the register live which caused it 
    unnecessarily to be saved.

The patch introduces a s390_regs_ever_clobbered function in the S/390 back end which is
now used instead of regs_ever_live to determine which registers need to be saved.
In order to make this actually work I had to add two special cases regarding
exception handling regs and stack unwinding.

Bootstrapped on s390 and s390x - no testsuite regressions.

OK for mainline?

Bye,

-Andreas-



2005-06-27  Andreas Krebbel  <krebbel1@de.ibm.com>

	* config/s390/s390.c (machine_function): New field has_landing_pad_p.
	(s390_set_has_landing_pad_p, s390_reg_clobbered_rtx,
	 s390_regs_ever_clobbered): New functions.
	(s390_return_addr_rtx): Use get_hard_reg_initial_value.
	(s390_register_info, s390_init_frame_layout, s390_update_frame_layout): 
	Use s390_regs_ever_clobbered.
	(s390_emit_prologue): Don't use r14 as temp reg if its content is used
	for builtin_return_address.
	* config/s390/s390.md ("exception_receiver"): New expander.
	* config/s390/s390-protos.h (s390_set_has_landing_pad_p): Prototype
	added.

Index: gcc/config/s390/s390.c
===================================================================
--- gcc/config/s390/s390.c.orig	2005-06-27 09:50:09.000000000 +0200
+++ gcc/config/s390/s390.c	2005-06-27 14:59:15.000000000 +0200
@@ -245,6 +245,8 @@ struct machine_function GTY(())
 
   /* Some local-dynamic TLS symbol name.  */
   const char *some_ld_name;
+
+  bool has_landing_pad_p;
 };
 
 /* Few accessor macros for struct cfun->machine->s390_frame_layout.  */
@@ -263,6 +265,12 @@ struct machine_function GTY(())
 #define FP_ARG_NUM_REG (TARGET_64BIT? 4 : 2)
 
 
+void
+s390_set_has_landing_pad_p (bool value)
+{
+  cfun->machine->has_landing_pad_p = value;
+}
+
 /* Return true if SET either doesn't set the CC register, or else
    the source and destination have matching CC modes and that
    CC mode is at least as constrained as REQ_MODE.  */
@@ -5483,8 +5491,14 @@ s390_return_addr_rtx (int count, rtx fra
 
   if (count == 0)
     {
-      cfun_frame_layout.save_return_addr_p = true;
-      return gen_rtx_MEM (Pmode, return_address_pointer_rtx);
+      /* On non-z architectures branch splitting could overwrite r14.  */
+      if (TARGET_CPU_ZARCH)
+	return get_hard_reg_initial_val (Pmode, RETURN_REGNUM);
+      else
+	{
+	  cfun_frame_layout.save_return_addr_p = true;
+	  return gen_rtx_MEM (Pmode, return_address_pointer_rtx);
+	}
     }
 
   if (TARGET_PACKED_STACK)
@@ -5531,6 +5545,67 @@ find_unused_clobbered_reg (void)
   return 0;
 }
 
+
+/* Helper function for s390_regs_ever_clobbered. Sets the fields in DATA for all 
+   clobbered hard regs in SETREG.  */
+
+static void
+s390_reg_clobbered_rtx (rtx setreg, rtx set_insn ATTRIBUTE_UNUSED, void *data)
+{
+  int *regs_ever_clobbered = (int*)data;
+  unsigned int i, regno;
+  enum machine_mode mode = GET_MODE (setreg);
+
+  if (GET_CODE (setreg) == SUBREG)
+    {
+      rtx inner = SUBREG_REG (setreg);
+      if (!GENERAL_REG_P (inner))
+	return;
+      regno = subreg_regno (setreg);
+    }
+  else if (GENERAL_REG_P (setreg))
+    regno = REGNO (setreg);
+  else
+    return;
+
+  for (i = regno;
+       i < regno + HARD_REGNO_NREGS (regno, mode);
+       i++)
+    regs_ever_clobbered[i] = 1;
+}
+
+/* Walks through all basic blocks of the current function looking
+   for clobbered hard regs using s390_reg_clobbered_rtx. The fields
+   of the passed integer array REGS_EVER_CLOBBERED are set to one for
+   each of those regs.  */
+
+static void
+s390_regs_ever_clobbered (int *regs_ever_clobbered)
+{
+  basic_block cur_bb;
+  rtx cur_insn;
+  int i;
+
+  memset (regs_ever_clobbered, 0, 16 * sizeof (int));
+
+  if (!current_function_is_leaf)
+    {
+      for (i = 0; i < 16; i++)
+	regs_ever_clobbered[i] = call_really_used_regs[i];
+    }
+
+  FOR_EACH_BB(cur_bb)
+    {
+      FOR_BB_INSNS (cur_bb, cur_insn)
+	{
+	  if (INSN_P (cur_insn))
+	    note_stores (PATTERN (cur_insn),
+			 s390_reg_clobbered_rtx, 
+			 regs_ever_clobbered);
+	}
+    }
+}
+
 /* Determine the frame area which actually has to be accessed 
    in the function epilogue. The values are stored at the 
    given pointers AREA_BOTTOM (address of the lowest used stack
@@ -5574,10 +5649,10 @@ s390_frame_area (int *area_bottom, int *
 }
 
 /* Fill cfun->machine with info about register usage of current function.
-   Return in LIVE_REGS which GPRs are currently considered live.  */
+   Return in CLOBBERED_REGS which GPRs are currently considered set.  */
 
 static void
-s390_register_info (int live_regs[])
+s390_register_info (int clobbered_regs[])
 {
   int i, j;
 
@@ -5598,34 +5673,56 @@ s390_register_info (int live_regs[])
      Also, all registers with special meaning to the compiler need
      to be handled extra.  */
 
+  s390_regs_ever_clobbered (clobbered_regs);
+
   for (i = 0; i < 16; i++)
-    live_regs[i] = regs_ever_live[i] && !global_regs[i];
+    clobbered_regs[i] = clobbered_regs[i] && !global_regs[i];
+
+  if (frame_pointer_needed)
+    clobbered_regs[HARD_FRAME_POINTER_REGNUM] = 1;
 
   if (flag_pic)
-    live_regs[PIC_OFFSET_TABLE_REGNUM] 
+    clobbered_regs[PIC_OFFSET_TABLE_REGNUM] 
     = regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
 
-  live_regs[BASE_REGNUM] 
+  clobbered_regs[BASE_REGNUM] 
     = cfun->machine->base_reg
       && REGNO (cfun->machine->base_reg) == BASE_REGNUM;
 
-  live_regs[RETURN_REGNUM]
+  clobbered_regs[RETURN_REGNUM]
     = cfun->machine->split_branches_pending_p
       || cfun_frame_layout.save_return_addr_p;
 
-  live_regs[STACK_POINTER_REGNUM]
+  clobbered_regs[STACK_POINTER_REGNUM]
     = !current_function_is_leaf
       || TARGET_TPF_PROFILING
       || cfun_save_high_fprs_p
       || get_frame_size () > 0
       || current_function_calls_alloca
       || current_function_stdarg;
+
+  /* Make the "magic" eh_return registers live if necessary. For regs_ever_live
+     this work is done by liveness analysis (mark_regs_live_at_end).
+     Special care is needed for functions containing landing pads. landing pads
+     may use the eh registers, but the code which sets these registers is not
+     contained in that function.  Hence s390_regs_ever_clobbered is not able to
+     deal with this automatically.  */
+  if (current_function_calls_eh_return || cfun->machine->has_landing_pad_p)
+    for (i = 6; i < 10; i++)
+      clobbered_regs[i] = 1;
+
+  /* For nonlocal gotos all call-saved registers have to be saved. This flag
+     is also set for the unwinding code in libgcc. For regs_ever_live this
+     is done by reload.  See expand_builtin_unwind_init.  */
+  if (current_function_has_nonlocal_label)
+    for (i = 6; i < 16; i++)
+      clobbered_regs[i] = 1;
   
   for (i = 6; i < 16; i++)
-    if (live_regs[i])
+    if (clobbered_regs[i])
       break;
   for (j = 15; j > i; j--)
-    if (live_regs[j])
+    if (clobbered_regs[j])
       break;
 
   if (i == 16)
@@ -5808,10 +5905,12 @@ s390_init_frame_layout (void)
 {
   HOST_WIDE_INT frame_size;
   int base_used;
-  int live_regs[16];
+  int clobbered_regs[16];
 
   /* If return address register is explicitly used, we need to save it.  */
-  if (regs_ever_live[RETURN_REGNUM]
+  s390_regs_ever_clobbered(clobbered_regs);
+
+  if (clobbered_regs[RETURN_REGNUM]
       || !current_function_is_leaf
       || TARGET_TPF_PROFILING
       || current_function_stdarg
@@ -5845,7 +5944,7 @@ s390_init_frame_layout (void)
       else
 	cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
 
-      s390_register_info (live_regs);
+      s390_register_info (clobbered_regs);
       s390_frame_info ();
     }
   while (frame_size != cfun_frame_layout.frame_size);
@@ -5859,13 +5958,14 @@ s390_init_frame_layout (void)
 static void
 s390_update_frame_layout (void)
 {
-  int live_regs[16];
+  int clobbered_regs[16];
 
-  s390_register_info (live_regs);
+  s390_regs_ever_clobbered(clobbered_regs);
+  s390_register_info (clobbered_regs);
 
-  regs_ever_live[BASE_REGNUM] = live_regs[BASE_REGNUM];
-  regs_ever_live[RETURN_REGNUM] = live_regs[RETURN_REGNUM];
-  regs_ever_live[STACK_POINTER_REGNUM] = live_regs[STACK_POINTER_REGNUM];
+  regs_ever_live[BASE_REGNUM] = clobbered_regs[BASE_REGNUM];
+  regs_ever_live[RETURN_REGNUM] = clobbered_regs[RETURN_REGNUM];
+  regs_ever_live[STACK_POINTER_REGNUM] = clobbered_regs[STACK_POINTER_REGNUM];
 
   if (cfun->machine->base_reg)
     regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
@@ -6137,7 +6237,9 @@ s390_emit_prologue (void)
   /* Choose best register to use for temp use within prologue.
      See below for why TPF must use the register 1.  */
 
-  if (!current_function_is_leaf && !TARGET_TPF_PROFILING)
+  if (!has_hard_reg_initial_val (Pmode, RETURN_REGNUM) 
+      && !current_function_is_leaf 
+      && !TARGET_TPF_PROFILING)
     temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
   else
     temp_reg = gen_rtx_REG (Pmode, 1);
Index: gcc/config/s390/s390.md
===================================================================
--- gcc/config/s390/s390.md.orig	2005-06-27 09:50:09.000000000 +0200
+++ gcc/config/s390/s390.md	2005-06-27 14:57:36.000000000 +0200
@@ -6895,6 +6895,12 @@
   DONE;
 })
 
+(define_expand "exception_receiver"
+  [(const_int 0)]
+  ""
+{
+  s390_set_has_landing_pad_p (true);
+})
 
 ;
 ; nop instruction pattern(s).
Index: gcc/config/s390/s390-protos.h
===================================================================
--- gcc/config/s390/s390-protos.h.orig	2005-06-13 10:28:31.000000000 +0200
+++ gcc/config/s390/s390-protos.h	2005-06-27 14:57:00.000000000 +0200
@@ -29,6 +29,7 @@ extern void s390_emit_prologue (void);
 extern void s390_emit_epilogue (bool);
 extern void s390_function_profiler (FILE *, int);
 extern void s390_conditional_register_usage (void);
+extern void s390_set_has_landing_pad_p (bool);
 
 #ifdef RTX_CODE
 extern int s390_extra_constraint_str (rtx, int, const char *);


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