OSDN Git Service

prologue / epilogue / warning patches:
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Jul 2003 21:41:20 +0000 (21:41 +0000)
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Jul 2003 21:41:20 +0000 (21:41 +0000)
2003-07-16  J"orn Rennecke <joern.rennecke@superh.com>
    Con Bradley <con.bradley@superh.com>

* sh-protos.h (sh_get_pr_initial_val): Declare.
* sh.c (regno_reg_class): Make its elements type enum reg_class.
(output_stack_adjust): Remove emit_fn argument.  Add epilogue_p
and live_regs_mask arguments.  Changed all callers.
(save_schedule_s): New structure.
(save_schedule): New typedef.
(scavenge_reg, sh5_schedule_saves, sh5_schedule_saves): New functions.
(calc_live_regs): For TARGET_SHMEDIA, use leaf_function_p.
In interrupts handlers, also save registers that are usually
partially saved, and make sure there is at least one general purpose
register saved if a target register needs saving.
Add casts in comparisons to avoid warnings.
(sh_media_register_for_return): return -1 for interrupt handlers.
(MAX_SAVED_REGS, MAX_TEMPS): New defines.
(sh_expand_prologue): Use sh5_schedule_saves.  Check that any temp
registers used are available.
Set RTX_FRAME_RELATED_P where appropriate.
Add an REG_FRAME_RELATED_EXPR for r0 + offset addressing.
(sh_expand_epilogue, sh_set_return_address): Use sh5_schedule_saves.
(initial_elimination_offset): Likewise.
* sh.h (DWARF_CIE_DATA_ALIGNMENT): Set to -4.
(LOCAL_ALIGNMENT, GENERAL_REGISTER_P): Add casts to avoid warnings.
(FP_REGISTER_P): Add casts to fix broken handling of unsigned REGNO.
(XD_REGISTER_P, TARGET_REGISTER_P): Likewise.
(HARD_REGNO_CALL_PART_CLOBBERED): Also yield nonzero for r15,
and for target registers.
(RETURN_IN_MEMORY): Add parentheses to avoid warnings.
(regno_reg_class): Make its elements type enum reg_class.
(CONSTRAINT_LEN): Don't use isdigit.
(FUNCTION_ARG_REGNO_P): Add casts to avoid warnings.
(FUNCTION_ARG): Add parentheses to avoid warnings.
(RETURN_ADDR_RTX): Use sh_get_pr_initial_val.
(RETURN_ADDR_OFFSET): Define to -1 for TARGET_SH5.
(SH_DBX_REGISTER_NUMBER): Add casts to avoid warnings.
(EH_RETURN_DATA_REGNO): Use unsigned constants to avoid warnings.
* sh.md (xordi3+1): Remove unused variable regno.
(return_media): Check that tr0 is available before using it.

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

gcc/ChangeLog
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md

index 973cb77..40f776f 100644 (file)
@@ -1,3 +1,44 @@
+2003-07-16  J"orn Rennecke <joern.rennecke@superh.com>
+           Con Bradley <con.bradley@superh.com>
+
+       * sh-protos.h (sh_get_pr_initial_val): Declare.
+       * sh.c (regno_reg_class): Make its elements type enum reg_class.
+       (output_stack_adjust): Remove emit_fn argument.  Add epilogue_p
+       and live_regs_mask arguments.  Changed all callers.
+       (save_schedule_s): New structure.
+       (save_schedule): New typedef.
+       (scavenge_reg, sh5_schedule_saves, sh5_schedule_saves): New functions.
+       (calc_live_regs): For TARGET_SHMEDIA, use leaf_function_p.
+       In interrupts handlers, also save registers that are usually
+       partially saved, and make sure there is at least one general purpose
+       register saved if a target register needs saving.
+       Add casts in comparisons to avoid warnings.
+       (sh_media_register_for_return): return -1 for interrupt handlers.
+       (MAX_SAVED_REGS, MAX_TEMPS): New defines.
+       (sh_expand_prologue): Use sh5_schedule_saves.  Check that any temp
+       registers used are available.
+       Set RTX_FRAME_RELATED_P where appropriate.
+       Add an REG_FRAME_RELATED_EXPR for r0 + offset addressing.
+       (sh_expand_epilogue, sh_set_return_address): Use sh5_schedule_saves.
+       (initial_elimination_offset): Likewise.
+       * sh.h (DWARF_CIE_DATA_ALIGNMENT): Set to -4.
+       (LOCAL_ALIGNMENT, GENERAL_REGISTER_P): Add casts to avoid warnings.
+       (FP_REGISTER_P): Add casts to fix broken handling of unsigned REGNO.
+       (XD_REGISTER_P, TARGET_REGISTER_P): Likewise.
+       (HARD_REGNO_CALL_PART_CLOBBERED): Also yield nonzero for r15,
+       and for target registers.
+       (RETURN_IN_MEMORY): Add parentheses to avoid warnings.
+       (regno_reg_class): Make its elements type enum reg_class.
+       (CONSTRAINT_LEN): Don't use isdigit.
+       (FUNCTION_ARG_REGNO_P): Add casts to avoid warnings.
+       (FUNCTION_ARG): Add parentheses to avoid warnings.
+       (RETURN_ADDR_RTX): Use sh_get_pr_initial_val.
+       (RETURN_ADDR_OFFSET): Define to -1 for TARGET_SH5.
+       (SH_DBX_REGISTER_NUMBER): Add casts to avoid warnings.
+       (EH_RETURN_DATA_REGNO): Use unsigned constants to avoid warnings.
+       * sh.md (xordi3+1): Remove unused variable regno.
+       (return_media): Check that tr0 is available before using it.
+
 2003-07-16  Neil Booth  <neil@daikokuya.co.uk>
 
        * c.opt: Document more options.
index 10ef2e4..e046206 100644 (file)
@@ -136,5 +136,6 @@ extern void sh_pr_interrupt PARAMS ((struct cpp_reader *));
 extern void sh_pr_trapa PARAMS ((struct cpp_reader *));
 extern void sh_pr_nosave_low_regs PARAMS ((struct cpp_reader *));
 extern rtx function_symbol (const char *);
+extern rtx sh_get_pr_initial_val (void);
 
 #endif /* ! GCC_SH_PROTOS_H */
index ee8193c..cc75c2f 100644 (file)
@@ -108,7 +108,7 @@ rtx sh_compare_op1;
 /* Provides the class number of the smallest class containing
    reg number.  */
 
-int regno_reg_class[FIRST_PSEUDO_REGISTER] =
+enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] =
 {
   R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
@@ -190,7 +190,7 @@ static rtx find_barrier PARAMS ((int, rtx, rtx));
 static int noncall_uses_reg PARAMS ((rtx, rtx, rtx *));
 static rtx gen_block_redirect PARAMS ((rtx, int, int));
 static void sh_reorg PARAMS ((void));
-static void output_stack_adjust PARAMS ((int, rtx, int, rtx (*) (rtx)));
+static void output_stack_adjust (int, rtx, int, HARD_REG_SET *);
 static rtx frame_insn PARAMS ((rtx));
 static rtx push PARAMS ((int));
 static void pop PARAMS ((int));
@@ -234,6 +234,10 @@ static int sh_address_cost PARAMS ((rtx));
 static int shmedia_target_regs_stack_space (HARD_REG_SET *);
 static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *);
 static int shmedia_target_regs_stack_adjust (HARD_REG_SET *);
+static int scavenge_reg (HARD_REG_SET *s);
+struct save_schedule_s;
+static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *,
+                                               struct save_schedule_s *, int);
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -4558,17 +4562,16 @@ output_jump_label_table ()
 
 static int extra_push;
 
-/* Adjust the stack by SIZE bytes.  REG holds the rtl of the register
-  to be adjusted, and TEMP, if nonnegative, holds the register number
-  of a general register that we may clobber.  */
+/* Adjust the stack by SIZE bytes.  REG holds the rtl of the register to be
+   adjusted.  If epilogue_p is zero, this is for a prologue; otherwise, it's
+   for an epilogue.  If LIVE_REGS_MASK is nonzero, it points to a HARD_REG_SET
+   of all the registers that are about to be restored, and hence dead.  */
 
 static void
-output_stack_adjust (size, reg, temp, emit_fn)
-     int size;
-     rtx reg;
-     int temp;
-     rtx (*emit_fn) PARAMS ((rtx));
+output_stack_adjust (int size, rtx reg, int epilogue_p,
+                    HARD_REG_SET *live_regs_mask)
 {
+  rtx (*emit_fn) (rtx) = epilogue_p ? &emit_insn : &frame_insn;
   if (size)
     {
       HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT;
@@ -4591,10 +4594,43 @@ output_stack_adjust (size, reg, temp, emit_fn)
        {
          rtx const_reg;
          rtx insn;
+         int temp = epilogue_p ? 7 : (TARGET_SH5 ? 0 : 1);
+         int i;
 
          /* If TEMP is invalid, we could temporarily save a general
             register to MACL.  However, there is currently no need
             to handle this case, so just abort when we see it.  */
+         if (current_function_interrupt
+             || ! call_used_regs[temp] || fixed_regs[temp])
+           temp = -1;
+         if (temp < 0 && ! current_function_interrupt)
+           {
+             HARD_REG_SET temps;
+             COPY_HARD_REG_SET (temps, call_used_reg_set);
+             AND_COMPL_HARD_REG_SET (temps, call_fixed_reg_set);
+             if (epilogue_p)
+               {
+                 for (i = 0; i < HARD_REGNO_NREGS (FIRST_RET_REG, DImode); i++)
+                   CLEAR_HARD_REG_BIT (temps, FIRST_RET_REG + i);
+                 if (current_function_calls_eh_return)
+                   {
+                     CLEAR_HARD_REG_BIT (temps, EH_RETURN_STACKADJ_REGNO);
+                     for (i = 0; i <= 3; i++)
+                       CLEAR_HARD_REG_BIT (temps, EH_RETURN_DATA_REGNO (i));
+                   }
+               }
+             else
+               {
+                 for (i = FIRST_PARM_REG;
+                      i < FIRST_PARM_REG + NPARM_REGS (SImode); i++)
+                   CLEAR_HARD_REG_BIT (temps, i);
+                 if (current_function_needs_context)
+                   CLEAR_HARD_REG_BIT (temps, STATIC_CHAIN_REGNUM);
+               }
+             temp = scavenge_reg (&temps);
+           }
+         if (temp < 0 && live_regs_mask)
+           temp = scavenge_reg (live_regs_mask);
          if (temp < 0)
            abort ();
          const_reg = gen_rtx_REG (GET_MODE (reg), temp);
@@ -4612,7 +4648,7 @@ output_stack_adjust (size, reg, temp, emit_fn)
              emit_insn (GEN_MOV (const_reg, GEN_INT (size)));
              insn = emit_fn (GEN_ADD3 (reg, reg, const_reg));
            }
-         if (emit_fn == frame_insn)
+         if (! epilogue_p)
            REG_NOTES (insn)
              = (gen_rtx_EXPR_LIST
                 (REG_FRAME_RELATED_EXPR,
@@ -4789,12 +4825,11 @@ calc_live_regs (live_regs_mask)
   int reg;
   int count;
   int interrupt_handler;
-  int pr_live;
+  int pr_live, has_call;
 
   interrupt_handler = sh_cfun_interrupt_handler_p ();
 
-  for (count = 0; 32 * count < FIRST_PSEUDO_REGISTER; count++)
-    CLEAR_HARD_REG_SET (*live_regs_mask);
+  CLEAR_HARD_REG_SET (*live_regs_mask);
   if (TARGET_SH4 && TARGET_FMOVD && interrupt_handler
       && regs_ever_live[FPSCR_REG])
     target_flags &= ~FPU_SINGLE_BIT;
@@ -4829,16 +4864,19 @@ calc_live_regs (live_regs_mask)
           & ~ CALL_COOKIE_RET_TRAMP (1))
          || current_function_has_nonlocal_label))
     pr_live = 1;
+  has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live;
   for (count = 0, reg = FIRST_PSEUDO_REGISTER - 1; reg >= 0; reg--)
     {
-      if (reg == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG)
+      if ((! TARGET_SHMEDIA && reg == PR_REG)
          ? pr_live
          : (interrupt_handler && ! pragma_trapa)
          ? (/* Need to save all the regs ever live.  */
             (regs_ever_live[reg]
              || (call_used_regs[reg]
                  && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG)
-                 && pr_live))
+                 && has_call)
+             || (has_call && REGISTER_NATURAL_MODE (reg) == SImode
+                 && (GENERAL_REGISTER_P (reg) || TARGET_REGISTER_P (reg))))
             && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
             && reg != RETURN_ADDRESS_POINTER_REGNUM
             && reg != T_REG && reg != GBR_REG
@@ -4848,13 +4886,13 @@ calc_live_regs (live_regs_mask)
             (TARGET_SHCOMPACT
              && flag_pic
              && current_function_args_info.call_cookie
-             && reg == PIC_OFFSET_TABLE_REGNUM)
+             && reg == (int) PIC_OFFSET_TABLE_REGNUM)
             || (regs_ever_live[reg] && ! call_used_regs[reg])
             || (current_function_calls_eh_return
-                && (reg == EH_RETURN_DATA_REGNO (0)
-                    || reg == EH_RETURN_DATA_REGNO (1)
-                    || reg == EH_RETURN_DATA_REGNO (2)
-                    || reg == EH_RETURN_DATA_REGNO (3)))))
+                && (reg == (int) EH_RETURN_DATA_REGNO (0)
+                    || reg == (int) EH_RETURN_DATA_REGNO (1)
+                    || reg == (int) EH_RETURN_DATA_REGNO (2)
+                    || reg == (int) EH_RETURN_DATA_REGNO (3)))))
        {
          SET_HARD_REG_BIT (*live_regs_mask, reg);
          count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
@@ -4891,6 +4929,19 @@ calc_live_regs (live_regs_mask)
          SET_HARD_REG_BIT (*live_regs_mask, reg);
          count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
        }
+  /* If this is an interrupt handler, we don't have any call-clobbered
+     registers we can conveniently use for target register save/restore.
+     Make sure we save at least one general purpose register when we need
+     to save target registers.  */
+  if (interrupt_handler
+      && hard_regs_intersect_p (live_regs_mask,
+                               &reg_class_contents[TARGET_REGS])
+      && ! hard_regs_intersect_p (live_regs_mask,
+                                 &reg_class_contents[GENERAL_REGS]))
+    {
+      SET_HARD_REG_BIT (*live_regs_mask, R0_REG);
+      count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (R0_REG));
+    }
 
   return count;
 }
@@ -4921,6 +4972,9 @@ sh_media_register_for_return ()
 
   if (! current_function_is_leaf)
     return -1;
+  if (lookup_attribute ("interrupt_handler",
+                       DECL_ATTRIBUTES (current_function_decl)))
+    return -1;
 
   tr0_used = flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
 
@@ -4931,6 +4985,130 @@ sh_media_register_for_return ()
   return -1;
 }
 
+/* The maximum registers we need to save are:
+   - 62 general purpose registers (r15 is stack pointer, r63 is zero)
+   - 32 floating point registers (for each pair, we save none,
+         one single precision value, or a double precision value).
+   -  8 target registers
+   -  add 1 entry for a delimiter.  */
+#define MAX_SAVED_REGS (62+32+8)
+
+typedef struct save_entry_s
+{
+  unsigned char reg;
+  unsigned char mode;
+  short offset;
+} save_entry;
+
+#define MAX_TEMPS 4
+
+/* There will be a delimiter entry with VOIDmode both at the start and the
+   end of a filled in schedule.  The end delimiter has the offset of the
+   save with the smallest (i.e. most negative) offset.  */
+typedef struct save_schedule_s
+{
+  save_entry entries[MAX_SAVED_REGS + 2];
+  int temps[MAX_TEMPS+1];
+} save_schedule;
+
+/* Fill in SCHEDULE according to LIVE_REGS_MASK.  If RESTORE is nonzero,
+   use reverse order.  Returns the last entry written to (not counting
+   the delimiter).  OFFSET_BASE is a number to be added to all offset
+   entries.  */
+   
+static save_entry *
+sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule,
+                   int offset_base)
+{
+  int align, i;
+  save_entry *entry = schedule->entries;
+  int tmpx = 0;
+  int offset;
+
+  if (! current_function_interrupt)
+    for (i = FIRST_GENERAL_REG; tmpx < MAX_TEMPS && i <= LAST_GENERAL_REG; i++)
+      if (call_used_regs[i] && ! fixed_regs[i]
+         && ! FUNCTION_ARG_REGNO_P (i)
+         && i != FIRST_RET_REG
+         && ! (current_function_needs_context && i == STATIC_CHAIN_REGNUM)
+         && ! (current_function_calls_eh_return
+               && (i == EH_RETURN_STACKADJ_REGNO
+                   || ((unsigned)i <= EH_RETURN_DATA_REGNO (0)
+                       && (unsigned)i >= EH_RETURN_DATA_REGNO (3)))))
+       schedule->temps[tmpx++] = i;
+  entry->reg = -1;
+  entry->mode = VOIDmode;
+  entry->offset = offset_base;
+  entry++;
+  /* We loop twice: first, we save 8-byte aligned registers in the
+     higher addresses, that are known to be aligned.  Then, we
+     proceed to saving 32-bit registers that don't need 8-byte
+     alignment.
+     If this is an interrupt function, all registers that need saving
+     need to be saved in full.  moreover, we need to postpone saving
+     target registers till we have saved some general purpose registers
+     we can then use as scratch registers.  */
+  offset = offset_base;
+  for (align = 1; align >= 0; align--)
+    {
+      for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
+       if (TEST_HARD_REG_BIT (*live_regs_mask, i))
+         {
+           enum machine_mode mode = REGISTER_NATURAL_MODE (i);
+           int reg = i;
+
+           if (current_function_interrupt)
+             {
+               if (TARGET_REGISTER_P (i))
+                 continue;
+               if (GENERAL_REGISTER_P (i))
+                 mode = DImode;
+             }
+           if (mode == SFmode && (i % 2) == 1
+               && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i)
+               && (TEST_HARD_REG_BIT (*live_regs_mask, (i ^ 1))))
+             {
+               mode = DFmode;
+               i--;
+               reg--;
+             }
+
+           /* If we're doing the aligned pass and this is not aligned,
+              or we're doing the unaligned pass and this is aligned,
+              skip it.  */
+           if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) == 0)
+               != align)
+             continue;
+
+           if (current_function_interrupt
+               && GENERAL_REGISTER_P (i)
+               && tmpx < MAX_TEMPS)
+             schedule->temps[tmpx++] = i;
+
+           offset -= GET_MODE_SIZE (mode);
+           entry->reg = i;
+           entry->mode = mode;
+           entry->offset = offset;
+           entry++;
+         }
+      if (align && current_function_interrupt)
+       for (i = LAST_TARGET_REG; i >= FIRST_TARGET_REG; i--)
+         if (TEST_HARD_REG_BIT (*live_regs_mask, i))
+           {
+             offset -= GET_MODE_SIZE (DImode);
+             entry->reg = i;
+             entry->mode = DImode;
+             entry->offset = offset;
+             entry++;
+           }
+    }
+  entry->reg = -1;
+  entry->mode = VOIDmode;
+  entry->offset = offset;
+  schedule->temps[tmpx] = -1;
+  return entry - 1;
+}
+
 void
 sh_expand_prologue ()
 {
@@ -4945,7 +5123,7 @@ sh_expand_prologue ()
      and partially on the stack, e.g. a large structure.  */
   output_stack_adjust (-current_function_pretend_args_size
                       - current_function_args_info.stack_regs * 8,
-                      stack_pointer_rtx, TARGET_SH5 ? 0 : 1, frame_insn);
+                      stack_pointer_rtx, 0, NULL);
 
   extra_push = 0;
 
@@ -5034,14 +5212,19 @@ sh_expand_prologue ()
     
   if (TARGET_SH5)
     {
-      int i;
-      int offset;
-      int align;
-      rtx r0 = gen_rtx_REG (Pmode, R0_REG);
+      int offset_base, offset;
+      rtx r0 = NULL_RTX;
       int offset_in_r0 = -1;
       int sp_in_r0 = 0;
       int tregs_space = shmedia_target_regs_stack_adjust (&live_regs_mask);
       int total_size, save_size;
+      save_schedule schedule;
+      save_entry *entry;
+      int *tmp_pnt;
+
+      if (call_used_regs[R0_REG] && ! fixed_regs[R0_REG]
+         && ! current_function_interrupt)
+       r0 = gen_rtx_REG (Pmode, R0_REG);
 
       /* D is the actual number of bytes that we need for saving registers,
         however, in initial_elimination_offset we have committed to using
@@ -5067,146 +5250,153 @@ sh_expand_prologue ()
                  && total_size <= 2044)))
        d_rounding = total_size - save_size;
 
-      offset = d + d_rounding;
+      offset_base = d + d_rounding;
 
       output_stack_adjust (-(save_size + d_rounding), stack_pointer_rtx,
-                          1, frame_insn);
-
-      /* We loop twice: first, we save 8-byte aligned registers in the
-        higher addresses, that are known to be aligned.  Then, we
-        proceed to saving 32-bit registers that don't need 8-byte
-        alignment.  */
-      /* Note that if you change this code in a way that affects where
-        the return register is saved, you have to update not only
-        sh_expand_epilogue, but also sh_set_return_address.  */
-      for (align = 1; align >= 0; align--)
-       for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
-         if (TEST_HARD_REG_BIT (live_regs_mask, i))
-           {
-             enum machine_mode mode = REGISTER_NATURAL_MODE (i);
-             int reg = i;
-             rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX;
+                          0, NULL);
 
-             if (mode == SFmode && (i % 2) == 1
-                 && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i)
-                 && (TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1))))
-               {
-                 mode = DFmode;
-                 i--;
-                 reg--;
-               }
-               
-             /* If we're doing the aligned pass and this is not aligned,
-                or we're doing the unaligned pass and this is aligned,
-                skip it.  */
-             if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT)
-                  == 0) != align)
-               continue;
+      sh5_schedule_saves (&live_regs_mask, &schedule, offset_base);
+      tmp_pnt = schedule.temps;
+      for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++)
+        {
+         enum machine_mode mode = entry->mode;
+         int reg = entry->reg;
+         rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX;
 
-             offset -= GET_MODE_SIZE (mode);
+         offset = entry->offset;
 
-             reg_rtx = gen_rtx_REG (mode, reg);
+         reg_rtx = gen_rtx_REG (mode, reg);
 
-             mem_rtx = gen_rtx_MEM (mode,
-                                    gen_rtx_PLUS (Pmode,
-                                                  stack_pointer_rtx,
-                                                  GEN_INT (offset)));
+         mem_rtx = gen_rtx_MEM (mode,
+                                gen_rtx_PLUS (Pmode,
+                                              stack_pointer_rtx,
+                                              GEN_INT (offset)));
 
-             GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec);
+         GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec);
 
-             mem_rtx = NULL_RTX;
+         if (! r0)
+           abort ();
+         mem_rtx = NULL_RTX;
 
-           try_pre_dec:
-             do
-               if (HAVE_PRE_DECREMENT
-                   && (offset_in_r0 - offset == GET_MODE_SIZE (mode)
-                       || mem_rtx == NULL_RTX
-                       || i == PR_REG || SPECIAL_REGISTER_P (i)))
-                 {
-                   pre_dec = gen_rtx_MEM (mode,
-                                          gen_rtx_PRE_DEC (Pmode, r0));
+       try_pre_dec:
+         do
+           if (HAVE_PRE_DECREMENT
+               && (offset_in_r0 - offset == GET_MODE_SIZE (mode)
+                   || mem_rtx == NULL_RTX
+                   || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
+             {
+               pre_dec = gen_rtx_MEM (mode,
+                                      gen_rtx_PRE_DEC (Pmode, r0));
 
-                   GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0),
-                                             pre_dec_ok);
+               GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0),
+                                         pre_dec_ok);
 
-                   pre_dec = NULL_RTX;
+               pre_dec = NULL_RTX;
 
-                   break;
+               break;
 
-                 pre_dec_ok:
-                   mem_rtx = NULL_RTX;
-                   offset += GET_MODE_SIZE (mode);
-                 }
-             while (0);
+             pre_dec_ok:
+               mem_rtx = NULL_RTX;
+               offset += GET_MODE_SIZE (mode);
+             }
+         while (0);
 
-             if (mem_rtx != NULL_RTX)
-               goto addr_ok;
+         if (mem_rtx != NULL_RTX)
+           goto addr_ok;
 
-             if (offset_in_r0 == -1)
-               {
-                 emit_move_insn (r0, GEN_INT (offset));
-                 offset_in_r0 = offset;
-               }
-             else if (offset != offset_in_r0)
+         if (offset_in_r0 == -1)
+           {
+             emit_move_insn (r0, GEN_INT (offset));
+             offset_in_r0 = offset;
+           }
+         else if (offset != offset_in_r0)
+           {
+             emit_move_insn (r0,
+                             gen_rtx_PLUS
+                             (Pmode, r0,
+                              GEN_INT (offset - offset_in_r0)));
+             offset_in_r0 += offset - offset_in_r0;
+           }
+                                             
+         if (pre_dec != NULL_RTX)
+           {
+             if (! sp_in_r0)
                {
                  emit_move_insn (r0,
                                  gen_rtx_PLUS
-                                 (Pmode, r0,
-                                  GEN_INT (offset - offset_in_r0)));
-                 offset_in_r0 += offset - offset_in_r0;
+                                 (Pmode, r0, stack_pointer_rtx));
+                 sp_in_r0 = 1;
                }
-                                                 
-             if (pre_dec != NULL_RTX)
-               {
-                 if (! sp_in_r0)
-                   {
-                     emit_move_insn (r0,
-                                     gen_rtx_PLUS
-                                     (Pmode, r0, stack_pointer_rtx));
-                     sp_in_r0 = 1;
-                   }
 
-                 offset -= GET_MODE_SIZE (mode);
-                 offset_in_r0 -= GET_MODE_SIZE (mode);
+             offset -= GET_MODE_SIZE (mode);
+             offset_in_r0 -= GET_MODE_SIZE (mode);
 
-                 mem_rtx = pre_dec;
-               }
-             else if (sp_in_r0)
-               mem_rtx = gen_rtx_MEM (mode, r0);
-             else
-               mem_rtx = gen_rtx_MEM (mode,
-                                      gen_rtx_PLUS (Pmode,
-                                                    stack_pointer_rtx,
-                                                    r0));
-
-             /* We must not use an r0-based address for target-branch
-                registers or for special registers without pre-dec
-                memory addresses, since we store their values in r0
-                first.  */
-             if (TARGET_REGISTER_P (i)
-                 || ((i == PR_REG || SPECIAL_REGISTER_P (i))
-                     && mem_rtx != pre_dec))
-               abort ();
-
-           addr_ok:
-             if (TARGET_REGISTER_P (i)
-                 || ((i == PR_REG || SPECIAL_REGISTER_P (i))
-                     && mem_rtx != pre_dec))
-               {
-                 rtx r0mode = gen_rtx_REG (GET_MODE (reg_rtx), R0_REG);
+             mem_rtx = pre_dec;
+           }
+         else if (sp_in_r0)
+           mem_rtx = gen_rtx_MEM (mode, r0);
+         else
+           mem_rtx = gen_rtx_MEM (mode,
+                                  gen_rtx_PLUS (Pmode,
+                                                stack_pointer_rtx,
+                                                r0));
+
+         /* We must not use an r0-based address for target-branch
+            registers or for special registers without pre-dec
+            memory addresses, since we store their values in r0
+            first.  */
+         if (TARGET_REGISTER_P (reg)
+             || ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
+                 && mem_rtx != pre_dec))
+           abort ();
+
+       addr_ok:
+         if (TARGET_REGISTER_P (reg)
+             || ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
+                 && mem_rtx != pre_dec))
+           {
+             rtx tmp_reg = gen_rtx_REG (GET_MODE (reg_rtx), *tmp_pnt);
 
-                 emit_move_insn (r0mode, reg_rtx);
+             emit_move_insn (tmp_reg, reg_rtx);
 
+             if (REGNO (tmp_reg) == R0_REG)
+               {
                  offset_in_r0 = -1;
                  sp_in_r0 = 0;
-
-                 reg_rtx = r0mode;
+                 if (refers_to_regno_p (R0_REG, R0_REG+1, mem_rtx, (rtx *) 0))
+                   abort ();
                }
 
-             emit_move_insn (mem_rtx, reg_rtx);
+             if (*++tmp_pnt <= 0)
+               tmp_pnt = schedule.temps;
+
+             reg_rtx = tmp_reg;
            }
+         {
+           rtx insn;
+
+           /* Mark as interesting for dwarf cfi generator */
+           insn = emit_move_insn (mem_rtx, reg_rtx);
+           RTX_FRAME_RELATED_P (insn) = 1;
+
+           if (TARGET_SHCOMPACT && (offset_in_r0 != -1)) 
+             {
+               rtx reg_rtx = gen_rtx_REG (mode, reg);
+               rtx set, note_rtx;
+               rtx mem_rtx = gen_rtx_MEM (mode,
+                                          gen_rtx_PLUS (Pmode,
+                                                        stack_pointer_rtx,
+                                                        GEN_INT (offset)));
+
+               set = gen_rtx_SET (VOIDmode, mem_rtx, reg_rtx);
+               note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set,
+                                             REG_NOTES (insn));
+               REG_NOTES (insn) = note_rtx;
+             }
+         }
+       }
 
-      if (offset != d_rounding)
+      if (entry->offset != d_rounding)
        abort ();
     }
   else
@@ -5258,7 +5448,7 @@ sh_expand_prologue ()
   target_flags = save_flags;
 
   output_stack_adjust (-rounded_frame_size (d) + d_rounding,
-                      stack_pointer_rtx, TARGET_SH5 ? 0 : 1, frame_insn);
+                      stack_pointer_rtx, 0, NULL);
 
   if (frame_pointer_needed)
     frame_insn (GEN_MOV (frame_pointer_rtx, stack_pointer_rtx));
@@ -5318,7 +5508,7 @@ sh_expand_epilogue ()
 
   if (frame_pointer_needed)
     {
-      output_stack_adjust (frame_size, frame_pointer_rtx, 7, emit_insn);
+      output_stack_adjust (frame_size, frame_pointer_rtx, 1, &live_regs_mask);
 
       /* We must avoid moving the stack pointer adjustment past code
         which reads from the local frame, else an interrupt could
@@ -5334,7 +5524,7 @@ sh_expand_epilogue ()
         occur after the SP adjustment and clobber data in the local
         frame.  */
       emit_insn (gen_blockage ());
-      output_stack_adjust (frame_size, stack_pointer_rtx, 7, emit_insn);
+      output_stack_adjust (frame_size, stack_pointer_rtx, 1, &live_regs_mask);
     }
 
   if (SHMEDIA_REGS_STACK_ADJUST ())
@@ -5355,143 +5545,126 @@ sh_expand_epilogue ()
     emit_insn (gen_toggle_sz ());
   if (TARGET_SH5)
     {
-      int offset = d_rounding;
+      int offset_base, offset;
       int offset_in_r0 = -1;
       int sp_in_r0 = 0;
-      int align;
       rtx r0 = gen_rtx_REG (Pmode, R0_REG);
-      int tmp_regno = R20_REG;
+      save_schedule schedule;
+      save_entry *entry;
+      int *tmp_pnt;
       
-      /* We loop twice: first, we save 8-byte aligned registers in the
-        higher addresses, that are known to be aligned.  Then, we
-        proceed to saving 32-bit registers that don't need 8-byte
-        alignment.  */
-      for (align = 0; align <= 1; align++)
-       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-         if (TEST_HARD_REG_BIT (live_regs_mask, i))
-           {
-             enum machine_mode mode = REGISTER_NATURAL_MODE (i);
-             int reg = i;
-             rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn;
+      entry = sh5_schedule_saves (&live_regs_mask, &schedule, d_rounding);
+      offset_base = -entry[1].offset + d_rounding;
+      tmp_pnt = schedule.temps;
+      for (; entry->mode != VOIDmode; entry--)
+       {
+         enum machine_mode mode = entry->mode;
+         int reg = entry->reg;
+         rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn;
 
-             if (mode == SFmode && (i % 2) == 0
-                 && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i)
-                 && (TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1))))
-               {
-                 mode = DFmode;
-                 i++;
-               }
+         offset = offset_base + entry->offset;
+         reg_rtx = gen_rtx_REG (mode, reg);
 
-             /* If we're doing the aligned pass and this is not aligned,
-                or we're doing the unaligned pass and this is aligned,
-                skip it.  */
-             if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT)
-                  == 0) != align)
-               continue;
+         mem_rtx = gen_rtx_MEM (mode,
+                                gen_rtx_PLUS (Pmode,
+                                              stack_pointer_rtx,
+                                              GEN_INT (offset)));
 
-             reg_rtx = gen_rtx_REG (mode, reg);
+         GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
 
-             mem_rtx = gen_rtx_MEM (mode,
-                                    gen_rtx_PLUS (Pmode,
-                                                  stack_pointer_rtx,
-                                                  GEN_INT (offset)));
+         mem_rtx = NULL_RTX;
 
-             GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
+       try_post_inc:
+         do
+           if (HAVE_POST_INCREMENT
+               && (offset == offset_in_r0
+                   || (offset + GET_MODE_SIZE (mode) != d + d_rounding
+                       && mem_rtx == NULL_RTX)
+                   || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
+             {
+               post_inc = gen_rtx_MEM (mode,
+                                       gen_rtx_POST_INC (Pmode, r0));
 
-             mem_rtx = NULL_RTX;
+               GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0),
+                                         post_inc_ok);
 
-           try_post_inc:
-             do
-               if (HAVE_POST_INCREMENT
-                   && (offset == offset_in_r0
-                       || (offset + GET_MODE_SIZE (mode) != d + d_rounding
-                           && mem_rtx == NULL_RTX)
-                       || i == PR_REG || SPECIAL_REGISTER_P (i)))
-                 {
-                   post_inc = gen_rtx_MEM (mode,
-                                           gen_rtx_POST_INC (Pmode, r0));
-
-                   GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0),
-                                             post_inc_ok);
+               post_inc = NULL_RTX;
 
-                   post_inc = NULL_RTX;
+               break;
+               
+             post_inc_ok:
+               mem_rtx = NULL_RTX;
+             }
+         while (0);
+         
+         if (mem_rtx != NULL_RTX)
+           goto addr_ok;
 
-                   break;
-                   
-                 post_inc_ok:
-                   mem_rtx = NULL_RTX;
-                 }
-             while (0);
+         if (offset_in_r0 == -1)
+           {
+             emit_move_insn (r0, GEN_INT (offset));
+             offset_in_r0 = offset;
+           }
+         else if (offset != offset_in_r0)
+           {
+             emit_move_insn (r0,
+                             gen_rtx_PLUS
+                             (Pmode, r0,
+                              GEN_INT (offset - offset_in_r0)));
+             offset_in_r0 += offset - offset_in_r0;
+           }
              
-             if (mem_rtx != NULL_RTX)
-               goto addr_ok;
-
-             if (offset_in_r0 == -1)
-               {
-                 emit_move_insn (r0, GEN_INT (offset));
-                 offset_in_r0 = offset;
-               }
-             else if (offset != offset_in_r0)
+         if (post_inc != NULL_RTX)
+           {
+             if (! sp_in_r0)
                {
                  emit_move_insn (r0,
                                  gen_rtx_PLUS
-                                 (Pmode, r0,
-                                  GEN_INT (offset - offset_in_r0)));
-                 offset_in_r0 += offset - offset_in_r0;
+                                 (Pmode, r0, stack_pointer_rtx));
+                 sp_in_r0 = 1;
                }
-                 
-             if (post_inc != NULL_RTX)
-               {
-                 if (! sp_in_r0)
-                   {
-                     emit_move_insn (r0,
-                                     gen_rtx_PLUS
-                                     (Pmode, r0, stack_pointer_rtx));
-                     sp_in_r0 = 1;
-                   }
-                 
-                 mem_rtx = post_inc;
+             
+             mem_rtx = post_inc;
 
-                 offset_in_r0 += GET_MODE_SIZE (mode);
-               }
-             else if (sp_in_r0)
-               mem_rtx = gen_rtx_MEM (mode, r0);
-             else
-               mem_rtx = gen_rtx_MEM (mode,
-                                      gen_rtx_PLUS (Pmode,
-                                                    stack_pointer_rtx,
-                                                    r0));
-
-             if ((i == PR_REG || SPECIAL_REGISTER_P (i))
-                 && mem_rtx != post_inc)
-               abort ();
-
-           addr_ok:
-             if ((i == PR_REG || SPECIAL_REGISTER_P (i))
-                 && mem_rtx != post_inc)
-               {
-                 insn = emit_move_insn (r0, mem_rtx);
-                 mem_rtx = r0;
-               }
-             else if (TARGET_REGISTER_P (i))
-               {
-                 rtx tmp_reg = gen_rtx_REG (mode, tmp_regno);
-
-                 /* Give the scheduler a bit of freedom by using R20..R23
-                    in a round-robin fashion.  Don't use R1 here because
-                    we want to use it for EH_RETURN_STACKADJ_RTX.  */
-                 insn = emit_move_insn (tmp_reg, mem_rtx);
-                 mem_rtx = tmp_reg;
-                 if (++tmp_regno > R23_REG)
-                   tmp_regno = R20_REG;
-               }
+             offset_in_r0 += GET_MODE_SIZE (mode);
+           }
+         else if (sp_in_r0)
+           mem_rtx = gen_rtx_MEM (mode, r0);
+         else
+           mem_rtx = gen_rtx_MEM (mode,
+                                  gen_rtx_PLUS (Pmode,
+                                                stack_pointer_rtx,
+                                                r0));
 
-             insn = emit_move_insn (reg_rtx, mem_rtx);
+         if ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
+             && mem_rtx != post_inc)
+           abort ();
 
-             offset += GET_MODE_SIZE (mode);
+       addr_ok:
+         if ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
+             && mem_rtx != post_inc)
+           {
+             insn = emit_move_insn (r0, mem_rtx);
+             mem_rtx = r0;
+           }
+         else if (TARGET_REGISTER_P (reg))
+           {
+             rtx tmp_reg = gen_rtx_REG (mode, *tmp_pnt);
+
+             /* Give the scheduler a bit of freedom by using up to
+                MAX_TEMPS registers in a round-robin fashion.  */
+             insn = emit_move_insn (tmp_reg, mem_rtx);
+             mem_rtx = tmp_reg;
+             if (*++tmp_pnt < 0)
+               tmp_pnt = schedule.temps;
            }
 
-      if (offset != d + d_rounding)
+         insn = emit_move_insn (reg_rtx, mem_rtx);
+
+         offset += GET_MODE_SIZE (mode);
+       }
+
+      if (entry->offset + offset_base != d + d_rounding)
        abort ();
     }
   else /* ! TARGET_SH5 */
@@ -5521,7 +5694,7 @@ sh_expand_epilogue ()
   output_stack_adjust (extra_push + current_function_pretend_args_size
                       + save_size + d_rounding
                       + current_function_args_info.stack_regs * 8,
-                      stack_pointer_rtx, 7, emit_insn);
+                      stack_pointer_rtx, 1, NULL);
 
   if (current_function_calls_eh_return)
     emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx,
@@ -5566,7 +5739,6 @@ sh_set_return_address (ra, tmp)
 {
   HARD_REG_SET live_regs_mask;
   int d;
-  int d_rounding = 0;
   int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
   int pr_offset;
 
@@ -5598,56 +5770,26 @@ sh_set_return_address (ra, tmp)
 
   if (TARGET_SH5)
     {
-      int i;
       int offset;
-      int align;
+      save_schedule schedule;
+      save_entry *entry;
       
-      if (d % (STACK_BOUNDARY / BITS_PER_UNIT))
-       d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT)
-                     - d % (STACK_BOUNDARY / BITS_PER_UNIT));
-
-      offset = 0;
-
-      /* We loop twice: first, we save 8-byte aligned registers in the
-        higher addresses, that are known to be aligned.  Then, we
-        proceed to saving 32-bit registers that don't need 8-byte
-        alignment.  */
-      for (align = 0; align <= 1; align++)
-       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-         if (TEST_HARD_REG_BIT (live_regs_mask, i))
-           {
-             enum machine_mode mode = REGISTER_NATURAL_MODE (i);
-
-             if (mode == SFmode && (i % 2) == 0
-                 && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i)
-                 && (TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1))))
-               {
-                 mode = DFmode;
-                 i++;
-               }
-
-             /* If we're doing the aligned pass and this is not aligned,
-                or we're doing the unaligned pass and this is aligned,
-                skip it.  */
-             if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT)
-                  == 0) != align)
-               continue;
-
-             if (i == pr_reg)
-               goto found;
-
-             offset += GET_MODE_SIZE (mode);
-           }
+      entry = sh5_schedule_saves (&live_regs_mask, &schedule, 0);
+      offset = entry[1].offset;
+      for (; entry->mode != VOIDmode; entry--)
+       if (entry->reg == pr_reg)
+         goto found;
 
       /* We can't find pr register.  */
       abort ();
 
     found:
-      pr_offset = (rounded_frame_size (d) - d_rounding + offset
+      offset = entry->offset - offset;
+      pr_offset = (rounded_frame_size (d) + offset
                   + SHMEDIA_REGS_STACK_ADJUST ());
     }
   else
-    pr_offset = rounded_frame_size (d) - d_rounding;
+    pr_offset = rounded_frame_size (d);
 
   emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset)));
   emit_insn (GEN_ADD3 (tmp, tmp, frame_pointer_rtx));
@@ -6188,9 +6330,10 @@ initial_elimination_offset (from, to)
     {
       if (TARGET_SH5)
        {
-         int i, n = total_saved_regs_space;
-         int align;
+         int n = total_saved_regs_space;
          int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
+         save_schedule schedule;
+         save_entry *entry;
          
          n += total_auto_space;
 
@@ -6200,40 +6343,13 @@ initial_elimination_offset (from, to)
 
          target_flags = copy_flags;
 
-         /* We loop twice: first, check 8-byte aligned registers,
-            that are stored in the higher addresses, that are known
-            to be aligned.  Then, check 32-bit registers that don't
-            need 8-byte alignment.  */
-         for (align = 1; align >= 0; align--)
-           for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
-             if (TEST_HARD_REG_BIT (live_regs_mask, i))
-               {
-                 enum machine_mode mode = REGISTER_NATURAL_MODE (i);
-
-                 if (mode == SFmode && (i % 2) == 1
-                     && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i)
-                     && TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1)))
-                   {
-                     mode = DFmode;
-                     i--;
-                   }
-               
-                 /* If we're doing the aligned pass and this is not aligned,
-                    or we're doing the unaligned pass and this is aligned,
-                    skip it.  */
-                 if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT)
-                      == 0) != align)
-                   continue;
-
-                 n -= GET_MODE_SIZE (mode);
-
-                 if (i == pr_reg)
-                   {
-                     target_flags = save_flags;
-                     return n;
-                   }
-               }
-
+         sh5_schedule_saves (&live_regs_mask, &schedule, n);
+         for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++)
+           if (entry->reg == pr_reg)
+             {
+               target_flags = save_flags;
+               return entry->offset;
+             }
          abort ();
        }
       else
@@ -8705,4 +8821,22 @@ function_symbol (const char *name)
   return sym;
 }
 
+/* Find the number of a general purpose register in S.  */
+static int
+scavenge_reg (HARD_REG_SET *s)
+{
+  int r;
+  for (r = FIRST_GENERAL_REG; r <= LAST_GENERAL_REG; r++)
+    if (TEST_HARD_REG_BIT (*s, r))
+      return r;
+  return -1;
+}
+
+rtx
+sh_get_pr_initial_val (void)
+{
+  return
+    get_hard_reg_initial_val (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
+}
+
 #include "gt-sh.h"
index 9ab647a..cf97d91 100644 (file)
@@ -591,6 +591,13 @@ do {                                                                       \
 #define UNITS_PER_WORD (TARGET_SHMEDIA ? 8 : 4)
 #define MIN_UNITS_PER_WORD 4
 
+/* Scaling factor for Dwarf data offsets for CFI information.
+   The dwarf2out.c default would use -UNITS_PER_WORD, which is -8 for
+   SHmedia; however, since we do partial register saves for the registers
+   visible to SHcompact, and for target registers for SHMEDIA32, we have
+   to allow saves that are only 4-byte aligned.  */
+#define DWARF_CIE_DATA_ALIGNMENT -4
+
 /* Width in bits of a pointer.
    See also the macro `Pmode' defined below.  */
 #define POINTER_SIZE  (TARGET_SHMEDIA64 ? 64 : 32)
@@ -639,8 +646,8 @@ do {                                                                        \
 #define LOCAL_ALIGNMENT(TYPE, ALIGN) \
   ((GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_INT \
     || GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_FLOAT) \
-   ? MIN (BIGGEST_ALIGNMENT, GET_MODE_BITSIZE (TYPE_MODE (TYPE))) \
-   : ALIGN)
+   ? (unsigned) MIN (BIGGEST_ALIGNMENT, GET_MODE_BITSIZE (TYPE_MODE (TYPE))) \
+   : (unsigned) ALIGN)
 
 /* Make arrays of chars word-aligned for the same reasons.  */
 #define DATA_ALIGNMENT(TYPE, ALIGN)            \
@@ -816,16 +823,18 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
 #define LAST_TARGET_REG  (FIRST_TARGET_REG + (TARGET_SHMEDIA ? 7 : -1))
 
 #define GENERAL_REGISTER_P(REGNO) \
-  IN_RANGE ((REGNO), FIRST_GENERAL_REG, LAST_GENERAL_REG)
+  IN_RANGE ((REGNO), \
+           (unsigned HOST_WIDE_INT) FIRST_GENERAL_REG, \
+           (unsigned HOST_WIDE_INT) LAST_GENERAL_REG)
 
 #define GENERAL_OR_AP_REGISTER_P(REGNO) \
   (GENERAL_REGISTER_P (REGNO) || ((REGNO) == AP_REG))
 
 #define FP_REGISTER_P(REGNO) \
-  ((REGNO) >= FIRST_FP_REG && (REGNO) <= LAST_FP_REG)
+  ((int) (REGNO) >= FIRST_FP_REG && (int) (REGNO) <= LAST_FP_REG)
 
 #define XD_REGISTER_P(REGNO) \
-  ((REGNO) >= FIRST_XD_REG && (REGNO) <= LAST_XD_REG)
+  ((int) (REGNO) >= FIRST_XD_REG && (int) (REGNO) <= LAST_XD_REG)
 
 #define FP_OR_XD_REGISTER_P(REGNO) \
   (FP_REGISTER_P (REGNO) || XD_REGISTER_P (REGNO))
@@ -838,7 +847,7 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
    || (REGNO) == MACH_REG || (REGNO) == MACL_REG)
 
 #define TARGET_REGISTER_P(REGNO) \
-  ((REGNO) >= FIRST_TARGET_REG && (REGNO) <= LAST_TARGET_REG)
+  ((int) (REGNO) >= FIRST_TARGET_REG && (int) (REGNO) <= LAST_TARGET_REG)
 
 #define SHMEDIA_REGISTER_P(REGNO) \
   (GENERAL_REGISTER_P (REGNO) || FP_REGISTER_P (REGNO) \
@@ -951,7 +960,8 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
   (TARGET_SHMEDIA32 \
    && GET_MODE_SIZE (MODE) > 4 \
    && (((REGNO) >= FIRST_GENERAL_REG + 10 \
-        && (REGNO) <= FIRST_GENERAL_REG + 14) \
+        && (REGNO) <= FIRST_GENERAL_REG + 15) \
+       || TARGET_REGISTER_P (REGNO) \
        || (REGNO) == PR_MEDIA_REG))
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
@@ -1137,7 +1147,7 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
        ? (unsigned HOST_WIDE_INT) int_size_in_bytes (TYPE) \
        : GET_MODE_SIZE (TYPE_MODE (TYPE))) > 8) \
    : (TYPE_MODE (TYPE) == BLKmode \
-      || TARGET_HITACHI && TREE_CODE (TYPE) == RECORD_TYPE))
+      || (TARGET_HITACHI && TREE_CODE (TYPE) == RECORD_TYPE)))
 
 /* Don't default to pcc-struct-return, because we have already specified
    exactly how to return structures in the RETURN_IN_MEMORY macro.  */
@@ -1273,7 +1283,7 @@ enum reg_class
    reg number REGNO.  This could be a conditional expression
    or could index an array.  */
 
-extern int regno_reg_class[FIRST_PSEUDO_REGISTER];
+extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
 #define REGNO_REG_CLASS(REGNO) regno_reg_class[(REGNO)]
 
 /* When defined, the compiler allows registers explicitly used in the
@@ -1363,7 +1373,9 @@ extern enum reg_class reg_class_from_letter[];
 #define CONSTRAINT_LEN(C,STR) \
   (((C) == 'L' || (C) == 'O' || (C) == 'D' || (C) == 'T' || (C) == 'U' \
     || (C) == 'Y' \
-    || ((C) == 'I' && (((STR)[1] != '0' && (STR)[1] != '1') || ! isdigit ((STR)[2]))) \
+    || ((C) == 'I' \
+        && (((STR)[1] != '0' && (STR)[1] != '1') \
+           || (STR)[2] < '0' || (STR)[2] > '9')) \
     || ((C) == 'B' && ((STR)[1] != 's' || (STR)[2] != 'c')) \
     || ((C) == 'J' && ((STR)[1] != '1' || (STR)[2] != '6')) \
     || ((C) == 'K' && ((STR)[1] != '0' || (STR)[2] != '8')) \
@@ -1667,12 +1679,15 @@ extern enum reg_class reg_class_from_letter[];
    || (TARGET_SHMEDIA_FPU && (REGNO) == FIRST_FP_RET_REG))
 
 /* 1 if N is a possible register number for function argument passing.  */
+/* ??? There are some callers that pass REGNO as int, and others that pass
+   it as unsigned.  We get warnings unless we do casts everywhere.  */
 #define FUNCTION_ARG_REGNO_P(REGNO) \
-  (((REGNO) >= FIRST_PARM_REG && (REGNO) < (FIRST_PARM_REG             \
-                                           + NPARM_REGS (SImode)))     \
+  (((unsigned) (REGNO) >= (unsigned) FIRST_PARM_REG                    \
+    && (unsigned) (REGNO) < (unsigned) (FIRST_PARM_REG + NPARM_REGS (SImode)))\
    || (TARGET_FPU_ANY                                                   \
-       && (REGNO) >= FIRST_FP_PARM_REG && (REGNO) < (FIRST_FP_PARM_REG \
-                                                    + NPARM_REGS (SFmode))))
+       && (unsigned) (REGNO) >= (unsigned) FIRST_FP_PARM_REG           \
+       && (unsigned) (REGNO) < (unsigned) (FIRST_FP_PARM_REG           \
+                                          + NPARM_REGS (SFmode))))
 \f
 /* Define a data type for recording info about an argument list
    during the scan of that argument list.  This data type should
@@ -2057,13 +2072,13 @@ struct sh_args {
             (VOIDmode,                                                 \
              gen_rtx_REG (SFmode,                                      \
                           BASE_ARG_REG (MODE)                          \
-                          + ROUND_REG ((CUM), (MODE)) ^ 1),            \
+                          + (ROUND_REG ((CUM), (MODE)) ^ 1)),          \
              const0_rtx)),                                             \
            (gen_rtx_EXPR_LIST                                          \
             (VOIDmode,                                                 \
              gen_rtx_REG (SFmode,                                      \
                           BASE_ARG_REG (MODE)                          \
-                          + (ROUND_REG ((CUM), (MODE)) + 1) ^ 1),      \
+                          + ((ROUND_REG ((CUM), (MODE)) + 1) ^ 1)),    \
              GEN_INT (4)))))))                                         \
       : gen_rtx_REG ((MODE),                                           \
                     ((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \
@@ -2311,9 +2326,7 @@ while (0)
    can ignore COUNT.  */
 
 #define RETURN_ADDR_RTX(COUNT, FRAME)  \
-  (((COUNT) == 0)                              \
-   ? get_hard_reg_initial_val (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG) \
-   : (rtx) 0)
+  (((COUNT) == 0) ? sh_get_pr_initial_val () : (rtx) 0)
 
 /* A C expression whose value is RTL representing the location of the
    incoming return address at the beginning of any function, before the
@@ -2322,6 +2335,11 @@ while (0)
    the stack.  */
 #define INCOMING_RETURN_ADDR_RTX \
   gen_rtx_REG (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG)
+
+/* libstdc++-v3/libsupc++/eh_personality.cc:__gxx_personality_v0
+   can get confused by SHmedia return addresses when it does:
+   ip = _Unwind_GetIP (context) - 1;  */
+#define RETURN_ADDR_OFFSET (TARGET_SH5 ? -1 : 0)
 \f
 /* Generate necessary RTL for __builtin_saveregs().  */
 #define EXPAND_BUILTIN_SAVEREGS() sh_builtin_saveregs ()
@@ -3085,18 +3103,18 @@ while (0)
 
 #define SH_DBX_REGISTER_NUMBER(REGNO) \
   (GENERAL_REGISTER_P (REGNO) \
-   ? ((REGNO) - FIRST_GENERAL_REG) \
+   ? ((unsigned) (REGNO) - FIRST_GENERAL_REG) \
    : FP_REGISTER_P (REGNO) \
-   ? ((REGNO) - FIRST_FP_REG + (TARGET_SH5 ? (TARGET_SHCOMPACT ? 245 \
-                                             : 77) : 25)) \
+   ? ((unsigned) (REGNO) - FIRST_FP_REG \
+      + (TARGET_SH5 ? (TARGET_SHCOMPACT ? 245 : 77) : 25)) \
    : XD_REGISTER_P (REGNO) \
-   ? ((REGNO) - FIRST_XD_REG + (TARGET_SH5 ? 289 : 87)) \
+   ? ((unsigned) (REGNO) - FIRST_XD_REG + (TARGET_SH5 ? 289 : 87)) \
    : TARGET_REGISTER_P (REGNO) \
-   ? ((REGNO) - FIRST_TARGET_REG + 68) \
+   ? ((unsigned) (REGNO) - FIRST_TARGET_REG + 68) \
    : (REGNO) == PR_REG \
    ? (TARGET_SH5 ? 241 : 17) \
    : (REGNO) == PR_MEDIA_REG \
-   ? (TARGET_SH5 ? 18 : -1) \
+   ? (TARGET_SH5 ? 18 : (unsigned) -1) \
    : (REGNO) == T_REG \
    ? (TARGET_SH5 ? 242 : 18) \
    : (REGNO) == GBR_REG \
@@ -3107,7 +3125,7 @@ while (0)
    ? (TARGET_SH5 ? 240 : 21) \
    : (REGNO) == FPUL_REG \
    ? (TARGET_SH5 ? 244 : 23) \
-   : -1)
+   : (unsigned) -1)
 
 /* This is how to output a reference to a symbol_ref.  On SH5,
    references to non-code symbols must be preceded by `datalabel'.  */
@@ -3449,9 +3467,10 @@ extern int rtx_equal_function_value_matters;
   (TARGET_SH5 ? DWARF_FRAME_REGNUM (PR_MEDIA_REG) : DWARF_FRAME_REGNUM (PR_REG))
 
 #define EH_RETURN_DATA_REGNO(N)        \
-  ((N) < 4 ? (N) + (TARGET_SH5 ? 2 : 4) : INVALID_REGNUM)
+  ((N) < 4 ? (N) + (TARGET_SH5 ? 2U : 4U) : INVALID_REGNUM)
 
-#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM)
+#define EH_RETURN_STACKADJ_REGNO STATIC_CHAIN_REGNUM
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, EH_RETURN_STACKADJ_REGNO)
 
 #if (defined CRT_BEGIN || defined CRT_END) && ! __SHMEDIA__
 /* SH constant pool breaks the devices in crtstuff.c to control section
index 2af568b..8e012d7 100644 (file)
 "
 {
   enum machine_mode inmode = GET_MODE (operands[1]);
-  int regno, offset = 0;
+  int offset = 0;
 
   if (GET_CODE (operands[0]) == SUBREG)
     {
@@ -7247,6 +7247,8 @@ mov.l\\t1f,r0\\n\\
     {
       rtx r18 = gen_rtx_REG (DImode, PR_MEDIA_REG);
 
+      if (! call_used_regs[TR0_REG] || fixed_regs[TR0_REG])
+       abort ();
       tr_regno = TR0_REG;
       tr = gen_rtx_REG (DImode, tr_regno);
       emit_move_insn (tr, r18);