OSDN Git Service

* config/s390/s390.c (struct machine_function): Use save_return_addr_p
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Oct 2003 14:11:34 +0000 (14:11 +0000)
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Oct 2003 14:11:34 +0000 (14:11 +0000)
as a general flag that the return address register needs to be saved,
not necessarily because of __builtin_return_addr (0).
(s390_split_branches): Remove TEMP_REG and TEMP_USED arguments,
remove special handling of zSeries machines.
(s390_optimize_prolog): Remove TEMP_USED argument, treat the return
register as a regular register on zSeries machines.
(s390_reorg): Adjust calls to s390_split_branches and
s390_optimize_prolog.
(s390_frame_info): On zSeries machines, do not assume the return
register is always used.  Update regs_ever_live with current data
for the special registers.
(s390_emit_epilogue): Use save_return_addr_p to determine whether
the return register was saved.
* config/s390/s390.h (CONDITIONAL_REGISTER_USAGE): Do not mark
RETURN_REGNUM fixed on zSeries machines.
(REG_ALLOC_ORDER): Use RETURN_REGNUM last.
* config/s390/s390.md ("*doloop_si"): Handle branch overflow
via ahi-jgne pair on zSeries machines.
("*doloop_di"): Likewise.
("*doloop_di_long"): Remove.

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

gcc/ChangeLog
gcc/config/s390/s390.c
gcc/config/s390/s390.h
gcc/config/s390/s390.md

index 7f2ea30..888b36e 100644 (file)
@@ -1,3 +1,27 @@
+2003-10-30  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * config/s390/s390.c (struct machine_function): Use save_return_addr_p
+       as a general flag that the return address register needs to be saved,
+       not necessarily because of __builtin_return_addr (0).
+       (s390_split_branches): Remove TEMP_REG and TEMP_USED arguments,
+       remove special handling of zSeries machines.
+       (s390_optimize_prolog): Remove TEMP_USED argument, treat the return 
+       register as a regular register on zSeries machines.
+       (s390_reorg): Adjust calls to s390_split_branches and 
+       s390_optimize_prolog.
+       (s390_frame_info): On zSeries machines, do not assume the return
+       register is always used.  Update regs_ever_live with current data
+       for the special registers.
+       (s390_emit_epilogue): Use save_return_addr_p to determine whether
+       the return register was saved.
+       * config/s390/s390.h (CONDITIONAL_REGISTER_USAGE): Do not mark
+       RETURN_REGNUM fixed on zSeries machines.
+       (REG_ALLOC_ORDER): Use RETURN_REGNUM last.
+       * config/s390/s390.md ("*doloop_si"): Handle branch overflow
+       via ahi-jgne pair on zSeries machines.
+       ("*doloop_di"): Likewise.
+       ("*doloop_di_long"): Remove.
+
 2003-10-30  Richard Earnshaw  <rearnsha@arm.com>
 
        * arm.c (arm_override_options): Revert change of arm_constant_limit
index 9a343a9..67020f0 100644 (file)
@@ -190,8 +190,7 @@ struct machine_function GTY(())
   /* Set, if some of the fprs 8-15 need to be saved (64 bit abi).  */
   int save_fprs_p;
 
-  /* Set if return address needs to be saved because the current
-     function uses __builtin_return_addr (0).  */
+  /* Set if return address needs to be saved.  */
   bool save_return_addr_p;
 
   /* Number of first and last gpr to be saved, restored.  */
@@ -220,12 +219,12 @@ static const char *get_some_local_dynamic_name (void);
 static int get_some_local_dynamic_name_1 (rtx *, void *);
 static int reg_used_in_mem_p (int, rtx);
 static int addr_generation_dependency_p (rtx, rtx);
-static int s390_split_branches (rtx, bool *);
+static int s390_split_branches (void);
 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 *, rtx);
-static void s390_optimize_prolog (bool, bool);
+static void s390_optimize_prolog (bool);
 static int find_unused_clobbered_reg (void);
 static void s390_frame_info (void);
 static rtx save_fpr (rtx, int, int);
@@ -3882,15 +3881,12 @@ s390_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
 
 
 /* Split all branches that exceed the maximum distance.
-   Returns true if this created a new literal pool entry.
-
-   Code generated by this routine is allowed to use
-   TEMP_REG as temporary scratch register.  If this is
-   done, TEMP_USED is set to true.  */
+   Returns true if this created a new literal pool entry.  */
 
 static int
-s390_split_branches (rtx temp_reg, bool *temp_used)
+s390_split_branches (void)
 {
+  rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
   int new_literal = 0;
   rtx insn, pat, tmp, target;
   rtx *label;
@@ -3928,19 +3924,14 @@ s390_split_branches (rtx temp_reg, bool *temp_used)
       else
        continue;
 
-      if (get_attr_length (insn) <= (TARGET_CPU_ZARCH ? 6 : 4))
+      if (get_attr_length (insn) <= 4)
        continue;
 
-      *temp_used = 1;
+      /* We are going to use the return register as scratch register,
+        make sure it will be saved/restored by the prologue/epilogue.  */
+      cfun->machine->save_return_addr_p = 1;
 
-      if (TARGET_CPU_ZARCH)
-       {
-         tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, *label), insn);
-         INSN_ADDRESSES_NEW (tmp, -1);
-
-         target = temp_reg;
-       }
-      else if (!flag_pic)
+      if (!flag_pic)
        {
          new_literal = 1;
          tmp = force_const_mem (Pmode, *label);
@@ -5023,12 +5014,10 @@ s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
 
 /* Rework the prolog/epilog to avoid saving/restoring
    registers unnecessarily.  BASE_USED specifies whether
-   the literal pool base register needs to be saved, 
-   TEMP_USED specifies whether the return register needs
-   to be saved.  */
+   the literal pool base register needs to be saved.  */
 
 static void
-s390_optimize_prolog (bool base_used, bool temp_used)
+s390_optimize_prolog (bool base_used)
 {
   int save_first, save_last, restore_first, restore_last;
   int i, j;
@@ -5036,17 +5025,9 @@ s390_optimize_prolog (bool base_used, bool temp_used)
 
   /* Recompute regs_ever_live data for special registers.  */
   regs_ever_live[BASE_REGISTER] = base_used;
-  regs_ever_live[RETURN_REGNUM] = temp_used;
+  regs_ever_live[RETURN_REGNUM] = cfun->machine->save_return_addr_p;
   regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
 
-  /* In non-leaf functions, the prolog/epilog code relies
-     on RETURN_REGNUM being saved in any case.  We also need
-     to save the return register if __builtin_return_address (0)
-     was used in the current function.  */
-  if (!current_function_is_leaf 
-      || cfun->machine->save_return_addr_p)
-    regs_ever_live[RETURN_REGNUM] = 1;
-
 
   /* Find first and last gpr to be saved.  */
 
@@ -5093,7 +5074,7 @@ s390_optimize_prolog (bool base_used, bool temp_used)
   /* If all special registers are in fact used, there's nothing we
      can do, so no point in walking the insn list.  */
   if (i <= BASE_REGISTER && j >= BASE_REGISTER
-      && i <= RETURN_REGNUM && j >= RETURN_REGNUM)
+      && (TARGET_CPU_ZARCH || (i <= RETURN_REGNUM && j >= RETURN_REGNUM)))
     return;
 
 
@@ -5108,10 +5089,9 @@ s390_optimize_prolog (bool base_used, bool temp_used)
 
       if (GET_CODE (insn) != INSN)
        continue;
-      if (GET_CODE (PATTERN (insn)) != PARALLEL)
-       continue;
 
-      if (store_multiple_operation (PATTERN (insn), VOIDmode))
+      if (GET_CODE (PATTERN (insn)) == PARALLEL
+         && store_multiple_operation (PATTERN (insn), VOIDmode))
        {
          set = XVECEXP (PATTERN (insn), 0, 0);
          first = REGNO (SET_SRC (set));
@@ -5122,9 +5102,31 @@ s390_optimize_prolog (bool base_used, bool temp_used)
 
          if (GET_CODE (base) != REG || off < 0)
            continue;
-         if (first > BASE_REGISTER && first > RETURN_REGNUM)
+         if (first > BASE_REGISTER || last < BASE_REGISTER)
            continue;
-         if (last < BASE_REGISTER && last < RETURN_REGNUM)
+
+         if (save_first != -1)
+           {
+             new_insn = save_gprs (base, off, save_first, save_last);
+             new_insn = emit_insn_before (new_insn, insn);
+             INSN_ADDRESSES_NEW (new_insn, -1);
+           }
+
+         remove_insn (insn);
+         continue;
+       }
+
+      if (GET_CODE (PATTERN (insn)) == SET
+         && GET_CODE (SET_SRC (PATTERN (insn))) == REG
+         && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGISTER
+         && GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
+       {
+         set = PATTERN (insn);
+         offset = const0_rtx;
+         base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
+         off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
+
+         if (GET_CODE (base) != REG || off < 0)
            continue;
 
          if (save_first != -1)
@@ -5135,9 +5137,11 @@ s390_optimize_prolog (bool base_used, bool temp_used)
            }
 
          remove_insn (insn);
+         continue;
        }
 
-      if (load_multiple_operation (PATTERN (insn), VOIDmode))
+      if (GET_CODE (PATTERN (insn)) == PARALLEL
+         && load_multiple_operation (PATTERN (insn), VOIDmode))
        {
          set = XVECEXP (PATTERN (insn), 0, 0);
          first = REGNO (SET_DEST (set));
@@ -5148,9 +5152,31 @@ s390_optimize_prolog (bool base_used, bool temp_used)
 
          if (GET_CODE (base) != REG || off < 0)
            continue;
-         if (first > BASE_REGISTER && first > RETURN_REGNUM)
+         if (first > BASE_REGISTER || last < BASE_REGISTER)
            continue;
-         if (last < BASE_REGISTER && last < RETURN_REGNUM)
+
+         if (restore_first != -1)
+           {
+             new_insn = restore_gprs (base, off, restore_first, restore_last);
+             new_insn = emit_insn_before (new_insn, insn);
+             INSN_ADDRESSES_NEW (new_insn, -1);
+           }
+
+         remove_insn (insn);
+         continue;
+       }
+
+      if (GET_CODE (PATTERN (insn)) == SET
+         && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+         && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGISTER
+         && GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
+       {
+         set = PATTERN (insn);
+         offset = const0_rtx;
+         base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
+         off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
+
+         if (GET_CODE (base) != REG || off < 0)
            continue;
 
          if (restore_first != -1)
@@ -5161,6 +5187,7 @@ s390_optimize_prolog (bool base_used, bool temp_used)
            }
 
          remove_insn (insn);
+         continue;
        }
     }
 }
@@ -5170,9 +5197,7 @@ s390_optimize_prolog (bool base_used, bool temp_used)
 static void
 s390_reorg (void)
 {
-  rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
   rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
-  bool temp_used = false;
   bool base_used = false;
   bool pool_overflow = false;
 
@@ -5238,8 +5263,9 @@ s390_reorg (void)
 
       /* Split out-of-range branches.  If this has created new
         literal pool entries, cancel current chunk list and
-        recompute it.  */
-      if (s390_split_branches (temp_reg, &temp_used))
+        recompute it.  zSeries machines have large branch
+        instructions, so we never need to split a branch.  */
+      if (!TARGET_CPU_ZARCH && s390_split_branches ())
         {
           if (pool_overflow)
             s390_chunkify_cancel (pool);
@@ -5263,7 +5289,7 @@ s390_reorg (void)
       break;
     }
 
-  s390_optimize_prolog (base_used, temp_used);
+  s390_optimize_prolog (base_used);
 }
 
 
@@ -5309,7 +5335,6 @@ find_unused_clobbered_reg (void)
 static void
 s390_frame_info (void)
 {
-  char gprs_ever_live[16];
   int i, j;
   HOST_WIDE_INT fsize = get_frame_size ();
 
@@ -5336,31 +5361,42 @@ s390_frame_info (void)
       || current_function_stdarg)
     cfun->machine->frame_size += STARTING_FRAME_OFFSET;
 
+  /* If we use the return register, we'll need to make sure
+     it is going to be saved/restored.  */
+
+  if (!current_function_is_leaf
+      || regs_ever_live[RETURN_REGNUM])
+    cfun->machine->save_return_addr_p = 1;
+
   /* Find first and last gpr to be saved.  Note that at this point,
-     we assume the return register and the base register always
-     need to be saved.  This is done because the usage of these
+     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
      register might change even after the prolog was emitted.
      If it turns out later that we really don't need them, the
      prolog/epilog code is modified again.  */
 
-  for (i = 0; i < 16; i++)
-    gprs_ever_live[i] = regs_ever_live[i] && !global_regs[i];
-
-  if (flag_pic)
-    gprs_ever_live[PIC_OFFSET_TABLE_REGNUM] =
-    regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
-  gprs_ever_live[BASE_REGISTER] = 1;
-  gprs_ever_live[RETURN_REGNUM] = 1;
-  gprs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
+  regs_ever_live[BASE_REGISTER] = 1;
+  if (!TARGET_CPU_ZARCH || cfun->machine->save_return_addr_p)
+    regs_ever_live[RETURN_REGNUM] = 1;
+  regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
 
   for (i = 6; i < 16; i++)
-    if (gprs_ever_live[i])
-      break;
+    if (regs_ever_live[i])
+      if (!global_regs[i]
+         || i == STACK_POINTER_REGNUM
+          || i == RETURN_REGNUM
+          || i == BASE_REGISTER
+          || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
+       break;
 
   for (j = 15; j > i; j--)
-    if (gprs_ever_live[j])
-      break;
-
+    if (regs_ever_live[j])
+      if (!global_regs[j]
+         || j == STACK_POINTER_REGNUM
+          || j == RETURN_REGNUM
+          || j == BASE_REGISTER
+          || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM))
+       break;
 
   /* Save / Restore from gpr i to j.  */
   cfun->machine->first_save_gpr = i;
@@ -5911,7 +5947,7 @@ s390_emit_epilogue (void)
       /* Fetch return address from stack before load multiple,
         this will do good for scheduling.  */
 
-      if (!current_function_is_leaf)
+      if (cfun->machine->save_return_addr_p)
        {
          int return_regnum = find_unused_clobbered_reg();
          if (!return_regnum)
index 610223a..63fd3ee 100644 (file)
@@ -313,7 +313,7 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
    GPRs 6-15 are always call-saved.
    GPR 12 is fixed if used as GOT pointer.
    GPR 13 is always fixed (as literal pool pointer).
-   GPR 14 is always fixed (as return address).
+   GPR 14 is always fixed on S/390 machines (as return address).
    GPR 15 is always fixed (as stack pointer).
    The 'fake' hard registers are call-clobbered and fixed.
 
@@ -364,6 +364,11 @@ do                                                         \
        fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;                \
        call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;            \
       }                                                                \
+    if (TARGET_CPU_ZARCH)                                      \
+      {                                                                \
+       fixed_regs[RETURN_REGNUM] = 0;                          \
+       call_used_regs[RETURN_REGNUM] = 0;                      \
+      }                                                                \
     if (TARGET_64BIT)                                          \
       {                                                                \
         for (i = 24; i < 32; i++)                              \
@@ -378,7 +383,7 @@ do                                                          \
 
 /* Preferred register allocation order.  */
 #define REG_ALLOC_ORDER                                         \
-{  1, 2, 3, 4, 5, 0, 14, 13, 12, 11, 10, 9, 8, 7, 6,            \
+{  1, 2, 3, 4, 5, 0, 13, 12, 11, 10, 9, 8, 7, 6, 14,            \
    16, 17, 18, 19, 20, 21, 22, 23,                              \
    24, 25, 26, 27, 28, 29, 30, 31,                              \
    15, 32, 33, 34 }
index 7cf926e..3237f9c 100644 (file)
     return "#";
   else if (get_attr_length (insn) == 4)
     return "brct\t%1,%l0";
+  else if (TARGET_CPU_ZARCH)
+    return "ahi\t%1,-1\;jgne\t%l0";
   else
     abort ();
 }
   else if (get_attr_length (insn) == 4)
     return "brctg\t%1,%l0";
   else
-    abort ();
+    return "aghi\t%1,-1\;jgne\t%l0";
 }
   [(set_attr "op_type"  "RI")
    (set_attr "type"  "branch")
    (set (attr "length")
         (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
-                      (const_int 4) (const_int 12)))])
-
-(define_insn "*doloop_di_long"
-  [(set (pc)
-        (if_then_else
-          (ne (match_operand:DI 1 "register_operand" "d,d")
-              (const_int 1))
-          (match_operand 0 "address_operand" "U,U")
-          (pc)))
-   (set (match_operand:DI 2 "register_operand" "=1,?*m*d")
-        (plus:DI (match_dup 1) (const_int -1)))
-   (clobber (match_scratch:DI 3 "=X,&d"))
-   (clobber (reg:CC 33))]
-  ""
-{
-  if (get_attr_op_type (insn) == OP_TYPE_RRE)
-    return "bctgr\t%1,%0";
-  else
-    return "bctg\t%1,%a0";
-}
-  [(set (attr "op_type")
-        (if_then_else (match_operand 0 "register_operand" "")
-                      (const_string "RRE") (const_string "RXE")))
-   (set_attr "type"  "branch")
-   (set_attr "atype" "agen")])
+                      (const_int 4) (const_int 10)))])
 
 (define_split
   [(set (pc)