OSDN Git Service

* config/s390/s390-protos.h (s390_arg_frame_offset): Remove.
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Sep 2004 21:23:29 +0000 (21:23 +0000)
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Sep 2004 21:23:29 +0000 (21:23 +0000)
(s390_return_address_offset): Remove.
(s390_can_eliminate): Add prototype.
(s390_initial_elimination_offset): Add prototype.
* config/s390/s390.h (CAN_ELIMINATE): Call s390_can_eliminate.
(INITIAL_ELIMINATION_OFFSET): Call s390_initial_elimination_offset.
* config/s390/s390.c (s390_arg_frame_offset): Remove.
(s390_return_address_offset): Remove.
(s390_can_eliminate, s390_initial_elimination_offset): New functions.
(struct machine_function): New member split_branches_pending_p.
(s390_mainpool_start): Allow nonexistant pool insn for empty pool.
(s390_mainpool_finish): Likewise.  Clear base_reg if pool empty.
(s390_optimize_prologue): Remove base_used argument.  Call
s390_update_frame_layout instead of s390_register_info.  Handle
prologue/epilogue insns that touch only RETURN_REGNUM.
(s390_reorg): Remove base_used.  Clear split_branches_pending_p.
(s390_register_info): Remove base_used and return_addr_used
arguments, compute special register usage inline.  Return live
register data to caller.
(s390_frame_info): Remove arguments, do not call s390_register_info.
(s390_init_frame_layout): New function.
(s390_update_frame_layout): Likewise.
(s390_emit_prologue): Call s390_update_frame_layout; some code
move to there.  Do not emit pool placeholder insn if unnecessary.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@88357 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.h

index e8b7b17..c658bc0 100644 (file)
@@ -1,5 +1,32 @@
 2004-09-30  Ulrich Weigand  <uweigand@de.ibm.com>
 
+       * config/s390/s390-protos.h (s390_arg_frame_offset): Remove.
+       (s390_return_address_offset): Remove.
+       (s390_can_eliminate): Add prototype.
+       (s390_initial_elimination_offset): Add prototype.
+       * config/s390/s390.h (CAN_ELIMINATE): Call s390_can_eliminate.
+       (INITIAL_ELIMINATION_OFFSET): Call s390_initial_elimination_offset.
+       * config/s390/s390.c (s390_arg_frame_offset): Remove.
+       (s390_return_address_offset): Remove.
+       (s390_can_eliminate, s390_initial_elimination_offset): New functions.
+       (struct machine_function): New member split_branches_pending_p.
+       (s390_mainpool_start): Allow nonexistant pool insn for empty pool.
+       (s390_mainpool_finish): Likewise.  Clear base_reg if pool empty.
+       (s390_optimize_prologue): Remove base_used argument.  Call
+       s390_update_frame_layout instead of s390_register_info.  Handle
+       prologue/epilogue insns that touch only RETURN_REGNUM.
+       (s390_reorg): Remove base_used.  Clear split_branches_pending_p.
+       (s390_register_info): Remove base_used and return_addr_used 
+       arguments, compute special register usage inline.  Return live
+       register data to caller.
+       (s390_frame_info): Remove arguments, do not call s390_register_info.
+       (s390_init_frame_layout): New function.
+       (s390_update_frame_layout): Likewise.
+       (s390_emit_prologue): Call s390_update_frame_layout; some code
+       move to there.  Do not emit pool placeholder insn if unnecessary.
+
+2004-09-30  Ulrich Weigand  <uweigand@de.ibm.com>
+
        * config/s390/s390.c (legitimate_reload_constant_p): Remove
        floating point constant workaround.
        (s390_secondary_input_reload_class): Handle PLUS reloads
index 359e20c..d1407c1 100644 (file)
@@ -23,8 +23,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 extern void optimization_options (int, int);
 extern void override_options (void);
-extern HOST_WIDE_INT s390_arg_frame_offset (void);
-extern HOST_WIDE_INT s390_return_address_offset (void);
+extern bool s390_can_eliminate (int, int);
+extern HOST_WIDE_INT s390_initial_elimination_offset (int, int);
 extern void s390_emit_prologue (void);
 extern void s390_emit_epilogue (bool);
 extern void s390_function_profiler (FILE *, int);
index bb468fe..073d9df 100644 (file)
@@ -254,6 +254,9 @@ struct machine_function GTY(())
   /* Literal pool base register.  */
   rtx base_reg;
 
+  /* True if we may need to perform branch splitting.  */
+  bool split_branches_pending_p;
+
   /* Some local-dynamic TLS symbol name.  */
   const char *some_ld_name;
 };
@@ -289,11 +292,13 @@ static void find_constant_pool_ref (rtx, rtx *);
 static void replace_constant_pool_ref (rtx *, rtx, rtx);
 static rtx find_ltrel_base (rtx);
 static void replace_ltrel_base (rtx *);
-static void s390_optimize_prologue (bool);
+static void s390_optimize_prologue (void);
 static int find_unused_clobbered_reg (void);
 static void s390_frame_area (int *, int *);
-static void s390_register_info (int, int);
-static void s390_frame_info (int, int);
+static void s390_register_info (int []);
+static void s390_frame_info (void);
+static void s390_init_frame_layout (void);
+static void s390_update_frame_layout (void);
 static rtx save_fpr (rtx, int, int);
 static rtx restore_fpr (rtx, int, int);
 static rtx save_gprs (rtx, int, int, int);
@@ -4895,7 +4900,7 @@ s390_mainpool_start (void)
        }
     }
 
-  if (!pool->pool_insn)
+  if (!pool->pool_insn && pool->size > 0)
     abort ();
 
   if (pool->size >= 4096)
@@ -4918,13 +4923,17 @@ s390_mainpool_start (void)
 static void
 s390_mainpool_finish (struct constant_pool *pool)
 {
-  rtx base_reg = SET_DEST (PATTERN (pool->pool_insn));
+  rtx base_reg = cfun->machine->base_reg;
   rtx insn;
 
   /* If the pool is empty, we're done.  */
   if (pool->size == 0)
     {
-      remove_insn (pool->pool_insn);
+      /* We don't actually need a base register after all.  */
+      cfun->machine->base_reg = NULL_RTX;
+
+      if (pool->pool_insn)
+       remove_insn (pool->pool_insn);
       s390_free_pool (pool);
       return;
     }
@@ -5437,20 +5446,16 @@ s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align)
 
 
 /* Rework the prologue/epilogue to avoid saving/restoring
-   registers unnecessarily.  BASE_USED specifies whether
-   the literal pool base register needs to be saved.  */
+   registers unnecessarily.  */
 
 static void
-s390_optimize_prologue (bool base_used)
+s390_optimize_prologue (void)
 {
   rtx insn, new_insn, next_insn;
 
   /* Do a final recompute of the frame-related data.  */
 
-  s390_register_info (base_used, cfun_frame_layout.save_return_addr_p);
-  regs_ever_live[BASE_REGNUM] = base_used;
-  regs_ever_live[RETURN_REGNUM] = cfun_frame_layout.save_return_addr_p;
-  regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0;
+  s390_update_frame_layout ();
 
   /* If all special registers are in fact used, there's nothing we
      can do, so no point in walking the insn list.  */
@@ -5509,10 +5514,13 @@ s390_optimize_prologue (bool base_used)
 
       if (GET_CODE (PATTERN (insn)) == SET
          && GET_CODE (SET_SRC (PATTERN (insn))) == REG
-         && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM
+         && (REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM
+             || (!TARGET_CPU_ZARCH
+                 && REGNO (SET_SRC (PATTERN (insn))) == RETURN_REGNUM))
          && GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
        {
          set = PATTERN (insn);
+         first = REGNO (SET_SRC (set));
          offset = const0_rtx;
          base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
          off = INTVAL (offset);
@@ -5526,7 +5534,7 @@ s390_optimize_prologue (bool base_used)
            {
              new_insn = save_gprs (base, 
                                    off + (cfun_frame_layout.first_save_gpr 
-                                          - BASE_REGNUM) * UNITS_PER_WORD, 
+                                          - first) * UNITS_PER_WORD, 
                                    cfun_frame_layout.first_save_gpr,
                                    cfun_frame_layout.last_save_gpr);
              new_insn = emit_insn_before (new_insn, insn);
@@ -5572,10 +5580,13 @@ s390_optimize_prologue (bool base_used)
 
       if (GET_CODE (PATTERN (insn)) == SET
          && GET_CODE (SET_DEST (PATTERN (insn))) == REG
-         && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM
+         && (REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM
+             || (!TARGET_CPU_ZARCH
+                 && REGNO (SET_DEST (PATTERN (insn))) == RETURN_REGNUM))
          && GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
        {
          set = PATTERN (insn);
+         first = REGNO (SET_DEST (set));
          offset = const0_rtx;
          base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
          off = INTVAL (offset);
@@ -5589,7 +5600,7 @@ s390_optimize_prologue (bool base_used)
            {
              new_insn = restore_gprs (base, 
                                       off + (cfun_frame_layout.first_restore_gpr 
-                                             - BASE_REGNUM) * UNITS_PER_WORD,
+                                             - first) * UNITS_PER_WORD,
                                       cfun_frame_layout.first_restore_gpr,
                                       cfun_frame_layout.last_restore_gpr);
              new_insn = emit_insn_before (new_insn, insn);
@@ -5607,7 +5618,6 @@ s390_optimize_prologue (bool base_used)
 static void
 s390_reorg (void)
 {
-  bool base_used = false;
   bool pool_overflow = false;
 
   /* Make sure all splits have been performed; splits after
@@ -5680,19 +5690,17 @@ s390_reorg (void)
 
       /* If we made it up to here, both conditions are satisfied.
         Finish up literal pool related changes.  */
-      if ((pool_overflow || pool->size > 0)
-          && REGNO (cfun->machine->base_reg) == BASE_REGNUM)
-       base_used = true;
-
       if (pool_overflow)
        s390_chunkify_finish (pool);
       else
        s390_mainpool_finish (pool);
 
+      /* We're done splitting branches.  */
+      cfun->machine->split_branches_pending_p = false;
       break;
     }
 
-  s390_optimize_prologue (base_used);
+  s390_optimize_prologue ();
 }
 
 
@@ -5806,14 +5814,12 @@ s390_frame_area (int *area_bottom, int *area_top)
   *area_top = t;
 }
 
-/* Fill cfun->machine with info about register usage of current 
-   function. BASE_USED and RETURN_ADDR_USED specify whether we assume the
-   base and return address register will need to be saved.  */
+/* Fill cfun->machine with info about register usage of current function.
+   Return in LIVE_REGS which GPRs are currently considered live.  */
 
 static void
-s390_register_info (int base_used, int return_addr_used)
+s390_register_info (int live_regs[])
 {
-  int live_regs[16];
   int i, j;
 
   /* fprs 8 - 15 are call saved for 64 Bit ABI.  */
@@ -5837,17 +5843,24 @@ s390_register_info (int base_used, int return_addr_used)
     live_regs[i] = regs_ever_live[i] && !global_regs[i];
 
   if (flag_pic)
-    live_regs[PIC_OFFSET_TABLE_REGNUM] = 
-    regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
-
-  live_regs[BASE_REGNUM] = base_used;
-  live_regs[RETURN_REGNUM] = return_addr_used;
-  live_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);
+    live_regs[PIC_OFFSET_TABLE_REGNUM] 
+    = regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
+
+  live_regs[BASE_REGNUM] 
+    = cfun->machine->base_reg
+      && REGNO (cfun->machine->base_reg) == BASE_REGNUM;
+
+  live_regs[RETURN_REGNUM]
+    = cfun->machine->split_branches_pending_p
+      || cfun_frame_layout.save_return_addr_p;
+
+  live_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])
@@ -5895,19 +5908,14 @@ s390_register_info (int base_used, int return_addr_used)
        cfun_set_fpr_bit (i);
 }
 
-/* Fill cfun->machine with info about frame of current 
-   function. BASE_USED and RETURN_ADDR_USED specify whether we assume the
-   base and return address register will need to be saved.  */
+/* Fill cfun->machine with info about frame of current function.  */
 
 static void
-s390_frame_info (int base_used, int return_addr_used)
+s390_frame_info (void)
 {
   int i;
 
   cfun_frame_layout.frame_size = get_frame_size ();
-
-  s390_register_info (base_used, return_addr_used);
-
   if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000)
     fatal_error ("Total size of local variables exceeds architecture limit.");
   
@@ -6011,37 +6019,136 @@ s390_frame_info (int base_used, int return_addr_used)
     }
 }
 
-/* Return offset between argument pointer and frame pointer
-   initially after prologue.  */
+/* Generate frame layout.  Fills in register and frame data for the current
+   function in cfun->machine.  This routine can be called multiple times;
+   it will re-do the complete frame layout every time.  */
 
-HOST_WIDE_INT
-s390_arg_frame_offset (void)
+static void
+s390_init_frame_layout (void)
+{
+  HOST_WIDE_INT frame_size;
+  int base_used;
+  int live_regs[16];
+
+  /* If return address register is explicitly used, we need to save it.  */
+  if (regs_ever_live[RETURN_REGNUM]
+      || !current_function_is_leaf
+      || TARGET_TPF_PROFILING
+      || current_function_stdarg
+      || current_function_calls_eh_return)
+    cfun_frame_layout.save_return_addr_p = true;
+
+  /* On S/390 machines, we may need to perform branch splitting, which
+     will require both base and return address register.  We have no
+     choice but to assume we're going to need them until right at the
+     end of the machine dependent reorg phase.  */
+  if (!TARGET_CPU_ZARCH)
+    cfun->machine->split_branches_pending_p = true;
+
+  do
+    {
+      frame_size = cfun_frame_layout.frame_size;
+
+      /* Try to predict whether we'll need the base register.  */
+      base_used = cfun->machine->split_branches_pending_p
+                 || current_function_uses_const_pool
+                 || (!DISP_IN_RANGE (-frame_size)
+                     && !CONST_OK_FOR_CONSTRAINT_P (-frame_size, 'K', "K"));
+
+      /* Decide which register to use as literal pool base.  In small
+        leaf functions, try to use an unused call-clobbered register
+        as base register to avoid save/restore overhead.  */
+      if (!base_used)
+       cfun->machine->base_reg = NULL_RTX;
+      else if (current_function_is_leaf && !regs_ever_live[5])
+       cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
+      else
+       cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
+
+      s390_register_info (live_regs);
+      s390_frame_info ();
+    }
+  while (frame_size != cfun_frame_layout.frame_size);
+}
+
+/* Update frame layout.  Recompute actual register save data based on
+   current info and update regs_ever_live for the special registers.
+   May be called multiple times, but may never cause *more* registers
+   to be saved than s390_init_frame_layout allocated room for.  */
+
+static void
+s390_update_frame_layout (void)
+{
+  int live_regs[16];
+
+  s390_register_info (live_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];
+
+  if (cfun->machine->base_reg)
+    regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
+}
+
+/* Return true if register FROM can be eliminated via register TO.  */
+
+bool
+s390_can_eliminate (int from, int to)
 {
-  /* See the comment in s390_emit_prologue about the assumptions we make
-     whether or not the base and return address register need to be saved.  */
-  int return_addr_used = !current_function_is_leaf
-                        || TARGET_TPF_PROFILING
-                        || regs_ever_live[RETURN_REGNUM]
-                        || cfun_frame_layout.save_return_addr_p;
+  gcc_assert (to == STACK_POINTER_REGNUM
+             || to == HARD_FRAME_POINTER_REGNUM);
+
+  gcc_assert (from == FRAME_POINTER_REGNUM
+             || from == ARG_POINTER_REGNUM
+             || from == RETURN_ADDRESS_POINTER_REGNUM);
 
-  s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used);
+  /* Make sure we actually saved the return address.  */
+  if (from == RETURN_ADDRESS_POINTER_REGNUM)
+    if (!current_function_calls_eh_return
+       && !current_function_stdarg
+       && !cfun_frame_layout.save_return_addr_p)
+      return false;
 
-  return cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
+  return true;
 }
 
-/* Return offset between return address pointer (location of r14
-   on the stack) and frame pointer initially after prologue.  */
+/* Return offset between register FROM and TO initially after prolog.  */
 
 HOST_WIDE_INT
-s390_return_address_offset (void)
+s390_initial_elimination_offset (int from, int to)
 {
-  s390_frame_info (1, 1);
+  HOST_WIDE_INT offset;
+  int index;
 
-  if (cfun_frame_layout.last_save_gpr < RETURN_REGNUM)
-    abort ();
+  /* ??? Why are we called for non-eliminable pairs?  */
+  if (!s390_can_eliminate (from, to))
+    return 0;
+
+  switch (from)
+    {
+    case FRAME_POINTER_REGNUM:
+      offset = 0;
+      break;
+
+    case ARG_POINTER_REGNUM:
+      s390_init_frame_layout ();
+      offset = cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
+      break;
 
-  return (cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset
-         + (RETURN_REGNUM - cfun_frame_layout.first_save_gpr) * UNITS_PER_WORD);
+    case RETURN_ADDRESS_POINTER_REGNUM:
+      s390_init_frame_layout ();
+      index = RETURN_REGNUM - cfun_frame_layout.first_save_gpr;
+      gcc_assert (index >= 0);
+      offset = cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset;
+      offset += index * UNITS_PER_WORD;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return offset;
 }
 
 /* Emit insn to save fpr REGNUM at offset OFFSET relative
@@ -6230,41 +6337,9 @@ s390_emit_prologue (void)
   int offset;
   int next_fpr = 0;
 
-  /* At this point, we decide whether we'll need to save/restore the
-     return address register.  This decision is final on zSeries machines;
-     on S/390 it can still be overridden in s390_split_branches.  */
-
-  if (!current_function_is_leaf
-      || TARGET_TPF_PROFILING
-      || regs_ever_live[RETURN_REGNUM])
-    cfun_frame_layout.save_return_addr_p = 1;
-
-  /* Decide which register to use as literal pool base.  In small leaf 
-     functions, try to use an unused call-clobbered register as base 
-     register to avoid save/restore overhead.  */
-
-  if (current_function_is_leaf && !regs_ever_live[5])
-    cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
-  else
-    cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
-
-  regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
-
-  /* Compute frame info.  Note that at this point, we assume the base 
-     register and -on S/390- the return register always need to be saved.
-     This is done because the usage of these registers might change even 
-     after the prologue was emitted.  If it turns out later that we really 
-     don't need them, the prologue/epilogue code is modified again.  */
-
-  s390_frame_info (1, !TARGET_CPU_ZARCH
-                  || cfun_frame_layout.save_return_addr_p);
-
-  /* We need to update regs_ever_live to avoid data-flow problems.  */
+  /* Complete frame layout.  */
 
-  regs_ever_live[BASE_REGNUM] = 1;
-  regs_ever_live[RETURN_REGNUM] = (!TARGET_CPU_ZARCH 
-                                  || cfun_frame_layout.save_return_addr_p);
-  regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0;
+  s390_update_frame_layout ();
 
   /* Annotate all constant pool references to let the scheduler know
      they implicitly use the base register.  */
@@ -6297,7 +6372,8 @@ s390_emit_prologue (void)
 
   /* Dummy insn to mark literal pool slot.  */
 
-  emit_insn (gen_main_pool (cfun->machine->base_reg));
+  if (cfun->machine->base_reg)
+    emit_insn (gen_main_pool (cfun->machine->base_reg));
 
   offset = cfun_frame_layout.f0_offset;
 
index 5b083aa..9814561 100644 (file)
@@ -652,26 +652,11 @@ extern int current_function_outgoing_args_size;
  { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM},     \
  { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
 
-#define CAN_ELIMINATE(FROM, TO) (1)
-
-#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)                     \
-{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)    \
-  { (OFFSET) = 0; }                                                      \
-  else  if ((FROM) == FRAME_POINTER_REGNUM                                \
-           && (TO) == HARD_FRAME_POINTER_REGNUM)                         \
-  { (OFFSET) = 0; }                                                      \
-  else if ((FROM) == ARG_POINTER_REGNUM                                   \
-            && (TO) == HARD_FRAME_POINTER_REGNUM)                         \
-  { (OFFSET) = s390_arg_frame_offset (); }                                       \
-  else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)  \
-  { (OFFSET) = s390_arg_frame_offset (); }                                       \
-  else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM                        \
-            && ((TO) == STACK_POINTER_REGNUM                              \
-                || (TO) == HARD_FRAME_POINTER_REGNUM))                    \
-  { (OFFSET) = s390_return_address_offset (); }                          \
-  else                                                                   \
-    abort();                                                             \
-}
+#define CAN_ELIMINATE(FROM, TO) \
+  s390_can_eliminate ((FROM), (TO))
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+  (OFFSET) = s390_initial_elimination_offset ((FROM), (TO))
 
 
 /* Stack arguments.  */