[PATCH] S/390: Determine clobbered regs in a function - take 2

Andreas Krebbel krebbel1@de.ibm.com
Tue Jun 28 08:37:00 GMT 2005


Hi,

Ulrich has reviewed my patch offline.

I've fixed few minor flaws and coding style issues. And of course I've 
added the DONE; to the exception_receiver expander - thanks to rth.

Bootstrapped on s390 and s390x - no testsuite regressions.

OK for mainline?

Bye,

-Andreas-


2005-06-28  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-protos.h
===================================================================
--- gcc/config/s390/s390-protos.h.orig	2005-06-28 09:01:49.000000000 +0200
+++ gcc/config/s390/s390-protos.h	2005-06-28 09:02:03.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: gcc/config/s390/s390.c
===================================================================
--- gcc/config/s390/s390.c.orig	2005-06-28 09:01:49.000000000 +0200
+++ gcc/config/s390/s390.c	2005-06-28 09:50:10.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.  */
@@ -262,6 +264,13 @@ struct machine_function GTY(())
 #define GP_ARG_NUM_REG 5
 #define FP_ARG_NUM_REG (TARGET_64BIT? 4 : 2)
 
+/* Set the has_landing_pad_p flag in struct machine_function to VALUE.  */
+
+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
@@ -5483,8 +5492,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 +5546,88 @@ 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;
+  unsigned int i;
+
+  memset (regs_ever_clobbered, 0, 16 * sizeof (int));
+
+  /* For non-leaf functions we have to consider all call clobbered regs to be
+     clobbered.  */
+  if (!current_function_is_leaf)
+    {
+      for (i = 0; i < 16; i++)
+	regs_ever_clobbered[i] = call_really_used_regs[i];
+    }
+
+  /* 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 = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM ; i++)
+      regs_ever_clobbered[EH_RETURN_DATA_REGNO (i)] = 1;
+
+  /* For nonlocal gotos all call-saved registers have to be saved.
+     This flag is also set for the unwinding code in libgcc.
+     See expand_builtin_unwind_init.  For regs_ever_live this is done by
+     reload.  */
+  if (current_function_has_nonlocal_label)
+    for (i = 0; i < 16; i++)
+      if (!call_really_used_regs[i])
+	regs_ever_clobbered[i] = 1;
+
+  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 +5671,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 +5695,39 @@ 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;
-  
+
   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 +5910,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 +5949,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 +5963,13 @@ 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_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 +6241,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-28 09:01:49.000000000 +0200
+++ gcc/config/s390/s390.md	2005-06-28 09:02:03.000000000 +0200
@@ -6895,6 +6895,13 @@
   DONE;
 })
 
+(define_expand "exception_receiver"
+  [(const_int 0)]
+  ""
+{
+  s390_set_has_landing_pad_p (true);
+  DONE;
+})
 
 ;
 ; nop instruction pattern(s).



More information about the Gcc-patches mailing list