OSDN Git Service

Major rework.
authorsac <sac@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 29 Jun 1993 00:10:35 +0000 (00:10 +0000)
committersac <sac@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 29 Jun 1993 00:10:35 +0000 (00:10 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@4792 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md
gcc/config/sh/t-sh
gcc/config/sh/xm-sh.h

index 6b3ec01..ca8f8f0 100644 (file)
@@ -39,10 +39,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
 static int add_constant ();
-static int dump_constants ();
+int dump_constants ();
 
 int current_function_anonymous_args;
 extern int current_function_pretend_args_size;
+extern char *version_string;
+extern int flag_traditional;
+
+
+enum attr_cpu sh_cpu;          /* target cpu */
 
 /* Global variables for machine-dependent things. */
 
@@ -80,6 +85,8 @@ enum reg_class reg_class_from_letter[] =
 };
 
 
+
+
 /* Local label counter, used for constants in the pool and inside
    pattern branches.  */
 
@@ -92,197 +99,83 @@ static int pc;
 #define MUST_DUMP_LEVEL 1000
 static int dumpnext;
 \f
-/* Functions for generating procedure prologue and epilogue code */
 
-/* Adjust the stack and return the number of bytes taken to do it */
-
-static int
-output_stack_adjust (file, direction, size)
-     FILE *file;
-     int direction;
-     int size;
+void
+push (rn)
 {
-  int code_size;
-
-  if (size > 127)
-    {
-      fprintf (file, "\tmov.l  LK%d,r13\n",
-              add_constant (GEN_INT (size * direction), SImode));
-
-      fprintf (file, "\tadd    r13,r15\n");
-      code_size += 4;
-    }
-  else if (size)
-    {
-      fprintf (file, "\tadd    #%d,r15\n", direction * size);
-      code_size += 2;
-    }
-  return code_size;
+  emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
 }
 
-/* Generate code to push the regs specified in the mask, and return
-   the number of bytes the insns take. */
-
-static int
-push_regs (f, mask)
-     FILE *f;
-     int mask;
+void
+pop (rn)
 {
-  int i;
-  int size = 0;
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      if (mask & (1 << i))
-       {
-         fprintf (f, "\tmov.l  r%d,@-r15\n", i);
-         size += 2;
-       }
-    }
-  return size;
+  emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
 }
 
 
-/* Working out the right code to use for an epilogue can get quite
-   hairy, since there are only certain insns which can go in the delay
-   slot, and there may or may not be a delay insn provided already.
-
-   We generate a canonical list of the instructions to use to perform
-   the exit, massage that and output from that list */
-
-
-/* The structure of a canonical element. */
+/* Adjust the stack and return the number of bytes taken to do it */
 
-typedef struct
+static void
+output_stack_adjust (direction, size)
+     int direction;
+     int size;
 {
-  enum epi_type
+  if (size)
     {
-      STACK_ADJUST,            /* add i to stack pointer       */
-      POP,                     /* pop into register i          */
-      RTS,                     /* rts instruction              */
-      DELAY,                   /* delay slot instruction       */
-      NOP,                     /* a nop                        */
-      DELETED,
-    } type;
-  int i;
-}
+      rtx val = GEN_INT (size);
+      rtx insn;
 
-epilogue_insn;
+      if (size > 120)
+       {
+         rtx nval = gen_rtx (REG, SImode, 13);
+         emit_insn (gen_movsi (nval, val));
+         val = nval;
+       }
 
-static epilogue_insn epilogue_vec[20];
-static int epilogue_vec_len;
+      if (direction > 0)
+       insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val);
+      else
+       insn = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, val);
 
-static void
-set_epilogue_insn (type, l)
-     enum epi_type type;
-     int l;
-{
-  epilogue_vec[epilogue_vec_len].type = type;
-  epilogue_vec[epilogue_vec_len].i = l;
-  epilogue_vec_len++;
+      emit_insn (insn);
+    }
 }
 
-/* Delete an insn from the epilogue list. */
 
-static void
-delete_epilogue_insn (n)
-     int n;
-{
-  int j;
-
-  for (j = n; j < epilogue_vec_len; j++)
-    epilogue_vec[j] = epilogue_vec[j + 1];
-
-  epilogue_vec_len--;
-}
 
-/* Run through the epilogue list and optimize it. */
+/* Generate code to push the regs specified in the mask, and return
+   the number of bytes the insns take. */
 
 static void
-optimize_epilogue_vec ()
+push_regs (mask)
+     int mask;
 {
   int i;
+  int size = 0;
 
-  /* Turn two adds in a row into one add and kill empty adds */
-  for (i = 0; i < epilogue_vec_len - 1; i++)
-    {
-      if (epilogue_vec[i].type == STACK_ADJUST
-         && epilogue_vec[i + 1].type == STACK_ADJUST)
-       {
-         epilogue_vec[i].i += epilogue_vec[i + 1].i;
-         delete_epilogue_insn (i + 1);
-       }
-      if (epilogue_vec[i].type == STACK_ADJUST
-         && epilogue_vec[i].i == 0)
-       delete_epilogue_insn (i);
-    }
-
-  /* If the instruction after the RTS is a nop, see if it can be
-     changed */
-
-  for (i = 1; i < epilogue_vec_len - 1; i++)
-    {
-      if (epilogue_vec[i].type == RTS
-         && epilogue_vec[i + 1].type == NOP)
-       {
-         epilogue_vec[i + 1] = epilogue_vec[i - 1];
-         delete_epilogue_insn (i - 1);
-       }
-    }
-
-  /* Delete all the instructions after the rts's delay slot */
-  for (i = 0; i < epilogue_vec_len; i++)
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      if (epilogue_vec[i].type == RTS)
+      if (mask & (1 << i))
        {
-         int j;
-
-         for (j = i + 2; j < epilogue_vec_len; j++)
-           epilogue_vec[j].type = DELETED;
-         return;
+         push (i);
        }
     }
 }
 
-/* Dump out the insns in epilogue vector. */
-
-static void
-output_epilogue_vec ()
-{
-  int i;
-
-  for (i = 0; i < epilogue_vec_len; i++)
-    {
-      switch (epilogue_vec[i].type)
-       {
-       case STACK_ADJUST:
-         fprintf (asm_out_file, "\tadd #%d,r15\n", epilogue_vec[i].i);
-         break;
-
-       case NOP:
-         fprintf (asm_out_file, "\tor  r0,r0\n");
-         break;
-
-       case DELAY:
-         final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
-                          asm_out_file, 1, 0, 1);
-         break;
 
-       case DELETED:
-         fprintf (asm_out_file, "\t!delete_epilogue_insnd\n");
-         break;
+/*
+  Print an instruction which would have gone into a delay slot
+  after an instructiuon, but couldn't because the instruction expanded
+  into a sequence where putting the slot insn at the end wouldn't work.
+  */
 
-       case RTS:
-         fprintf (asm_out_file, "\trts\n");
-         break;
+void
+print_slot (insn)
+     rtx insn;
+{
+  final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 0, 1);
 
-       case POP:
-         fprintf (asm_out_file, "\tmov.l       @r15+,r%d\n",
-                  epilogue_vec[i].i);
-         break;
-       }
-    }
-  epilogue_vec_len = 0;
+  INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
 }
 
 /* Number of bytes pushed for anonymous args */
@@ -310,162 +203,17 @@ calc_live_regs (count)
     }
   return live_regs_mask;
 }
-
-/* Generate a procedure prologue.  */
-
-void
-output_prologue (f, frame_size)
-     FILE *f;
-     int frame_size;
-{
-  int live_regs_mask;
-  int d;
-
-  pc = 0;
-
-  /* This only happens when an arg has been split, part in
-     registers, part in memory.  Allocate the stack space so there is
-     somewhere to put the value */
-
-  output_stack_adjust (f, -1, current_function_pretend_args_size);
-
-  live_regs_mask = calc_live_regs (&d);
-
-  extra_push = 0;
-
-  if (current_function_anonymous_args)
-    {
-      /* Push arg regs as if they'd been provided by caller in stack */
-      int i;
-      for (i = 0; i < NPARM_REGS; i++)
-       {
-         int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
-         if (i > NPARM_REGS - current_function_args_info)
-           break;
-         fprintf (f, "\tmov.l  r%d,@-r15\n", rn);
-         extra_push += 4;
-         pc += 2;
-       }
-    }
-
-  if (frame_pointer_needed)
-    {
-      /* Don't need to push the fp with the rest of the registers. */
-      live_regs_mask &= ~(1 << FRAME_POINTER_REGNUM);
-      pc += push_regs (f, live_regs_mask);
-      if (regs_ever_live[PR_REG])
-       {
-
-         fprintf (f, "\tsts.l  pr,@-r15\n");
-         pc += 2;
-       }
-
-      fprintf (f, "\tmov.l     r14,@-r15\n");
-      fprintf (f, "\tmov       r15,r14\n");
-      pc += 4;
-      pc += output_stack_adjust (f, -1, frame_size);
-    }
-  else
-    {
-      pc += push_regs (f, live_regs_mask);
-
-      if (regs_ever_live[PR_REG])
-       {
-
-         fprintf (f, "\tsts.l  pr,@-r15\n");
-         pc += 2;
-       }
-      pc += output_stack_adjust (f, -1, frame_size);
-    }
-}
+\f
 
 
-/* Generate a procedure epilogue. */
 
-void
-output_epilogue (f, frame_size)
-     FILE *f;
-     int frame_size;
+static int
+need_slot (insn)
+     rtx insn;
 {
-  int live_regs_mask = 0;
-  int d;
-  int i;
-  rtx delay_insn;
-  
-  live_regs_mask = calc_live_regs (&d);
-
-
-  /* See if the delay insn is really ok for the slot. */
-  if (current_function_epilogue_delay_list) {
-    delay_insn = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
-
-  if (GET_CODE (delay_insn) == SET
-      && SET_DEST (delay_insn) == stack_pointer_rtx)
-    {
-      /* Can not use this instruction in the delay slot because
-        it changes the stack pointer, so emit it now.  */
-      final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
-                      asm_out_file, 1, 0, 1);
-      current_function_epilogue_delay_list = 0;
-    }
-  }
-  
-
-  /* Reclaim the room for the automatics. */
-
-  output_stack_adjust (f, 1, frame_size);
-
-  /* Make the frame pointer. */
-
-  if (frame_pointer_needed)
-    {
-      fprintf (f, "\tmov       r14,r15\n");
-      fprintf (f, "\tmov.l     @r15+,r14\n");
-      live_regs_mask &= ~(1 << FRAME_POINTER_REGNUM);
-    }
-
-  /* Get the PR register if it was clobbered in the function. */
-
-  if (regs_ever_live[PR_REG])
-    fprintf (f, "\tlds.l       @r15+,pr\n");
-
-  /* Pop all the registers */
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      int j = (FIRST_PSEUDO_REGISTER - 1) - i;
-      if (live_regs_mask & (1 << j))
-       {
-         set_epilogue_insn (POP, j);
-       }
-    }
-
-  /* Need to adjust the stack by some amount of bytes since we've pushed
-     some of the args which normally come in registers */
-
-  set_epilogue_insn (STACK_ADJUST, extra_push);
-
-  /* Need to adjust the stack by some amount of bytes if there
-     an arg has been split part register and part stack */
-
-  set_epilogue_insn (STACK_ADJUST, current_function_pretend_args_size);
-
-  set_epilogue_insn (RTS, 0);
-
-  /* Got here without dumping a register pop into the delay slot */
-  if (current_function_epilogue_delay_list)
-    {
-      set_epilogue_insn (DELAY, 0);
-    }
-  set_epilogue_insn (NOP, 0);
-
-  optimize_epilogue_vec ();
-
-  output_epilogue_vec ();
-
-  dump_constants (0);
-  current_function_anonymous_args = 0;
+  return (insn && !INSN_ANNULLED_BRANCH_P (XVECEXP (insn, 0, 0)));
 }
-\f
+
 /* Print the operand address in x to the stream */
 
 void
@@ -478,7 +226,6 @@ print_operand_address (stream, x)
     case REG:
       fprintf (stream, "@%s", reg_names[REGNO (x)]);
       break;
-
     case PLUS:
       {
        rtx base = XEXP (x, 0);
@@ -501,12 +248,14 @@ print_operand_address (stream, x)
            break;
 
          case REG:
-           fprintf (stream, "@(%s,%s)",
-                    reg_names[REGNO (base)],
-                    reg_names[REGNO (index)]);
+           fprintf (stream, "@(r0,%s)",
+                    reg_names[MAX (REGNO (base), REGNO (index))]);
+
            break;
 
          default:
+           debug_rtx (x);
+
            abort ();
          }
       }
@@ -529,13 +278,16 @@ print_operand_address (stream, x)
 /* Print operand x (an rtx) in assembler syntax to file stream
    according to modifier code.
 
- '*'  print a local label
- '^'  increment the local label number
- '!'  dump the constant table
- '#'  output a nop if there is nothing to put in the delay slot
- 'R'  print the next register or memory location along, ie the lsw in
-      a double word value
- 'I'  put something into the constant pool and print its label */
+   '.'  print a .s if insn needs delay slot
+   '*'  print a local label
+   '^'  increment the local label number
+   '!'  dump the constant table
+   '#'  output a nop if there is nothing to put in the delay slot
+   'R'  print the next register or memory location along, ie the lsw in
+   a double word value
+   'O'  print a constant without the #
+   'M'  print a constant as its negative
+   'I'  put something into the constant pool and print its label */
 
 void
 print_operand (stream, x, code)
@@ -545,6 +297,12 @@ print_operand (stream, x, code)
 {
   switch (code)
     {
+
+
+    case '.':
+      if (need_slot (final_sequence))
+       fprintf (stream, ".s");
+      break;
     case '*':
       fprintf (stream, "LF%d", lf);
       break;
@@ -562,11 +320,18 @@ print_operand (stream, x, code)
          fprintf (stream, "\n\tor      r0,r0\t!wasted slot");
        }
       break;
+    case 'O':
+      fprintf (asm_out_file, "%d", INTVAL (x));
+      break;
 
     case 'I':
       fprintf (asm_out_file, "LK%d", add_constant (x, SImode));
       break;
 
+    case 'M':
+      fprintf (asm_out_file, "#%d", -INTVAL (x));
+      break;
+
     case 'R':
       /* Next location along in memory or register*/
       switch (GET_CODE (x))
@@ -599,10 +364,10 @@ print_operand (stream, x, code)
       break;
     }
 }
-
 \f
 
-/* Define the offset between two registers, one to be eliminated, and 
+
+/* Define the offset between two registers, one to be eliminated, and
    the other its replacement, at the start of a routine.  */
 
 int
@@ -610,7 +375,7 @@ initial_elimination_offset (from, to)
 {
   int regs_saved;
   int d = calc_live_regs (&regs_saved);
-  int total_saved_regs_space = (regs_saved + regs_ever_live[PR_REG]) * 4;
+  int total_saved_regs_space = (regs_saved) * 4;
   int total_auto_space = get_frame_size ();
 
 
@@ -630,22 +395,12 @@ initial_elimination_offset (from, to)
     }
 }
 
-delay_slots_for_epilogue ()
-{
-  /* We need to find something to fill the epilogue if there won't be
-     any instructions to make the stack or pop registers which can be
-     moved into the slot */
-
-  int d;
-  calc_live_regs (&d);
-  return !(get_frame_size () + d);
-}
-\f
 
 /* Prepare operands for a move define_expand; specifically, one of the
-   operands must be in a register */
+   operands must be in a register.  Take this chance to remove
+   addressing modes which can't be coped with very well. */
 
-void
+int
 prepare_move_operands (operands, mode)
      rtx operands[];
      enum machine_mode mode;
@@ -653,11 +408,33 @@ prepare_move_operands (operands, mode)
   /* One of the operands has to be a register */
   if ((!register_operand (operands[0], mode)
        && !register_operand (operands[1], mode))
-      || GET_CODE(operands[1]) == PLUS)
+      || GET_CODE (operands[1]) == PLUS)
     {
       /* copy the source to a register */
       operands[1] = copy_to_mode_reg (mode, operands[1]);
     }
+
+  /* If we've got a negative index, break it down */
+
+  if (GET_CODE (operands[0]) == MEM && !reload_in_progress)
+    {
+
+      rtx inside = XEXP (operands[0], 0);
+      if (GET_CODE (inside) == PLUS)
+       {
+         rtx inside1 = XEXP (inside, 1);
+         if (GET_CODE (inside1) == CONST_INT
+             && INTVAL (inside1) < 0)
+           {
+             /* Catch this now and break it into bits, it will only cause
+                problems later */
+
+             rtx sub = copy_to_mode_reg (SImode, inside);
+             XEXP (operands[0], 0) = sub;
+           }
+       }
+    }
+  return 0;
 }
 
 
@@ -666,93 +443,164 @@ prepare_move_operands (operands, mode)
 rtx
 prepare_scc_operands (code)
 {
-  if (GET_CODE(sh_compare_op0) != REG 
-      || REGNO(sh_compare_op0) != T_REG)
+  if (GET_CODE (sh_compare_op0) != REG
+      || REGNO (sh_compare_op0) != T_REG)
     {
       /* First need a compare insn */
-      emit_insn (gen_rtx (SET, SImode, 
+      emit_insn (gen_rtx (SET, SImode,
                          gen_rtx (REG, SImode, T_REG),
                          gen_rtx (code, SImode, sh_compare_op0,
                                   sh_compare_op1)));
     }
-  return gen_rtx(REG, SImode, T_REG);
+  return gen_rtx (REG, SImode, T_REG);
 }
 \f
+
 /* Functions to output assembly */
 
-/* Return a sequence of instructions to perform DI move, taking into
-   account overlapping source and dest registers */
+/* Return a sequence of instructions to perform DI or DF move.
 
+   Since the SH cannot move a DI or DF in one instruction, we have
+   to take care when we see overlapping source and dest registers.
+
+ */
 char *
 output_movedouble (operands, mode)
      rtx operands[];
      enum machine_mode mode;
 {
-  if (register_operand (operands[0], mode)
-      && register_operand (operands[1], mode))
+  rtx dst = operands[0];
+  rtx src = operands[1];
+  int lowfirst;
+
+  if (register_operand (dst, mode)
+      && register_operand (src, mode))
     {
-      if (REGNO (operands[1]) == MACH_REG)
+      if (REGNO (src) == MACH_REG)
        return "sts     mach,%0\n\tsts  macl,%R0";
-      if (REGNO (operands[1]) > REGNO (operands[0])) 
-       {
-         return "mov   %1,%0\n\tmov    %R1,%R0";
-       }
-      else 
-       {
-         return "mov   %R1,%R0\n\tmov  %1,%0";
-       }
-    }
 
-  if (GET_CODE (operands[1]) == CONST_INT)
+      /*
+       when mov.d r1,r2 do r2->r3 then r1->r2
+       when mov.d r1,r0 do r1->r0 then r2->r1
+       */
+
+      if (REGNO (src) + 1 == REGNO (dst))
+       return "mov     %1,%0\n\tmov    %R1,%R0 ! cr";
+      else
+       return "mov     %R1,%R0\n\tmov  %1,%0 ";
+
+    }
+  else if (GET_CODE (src) == CONST_INT)
     {
-      if (INTVAL (operands[1]) < 0)
+      if (INTVAL (src) < 0)
        return "mov     #-1,%0\n\tmov   %1,%R0";
       else
        return "mov     #0,%0\n\tmov    %1,%R0";
     }
 
-  if (GET_CODE (operands[1]) == MEM)
+  else if (GET_CODE (src) == MEM)
     {
-      int idxreg = -1;
-      rtx inside = XEXP (operands[1], 0);
+      int ptrreg1 = -1;
+      int ptrreg2 = -1;
+      int dreg = REGNO (dst);
+      rtx inside = XEXP (src, 0);
 
       if (GET_CODE (inside) == REG)
-       idxreg = REGNO (inside);
+       {
+         ptrreg1 = REGNO (inside);
+       }
       else if (GET_CODE (inside) == PLUS)
        {
          rtx lhs = XEXP (inside, 0);
          rtx rhs = XEXP (inside, 1);
          if (GET_CODE (lhs) == REG)
-           idxreg = REGNO (lhs);
-         else if (GET_CODE (rhs) == REG)
-           idxreg = REGNO (rhs);
-         else
-           abort ();
+           ptrreg1 = REGNO (lhs);
+         if (GET_CODE (rhs) == REG)
+           ptrreg2 = REGNO (rhs);
        }
       else
        abort ();
 
-      if (REGNO (operands[0]) != idxreg)
+
+      if ((ptrreg1 >= 0 && ptrreg2 >= 0)
+         && (dreg == ptrreg1
+             || dreg == ptrreg2
+             || dreg + 1 == ptrreg1
+             || dreg + 1 == ptrreg2))
+       {
+         /* This move clobbers both index registers,
+            calculate the sum in one register.  */
+         fprintf (asm_out_file, "      add     %s,%s ! special fix\n",
+                  reg_names[ptrreg2], reg_names[ptrreg1]);
+
+         if (dreg == ptrreg1)
+           {
+             /* Copy into dreg+1 first.  */
+             fprintf (asm_out_file, "  mov.l   @(4,%s),%s\n",
+                      reg_names[ptrreg1],
+                      reg_names[dreg + 1]);
+
+             fprintf (asm_out_file, "  mov.l   @(%s),%s\n",
+                      reg_names[ptrreg1],
+                      reg_names[dreg]);
+           }
+         else
+           {
+             /* Copy into dreg first. */
+             fprintf (asm_out_file, "  mov.l   @(%s),%s\n",
+                      reg_names[ptrreg1],
+                      reg_names[dreg]);
+
+             fprintf (asm_out_file, "  mov.l   @(4,%s),%s\n",
+                      reg_names[ptrreg1],
+                      reg_names[dreg + 1]);
+
+           }
+         warning ("generated complex amode");
+         return "";
+       }
+
+      /* Work out the safe way to copy */
+      if (dreg == ptrreg1)
        {
-         /* The dest register is mentioned in the addressing mode,
-            so print them the other way around */
-         return "mov.l %1,%0\n\tmov.l  %R1,%R0 ! one way";
+         /* Copy into the second half first */
+         return "mov.l %R1,%R0\n\tmov.l        %1,%0 ! cr";
        }
-      return "mov.l    %R1,%R0\n\tmov.l        %1,%0 ! other way";
     }
 
-  return "mov.l        %R1,%R0\n\tmov.l        %1,%0";
+  return "mov.l        %1,%0\n\tmov.l  %R1,%R0";
 }
 
 /* Emit assembly to shift reg by k bits */
 
 char *
-output_shift (string, reg, k)
+output_shift (string, reg, k, code)
      char *string;
      rtx reg;
      rtx k;
+     int code;
+
 {
   int s = INTVAL (k);
+
+  if (code == ASHIFT && s == 31)
+    {
+      /* Shift left by 31 moving into the t bit, clearing and rotating the other way */
+
+      fprintf (asm_out_file, "\trotr   r%d\n", REGNO (reg));
+      fprintf (asm_out_file, "\tmov    #0,r%d\n", REGNO (reg));
+      fprintf (asm_out_file, "\trotcr  r%d\n", REGNO (reg));
+      s = 0;
+    }
+
+  if (code == LSHIFTRT && s == 31)
+    {
+      fprintf (asm_out_file, "\trotl   r%d\n", REGNO (reg));
+      fprintf (asm_out_file, "\tmov    #0,r%d\n", REGNO (reg));
+      fprintf (asm_out_file, "\trotcl  r%d\n", REGNO (reg));
+      s = 0;
+    }
+
   while (s)
     {
       char *out;
@@ -785,51 +633,171 @@ output_shift (string, reg, k)
 }
 
 /* Return the text of the branch instruction which matches its length
-   attribute.  */
+   attribute.
+
+   This gets tricky if we have an insn in the delay slot of a branch
+   and the branch needs more than 1 insn to complete.*/
+
+
 
 char *
 output_branch (logic, insn)
      int logic;
-     rtx *insn;
+     rtx insn;
 {
   extern rtx recog_operand[];
   int label = lf++;
-  
+  int rn = -1;
+  int need_save;
+
   switch (get_attr_length (insn))
     {
     case 2:
       /* Simple branch in range -200..+200 bytes */
-      return logic ? "bt       %l0" : "bf      %l0";
+      return logic ? "bt%.     %l0" : "bf%.    %l0";
 
     case 6:
       /* Branch in range -4000..+4000 bytes */
-      fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
-      output_asm_insn ("bra    %l0     ! 12 bit cond ", recog_operand);
-      fprintf (asm_out_file, "\tor     r0,r0\n");
-      label = dump_constants (label);
-      fprintf (asm_out_file, "LF%d:\n", label);
+      {
+       rtx oldop = recog_operand[0];
+
+
+       if (need_slot (final_sequence))
+         {
+           fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't',
+                    label);
+
+           print_slot (final_sequence);
+         }
+
+       else
+         {
+           fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't',
+                    label);
+         }
+       recog_operand[0] = oldop;
+
+       output_asm_insn ("bra   %l0     ! 12 bit cond ", recog_operand);
+       fprintf (asm_out_file, "\tor    r0,r0\n");
+       label = dump_constants (label);
+       fprintf (asm_out_file, "LF%d:\n", label);
+      }
+
       return "";
 
     case 8:
       /* Branches a long way away */
-       
-      fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
-      output_asm_insn ("mov.l  %I0,r13", recog_operand);
-      fprintf (asm_out_file, "\tjmp    @r13    ! 32 cond \n");
-      fprintf (asm_out_file, "\tor     r0,r0\n");
-      fprintf (asm_out_file, "LF%d:\n", label);
-      return "";
+      {
+
+       rtx oldop = recog_operand[0];
+
+       if (need_slot (final_sequence))
+         {
+           fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't', label);
+           print_slot (final_sequence);
+
+         }
+       else
+         {
+           fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
+         }
+
+       recog_operand[0] = oldop;
+
+       /* We use r13 as a scratch */
+       need_save = 0;
+       rn = 13;
+
+       if (need_save)
+         fprintf (asm_out_file, "\tpush  r%d\n", rn);
+       fprintf (asm_out_file, "\tmov.l LK%d,r%d\n", add_constant (oldop, SImode), rn);
+       fprintf (asm_out_file, "\tjmp   @r%d    ! 32 cond \n", rn);
+       if (need_save)
+         fprintf (asm_out_file, "\tpop  r%d\n", rn);
+       else
+         fprintf (asm_out_file, "\tor  r0,r0\n");
+       fprintf (asm_out_file, "LF%d:\n", label);
+       return "";
+      }
     }
   return "bad";
-
 }
 \f
+
 /* Predicates used by the templates */
 
+/* Non zero if op is an immediate ok for a byte index */
+
+int 
+byte_index_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return (GET_CODE (op) == CONST_INT
+         && INTVAL (op) >= 0 && INTVAL (op) <= 15);
+}
+
+/* Non zero if OP is a pop operand */
+
+int
+pop_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) != MEM)
+    return 0;
+
+  if (GET_MODE (op) != mode)
+    return 0;
+
+  op = XEXP (op, 0);
+
+  if (GET_CODE (op) != POST_INC)
+    return 0;
+
+  return XEXP (op, 0) == stack_pointer_rtx;
+}
+
+/* Non zero if OP is an immediate which can be made from two insns. */
+
+int
+painful_immediate_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) == CONST_INT)
+    {
+      int i = INTVAL (op);
+
+      if (i > 127 && i < 255)
+       return 1;               /* two adds */
+    }
+  return 0;
+}
+
+
+/* Non zero if OP can be source of a simple move operation. */
+
+int
+general_movsrc_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) == REG
+      || GET_CODE (op) == SUBREG
+      || (GET_CODE (op) == CONST_INT &&
+         CONST_OK_FOR_I (INTVAL (op)))
+      || GET_CODE (op) == MEM)
+    return general_operand (op, mode);
+  return 0;
+}
+
+
+
 /* Nonzero if OP is a normal arithmetic register. */
 
 int
-arith_reg_operand(op, mode)
+arith_reg_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
@@ -842,7 +810,7 @@ arith_reg_operand(op, mode)
   return 0;
 }
 
-  
+
 /* Nonzero if OP is a valid source operand for an arithmetic insn.  */
 
 int
@@ -897,7 +865,7 @@ ok_shift_value (p)
          return 1;
        default:
          if (TARGET_FASTCODE)
-           return INTVAL(p) >= 0;
+           return INTVAL (p) >= 0;
        }
     }
   return 0;
@@ -1025,7 +993,7 @@ add_constant (x, mode)
       if (rtx_equal_p (x, pool_vector[i].value))
        return pool_vector[i].number;
     }
-  
+
 
   pool_vector[pool_size].value = x;
   pool_vector[pool_size].mode = mode;
@@ -1078,7 +1046,10 @@ int target_insn_smallest_size;
 int target_pc;
 int target_insn_range;
 int current_pc;
-int table_size;
+int pool_bytes;
+
+int last_uid;
+int last_pc;
 
 void
 adjust_insn_length (insn, insn_lengths)
@@ -1086,99 +1057,121 @@ adjust_insn_length (insn, insn_lengths)
      short *insn_lengths;
 {
   int uid = INSN_UID (insn);
+  rtx body = PATTERN (insn);
 
   current_pc += insn_lengths[uid];
 
-  if (has_constant_table (insn)) 
+
+  if (GET_CODE (body) == SEQUENCE)
     {
-      if (current_pc >= target_insn_range)
+      int i;
+
+      for (i = 0; i < XVECLEN (body, 0); i++)
        {
-         /* This instruction is further away from the referencing
-            instruction than it can reach, so we'll stop accumulating
-            from that one and start fresh. */
-         target_pc = current_pc;
-         target_insn_range = current_pc + MAYBE_DUMP_LEVEL;
+         adjust_insn_length (XVECEXP (body, 0, i), insn_lengths);
        }
-      else
+    }
+  else
+    {
+      if (has_constant_table (insn))
        {
-         /* This instruction is within the reach of the target,
-            remove the constant table from the target by adjusting
-            downwards, and increase the size of this one to
-            compensate.  */
+         if (current_pc >= target_insn_range)
+           {
+             /* This instruction is further away from the referencing
+              instruction than it can reach, so we'll stop accumulating
+              from that one and start fresh. */
+             target_pc = current_pc;
+             target_insn_range = current_pc + MAYBE_DUMP_LEVEL;
+           }
+         else
+           {
+             /* This instruction is within the reach of the target,
+              remove the constant table from the target by adjusting
+              downwards, and increase the size of this one to
+              compensate.  */
 
 
-         /* Add the stuff from this insn to what will go in the
-            growing table. */
+             /* Add the stuff from this insn to what will go in the
+              growing table. */
 
-         table_size += get_attr_constantsize (insn);
+             pool_bytes += get_attr_constantsize (insn);
 
-         /* The target shinks to its smallest natural size */
-         insn_lengths[target_insn_uid] = target_insn_smallest_size;
+             /* The target shinks to its smallest natural size */
+             insn_lengths[target_insn_uid] = target_insn_smallest_size;
 
-         /* The current insn grows to be its larger size plust the
-            table size. */
+             /* The current insn grows to be its larger size plust the
+              table size. */
 
-         insn_lengths[uid] = get_attr_largestsize (insn) + table_size;
+             insn_lengths[uid] = get_attr_largestsize (insn) + pool_bytes;
 
-       }
-      /* Current insn becomes the target.  */
-      target_insn_uid = uid;
-      target_insn_smallest_size = get_attr_smallestsize (insn);
+           }
+         /* Current insn becomes the target.  */
+         target_insn_uid = uid;
+         target_insn_smallest_size = get_attr_smallestsize (insn);
 
+       }
     }
-
 }
 
 
-/* Dump out the pending constant pool. 
-   If label provided then insert an branch in the middle of the table 
-  */
 
-static int
+/* Dump out the pending constant pool.
+   If label provided then insert an branch in the middle of the table
+   */
+
+int
 dump_constants (label)
 {
   int i;
   int rlabel = label;
   int size = 0;
-  
-  for (i = 0; i < pool_size; i++)
+
+  if (pool_size)
     {
-      pool_node *p = pool_vector + i;
       fprintf (asm_out_file, "\n\t! constants - waited %d\n", pc - first_pc);
       fprintf (asm_out_file, "\t.align\t2\n");
-      fprintf (asm_out_file, "LK%d:", p->number);
-      size += GET_MODE_SIZE (p->mode);
-      
-      switch (GET_MODE_CLASS (p->mode))
-       {
-       case MODE_INT:
-       case MODE_PARTIAL_INT:
-         assemble_integer (p->value, GET_MODE_SIZE (p->mode), 1);
-         break;
-       case MODE_FLOAT:
-         {
-           union real_extract u;
-           bcopy (&CONST_DOUBLE_LOW (p->value), &u, sizeof u);
-           assemble_real (u.d, p->mode);
-         }
-       }
-      
-      /* After 200 bytes of table, stick in another branch */
-      if (label && size > 200) 
+
+      for (i = 0; i < pool_size; i++)
        {
-         rlabel = lf ++;
-         fprintf (asm_out_file,"LF%d:\tbra     LF%d\n", label, rlabel);
-         fprintf (asm_out_file,"\tor   r0,r0\n");
-         label = 0;
+         pool_node *p = pool_vector + i;
+
+         fprintf (asm_out_file, "LK%d:", p->number);
+         size += GET_MODE_SIZE (p->mode);
+
+         switch (GET_MODE_CLASS (p->mode))
+           {
+           case MODE_INT:
+           case MODE_PARTIAL_INT:
+             assemble_integer (p->value, GET_MODE_SIZE (p->mode), 1);
+             break;
+           case MODE_FLOAT:
+             {
+               union real_extract u;
+               bcopy (&CONST_DOUBLE_LOW (p->value), &u, sizeof u);
+               assemble_real (u.d, p->mode);
+             }
+           }
+
+         /* After 200 bytes of table, stick in another branch */
+         if (label && size > 200)
+           {
+             rlabel = lf++;
+             fprintf (asm_out_file, "LF%d:\tbra        LF%d\n", label, rlabel);
+             fprintf (asm_out_file, "\tor      r0,r0\n");
+             label = 0;
+           }
+
        }
-      
-      fprintf (asm_out_file, "\n");
     }
+
   pool_size = 0;
   current_pc = 0;
+  pc = 0;
+  pool_bytes = 0;
+
   target_insn_range = 0;
   return rlabel;
-  
+
 }
 
 
@@ -1196,17 +1189,27 @@ output_movepcrel (insn, operands, mode)
   fprintf (asm_out_file, "\tmov.l      LK%d,r%d\n",
           add_constant (operands[1], mode), rn);
 
-  if (GET_MODE_SIZE(mode) > 4) 
+  if (GET_MODE_SIZE (mode) > 4)
     {
       fprintf (asm_out_file,
               "\tmov.l LK%d+4,r%d\n",
               add_constant (operands[1], mode),
               rn + 1);
 
-    } 
-  /* If this instruction is as small as it can be, there can be no 
+    }
+
+  /* This may have been the last move in the function, so nothing
+     took its constant table, we may be able to move it past the end
+     of the function (after the rts) if we are careful */
+
+  if (target_insn_uid == INSN_UID (insn)
+      && current_pc < target_insn_range)
+    return "";
+
+
+  /* If this instruction is as small as it can be, there can be no
      constant table attached to it.  */
-  if (get_attr_length (insn) !=  get_attr_smallestsize (insn))
+  if (get_attr_length (insn) != get_attr_smallestsize (insn))
     {
       /* This needs a constant table */
       fprintf (asm_out_file, "\t!constant table start\n");
@@ -1222,7 +1225,7 @@ output_movepcrel (insn, operands, mode)
 
 /* Dump out interesting debug info */
 
-void
+rtx
 final_prescan_insn (insn, opvec, noperands)
      rtx insn;
      rtx *opvec;
@@ -1245,25 +1248,390 @@ final_prescan_insn (insn, opvec, noperands)
 
 
     }
-  
-  pc += get_attr_length (insn);
 
+  pc += get_attr_length (insn);
   if (pool_size && pc - first_pc > MUST_DUMP_LEVEL)
     {
-      /* For some reason we have not dumped out a constant table, and 
-      we have emitted a lot of code.  This can happen if the think
-      which wants the table is a long conditional branch (which has no
-      room for a constant table), and there has not been a move
-      constant anywhere. */
+      /* For some reason we have not dumped out a constant table, and
+        we have emitted a lot of code.  This can happen if the think
+        which wants the table is a long conditional branch (which has no
+        room for a constant table), and there has not been a move
+        constant anywhere. */
       int label = lf++;
-      fprintf (asm_out_file, "\t!forced constant table\n");      
+      fprintf (asm_out_file, "\t!forced constant table\n");
       fprintf (asm_out_file, "\tbra    LF%d\n", label);
       fprintf (asm_out_file, "\tor     r0,r0 ! wasted slot\n");
       label = dump_constants (label);
       fprintf (asm_out_file, "LF%d:\n", label);
       fprintf (asm_out_file, "\t!constant table end\n");
     }
-  
 }
 
 
+
+/* Block move stuff stolen from m88k*/
+
+/* Emit code to perform a block move.  Choose the best method.
+
+   OPERANDS[0] is the destination.
+   OPERANDS[1] is the source.
+   OPERANDS[2] is the size.
+   OPERANDS[3] is the alignment safe to use.  */
+
+/* Emit code to perform a block move with an offset sequence of ld/st
+   instructions (..., ld 0, st 1, ld 1, st 0, ...).  SIZE and ALIGN are
+   known constants.  DEST and SRC are registers.  OFFSET is the known
+   starting point for the output pattern.  */
+
+static enum machine_mode mode_from_align[] =
+{VOIDmode, QImode, HImode, VOIDmode, SImode,
+ VOIDmode, VOIDmode, VOIDmode, DImode};
+static void
+
+block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
+     rtx dest, dest_mem;
+     rtx src, src_mem;
+     int size;
+     int align;
+     int offset;
+{
+  rtx temp[2];
+  enum machine_mode mode[2];
+  int amount[2];
+  int active[2];
+  int phase = 0;
+  int next;
+  int offset_ld = offset;
+  int offset_st = offset;
+
+  active[0] = active[1] = FALSE;
+
+  /* Establish parameters for the first load and for the second load if
+     it is known to be the same mode as the first.  */
+  amount[0] = amount[1] = align;
+
+
+  mode[0] = mode_from_align[align];
+
+  temp[0] = gen_reg_rtx (mode[0]);
+  if (size >= 2 * align)
+    {
+      mode[1] = mode[0];
+      temp[1] = gen_reg_rtx (mode[1]);
+    }
+
+  do
+    {
+      rtx srcp, dstp;
+      next = phase;
+      phase = !phase;
+
+      if (size > 0)
+       {
+         /* Change modes as the sequence tails off.  */
+         if (size < amount[next])
+           {
+             amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1));
+             mode[next] = mode_from_align[amount[next]];
+             temp[next] = gen_reg_rtx (mode[next]);
+           }
+         size -= amount[next];
+         srcp = gen_rtx (MEM,
+                         MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode,
+                         gen_rtx (PLUS, Pmode, src,
+                                  gen_rtx (CONST_INT, SImode, offset_ld)));
+         RTX_UNCHANGING_P (srcp) = RTX_UNCHANGING_P (src_mem);
+         MEM_VOLATILE_P (srcp) = MEM_VOLATILE_P (src_mem);
+         MEM_IN_STRUCT_P (srcp) = 1;
+         emit_insn (gen_rtx (SET, VOIDmode, temp[next], srcp));
+         offset_ld += amount[next];
+         active[next] = TRUE;
+       }
+
+      if (active[phase])
+       {
+         active[phase] = FALSE;
+         dstp = gen_rtx (MEM,
+                         MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode,
+                         gen_rtx (PLUS, Pmode, dest,
+                                  gen_rtx (CONST_INT, SImode, offset_st)));
+         RTX_UNCHANGING_P (dstp) = RTX_UNCHANGING_P (dest_mem);
+         MEM_VOLATILE_P (dstp) = MEM_VOLATILE_P (dest_mem);
+         MEM_IN_STRUCT_P (dstp) = 1;
+         emit_insn (gen_rtx (SET, VOIDmode, dstp, temp[phase]));
+         offset_st += amount[phase];
+       }
+    }
+  while (active[next]);
+}
+
+void
+expand_block_move (dest_mem, src_mem, operands)
+     rtx dest_mem;
+     rtx src_mem;
+     rtx *operands;
+{
+  int align = INTVAL (operands[3]);
+  int constp = (GET_CODE (operands[2]) == CONST_INT);
+  int bytes = (constp ? INTVAL (operands[2]) : 0);
+
+#if 0
+  if (constp && bytes <= 0)
+    return;
+
+  if (align > 4)
+    align = 4;
+
+  if (constp && bytes <= 3 * align)
+    block_move_sequence (operands[0], dest_mem, operands[1], src_mem,
+                        bytes, align, 0);
+
+#if 0
+  else if (constp && bytes <= best_from_align[target][align])
+    block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,
+                       bytes, align);
+
+  else if (constp && align == 4 && TARGET_88100)
+    block_move_loop (operands[0], dest_mem, operands[1], src_mem,
+                    bytes, align);
+#endif
+  else
+#endif
+    {
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
+                        VOIDmode, 3,
+                        operands[0], Pmode,
+                        operands[1], Pmode,
+                        operands[2], SImode);
+    }
+}
+
+
+override_options ()
+{
+  sh_cpu = CPU_SH0;
+  if (TARGET_SH1)
+    sh_cpu = CPU_SH1;
+  if (TARGET_SH2)
+    sh_cpu = CPU_SH2;
+  if (TARGET_SH3)
+    sh_cpu = CPU_SH3;
+}
+\f
+
+/* Stuff taken from m88k.c */
+
+/* Output to FILE the start of the assembler file.  */
+
+struct option
+{
+  char *string;
+  int *variable;
+  int on_value;
+};
+
+static int
+output_option (file, sep, type, name, indent, pos, max)
+     FILE *file;
+     char *sep;
+     char *type;
+     char *name;
+     char *indent;
+     int pos;
+     int max;
+{
+  if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
+    {
+      fprintf (file, indent);
+      return fprintf (file, "%s%s", type, name);
+    }
+  return pos + fprintf (file, "%s%s%s", sep, type, name);
+}
+
+static struct
+  {
+    char *name;
+    int value;
+  }
+
+m_options[] = TARGET_SWITCHES;
+
+static void
+output_options (file, f_options, f_len, W_options, W_len,
+               pos, max, sep, indent, term)
+     FILE *file;
+     struct option *f_options;
+     struct option *W_options;
+     int f_len, W_len;
+     int pos;
+     int max;
+     char *sep;
+     char *indent;
+     char *term;
+{
+  register int j;
+
+
+  if (optimize)
+    pos = output_option (file, sep, "-O", "", indent, pos, max);
+  if (write_symbols != NO_DEBUG)
+    pos = output_option (file, sep, "-g", "", indent, pos, max);
+  if (flag_traditional)
+    pos = output_option (file, sep, "-traditional", "", indent, pos, max);
+  if (profile_flag)
+    pos = output_option (file, sep, "-p", "", indent, pos, max);
+  if (profile_block_flag)
+    pos = output_option (file, sep, "-a", "", indent, pos, max);
+
+  for (j = 0; j < f_len; j++)
+    if (*f_options[j].variable == f_options[j].on_value)
+      pos = output_option (file, sep, "-f", f_options[j].string,
+                          indent, pos, max);
+
+  for (j = 0; j < W_len; j++)
+    if (*W_options[j].variable == W_options[j].on_value)
+      pos = output_option (file, sep, "-W", W_options[j].string,
+                          indent, pos, max);
+
+  for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
+    if (m_options[j].name[0] != '\0'
+       && m_options[j].value > 0
+       && ((m_options[j].value & target_flags)
+           == m_options[j].value))
+      pos = output_option (file, sep, "-m", m_options[j].name,
+                          indent, pos, max);
+
+
+  fprintf (file, term);
+}
+
+void
+output_file_start (file, f_options, f_len, W_options, W_len)
+     FILE *file;
+     struct option *f_options;
+     struct option *W_options;
+     int f_len, W_len;
+{
+  register int pos;
+
+  output_file_directive (file, main_input_filename);
+
+  /* Switch to the data section so that the coffsem symbol and the
+     gcc2_compiled. symbol aren't in the text section.  */
+  data_section ();
+
+
+  pos = fprintf (file, "\n! Hitachi SH cc1 (%s) arguments:", version_string);
+  output_options (file, f_options, f_len, W_options, W_len,
+                 pos, 75, " ", "\n! ", "\n\n");
+}
+\f
+
+/* Code to generate prologue and epilogue sequences */
+
+void
+sh_expand_prologue ()
+{
+  int live_regs_mask;
+  int d;
+
+  live_regs_mask = calc_live_regs (&d);
+
+  output_stack_adjust (-1, current_function_pretend_args_size);
+
+  if (current_function_anonymous_args)
+    {
+      /* Push arg regs as if they'd been provided by caller in stack */
+      int i;
+      for (i = 0; i < NPARM_REGS; i++)
+       {
+         int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
+         if (i > NPARM_REGS - current_function_args_info)
+           break;
+         push (rn);
+
+         extra_push += 4;
+       }
+    }
+
+  if (frame_pointer_needed)
+    {
+      push_regs (live_regs_mask);
+      emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
+    }
+  else
+    {
+      push_regs (live_regs_mask);
+    }
+
+  output_stack_adjust (-1, get_frame_size ());
+}
+
+void
+sh_expand_epilogue ()
+{
+  int live_regs_mask;
+  int d;
+  int i;
+
+  live_regs_mask = calc_live_regs (&d);
+
+  if (frame_pointer_needed)
+    {
+      emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
+    }
+  else
+    {
+      output_stack_adjust (1, get_frame_size ());
+    }
+
+
+  /* Pop all the registers */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      int j = (FIRST_PSEUDO_REGISTER - 1) - i;
+      if (live_regs_mask & (1 << j))
+       {
+         pop (j);
+       }
+    }
+  output_stack_adjust (1, extra_push +
+                      current_function_pretend_args_size);
+
+  extra_push = 0;
+
+  current_function_anonymous_args = 0;
+}
+
+
+/* Return the cost of a shift */
+
+int
+shiftcosts (RTX)
+     rtx RTX;
+{
+  /* If shift by a non constant, then this will be expensive. */
+  if (GET_CODE (XEXP (RTX, 1)) != CONST_INT)
+    return 20;
+
+  /* otherwise, it will be very cheap if by one of the constants
+     we can cope with. */
+  if (CONST_OK_FOR_K (INTVAL (XEXP (RTX, 1))))
+    return 1;
+
+  /* otherwise it will be several insns. */
+  return 4;
+}
+
+/* Return the cost of a multiply */
+int
+multcosts (RTX)
+     rtx RTX;
+{
+  /* If we we're aiming at small code, then just count the number of
+     insns in a multiply call sequence, otherwise, count all the insnsn
+     inside the call. */
+  if (TARGET_SMALLCODE)
+    return 3;
+  return 30;
+}
index edf7e1f..c889bb0 100644 (file)
@@ -49,18 +49,37 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern int target_flags;
 #define ISIZE_BIT  1
 #define FAST_BIT   2
-#define MULSI3_BIT 4
+
 #define MAC_BIT    8
 #define RTL_BIT    16
 #define DT_BIT     32
 #define DALIGN_BIT 64
+#define SH0_BIT        128
+#define SH1_BIT        256
+#define SH2_BIT        512
+#define SH3_BIT        1024
+#define C_BIT  2048
+#define R_BIT     (1<<12)
+#define SPACE_BIT (1<<13)
+
+/* Nonzero if we should generate code using type 0 insns */
+#define TARGET_SH0 (target_flags & SH0_BIT)
+
+/* Nonzero if we should generate code using type 1 insns */
+#define TARGET_SH1 (target_flags & SH1_BIT)
+
+/* Nonzero if we should generate code using type 2 insns */
+#define TARGET_SH2 (target_flags & SH2_BIT)
 
-/* Nonzero if we should generate code using muls.l insn */
-#define TARGET_HAS_MULSI3 (target_flags & MULSI3_BIT)
+/* Nonzero if we should generate code using type 3 insns */
+#define TARGET_SH3 (target_flags & SH3_BIT)
 
 /* Nonzero if we should generate faster code rather than smaller code */
 #define TARGET_FASTCODE   (target_flags & FAST_BIT)
 
+/* Nonzero if we should generate faster code rather than smaller code */
+#define TARGET_SMALLCODE   (target_flags & SPACE_BIT)
+
 /* Nonzero if we should dump out instruction size info */
 #define TARGET_DUMPISIZE  (target_flags & ISIZE_BIT)
 
@@ -70,27 +89,42 @@ extern int target_flags;
 /* Nonzero if we should dump the rtl in the assembly file. */
 #define TARGET_DUMP_RTL          (target_flags & RTL_BIT)
 
-/* Nonzero if the target has a decrement and test instruction .*/
-#define TARGET_HAS_DT     (target_flags & DT_BIT)
+/* Nonzero if we should dump the rtl somewher else. */
+#define TARGET_DUMP_R    (target_flags & R_BIT)
 
 /* Nonzero to align doubles on 64 bit boundaries */
 #define TARGET_ALIGN_DOUBLE (target_flags & DALIGN_BIT)
 
+
+/* Nonzero if Combine dumping wanted */
+#define TARGET_CDUMP (target_flags & C_BIT)
+
 #define TARGET_SWITCHES        \
 { {"isize",    ( ISIZE_BIT)  },\
-  {"space",    (-FAST_BIT)   },\
-  {"hasmulsi",  ( MULSI3_BIT) },\
-  {"hasdt",    ( DT_BIT)     },\
+  {"space",    ( SPACE_BIT)   },\
+  {"0",                ( SH0_BIT) },\
+  {"1",                ( SH1_BIT) },\
+  {"2",                ( SH2_BIT) },\
+  {"3",                ( SH3_BIT) },\
   {"ac",       ( MAC_BIT)    },\
   {"dalign",   ( DALIGN_BIT) },\
+  {"c",        ( C_BIT) },\
+  {"r",        ( RTL_BIT) },\
+  {"R",        ( R_BIT) },\
   {"",         TARGET_DEFAULT} \
 }
 
 #define TARGET_DEFAULT  FAST_BIT
 
+#define OVERRIDE_OPTIONS override_options();
+
 \f
 /* Target machine storage Layout.  */
 
+/* Define to use software floating point emulator for REAL_ARITHMETIC and
+   decimal <-> binary conversion. */
+#define REAL_ARITHMETIC
+
 /* Define this if most significant bit is lowest numbered
    in instructions that operate on numbered bit-fields.  */
 #define BITS_BIG_ENDIAN  0
@@ -163,8 +197,7 @@ extern int target_flags;
 
        r0-r3           scratch
        r4-r7           args in and out
-       r8-r11          call saved
-       r12             
+       r8-r12          call saved
        r13             assembler temp
        r14             frame pointer
        r15             stack pointer
@@ -195,11 +228,9 @@ extern int target_flags;
 
 /* 1 for registers that have pervasive standard uses
    and are not available for the register allocator.  */
- /*  r0  r1  r2  r3  r4  r5  r6  r7  r8 
-     r9  r10 r11 r12 r13 r14 r15 ap  pr  t   gbr mh   ml */
+ /*  r0  r1  r2  r3  r4  r5  r6  r7  r8  r9  r10 r11 r12 r13 r14 r15 ap  pr  t   gbr mh   ml */
 #define FIXED_REGISTERS  \
-   { 0,  0,  0,  0,  0,  0,  0,  0,  0,                \
-     0,  0,  0,  0,  1,  0,  1,  1,  1,  1,  1, 1,   1}
+   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  1,  0,  1,  1, 1,   1}
 
 /* 1 for registers not available across function calls.
    These must include the FIXED_REGISTERS and also any
@@ -208,11 +239,9 @@ extern int target_flags;
    and the register where structure-value addresses are passed.
    Aside from that, you can include as many other registers as you like.  */
 
- /*  r0  r1  r2  r3  r4  r5  r6  r7  r8 
-     r9  r10 r11 r12 r13 r14 r15 ap  pr  t   gbr mh  ml */
+ /*  r0  r1  r2  r3  r4  r5  r6  r7  r8 r9  r10 r11 r12 r13 r14 r15 ap  pr  t   gbr mh  ml */
 #define CALL_USED_REGISTERS \
-   { 1,  1,  1,  1,  1,  1,  1,  1,  0, \
-     0,  0,  0,  1,  1,  0,  1,  1,  1,  1,  1, 1, 1}
+   { 1,  1,  1,  1,  1,  1,  1,  1,  0, 0,  0,  0,  0,  1,  0,  1,  1,  0,  1,  1, 1, 1}
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
    to hold something of mode MODE.
@@ -252,7 +281,9 @@ extern int target_flags;
 /* Value should be nonzero if functions must have frame pointers.
    Zero means the frame pointer need not be set up (and parms may be accessed
    via the stack pointer) in functions that seem suitable.  */
-#define FRAME_POINTER_REQUIRED 0
+
+
+#define FRAME_POINTER_REQUIRED (get_frame_size() > 1000)
 
 /* Definitions for register eliminations.
 
@@ -288,12 +319,10 @@ extern int target_flags;
 /* Register in which the static-chain is passed to a function.  */
 #define STATIC_CHAIN_REGNUM    13
 
-/* If the structure value address is not passed in a register, define
-   this as an expression returning an RTX for the place
-   where the address is passed.  If it returns 0, the address is
-   passed as an "invisible" first argument. */
+/* The register in which a struct value address is passed */
+
+#define STRUCT_VALUE_REGNUM 3
 
-#define STRUCT_VALUE 0
 
 \f
 /* Define the classes of registers for register constraints in the
@@ -372,7 +401,7 @@ extern int regno_reg_class[];
 
 /* The order in which register should be allocated.  */
 #define REG_ALLOC_ORDER  \
-  { 1,2,3,0,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21}
+  { 1,2,3,7,4,5,6,0,8,9,10,11,12,13,14,15,16,17,18,19,20,21}
 
 /* The class value for index registers, and the one for base regs.  */
 #define INDEX_REG_CLASS  R0_REGS
@@ -392,13 +421,13 @@ extern enum reg_class reg_class_from_letter[];
    C is the letter, and VALUE is a constant value.
    Return 1 if VALUE is in the range specified by C.
        I: arithmetic operand -127..128, as used in add, sub, etc
-       L: logical operand 0..255, as used in add, or, etc.
+       L: logical operand 0..255, as used in and, or, etc.
        M: constant 1
        K: shift operand 1,2,8 or 16 */
 
 
-#define CONST_OK_FOR_I(VALUE) ((VALUE)>= -128 && (VALUE) <= 127)
-#define CONST_OK_FOR_L(VALUE) ((VALUE)>= 0 && (VALUE) <= 255)
+#define CONST_OK_FOR_I(VALUE) (((int)(VALUE))>= -128 && ((int)(VALUE)) <= 127)
+#define CONST_OK_FOR_L(VALUE) (((int)(VALUE))>=    0 && ((int)(VALUE)) <= 255)
 #define CONST_OK_FOR_M(VALUE) ((VALUE)==1)
 #define CONST_OK_FOR_K(VALUE) ((VALUE)==1||(VALUE)==2||(VALUE)==8||(VALUE)==16)
 
@@ -422,7 +451,7 @@ extern enum reg_class reg_class_from_letter[];
    In general this is just CLASS; but on some machines
    in some cases it is preferable to use a more restrictive class.  */
 
-#define PREFERRED_RELOAD_CLASS(X, CLASS)  (CLASS)
+#define PREFERRED_RELOAD_CLASS(X, CLASS)  CLASS
 
 /* Return the register class of a scratch register needed to copy IN into
    or out of a register in CLASS in MODE.  If it can be done directly,
@@ -605,19 +634,13 @@ extern int current_function_anonymous_args;
   current_function_anonymous_args = 1;
 
 
-/* Generate assembly output for the start of a function.  */
-
-#define FUNCTION_PROLOGUE(STREAM, SIZE)  \
-  output_prologue ((STREAM), (SIZE))
-
 /* Call the function profiler with a given profile label. */
 
-#define FUNCTION_PROFILER(STREAM,LABELNO)              \
-{                                                      \
-    fprintf(STREAM, "\tsts.l   pr,@-r15\n");           \
-    fprintf(STREAM, "\tjsr\tmcount\n");                        \
-    fprintf(STREAM, "\tor      r0,r0\n");              \
-    fprintf(STREAM, "\t.long\tLP%d\n", (LABELNO));     \
+#define FUNCTION_PROFILER(STREAM,LABELNO)                      \
+{                                                              \
+       fprintf(STREAM, "       trapa   #5\n");                 \
+       fprintf(STREAM, "       .align  2\n");                  \
+       fprintf(STREAM, "       .long   LP%d\n", (LABELNO));    \
 }
 
 
@@ -628,16 +651,11 @@ extern int current_function_anonymous_args;
 
 #define EXIT_IGNORE_STACK 0
 
-/* Generate the assembly code for function exit. */
+/* Generate the assembly code for function exit 
+   Just dump out any accumulated constant table.*/
 
 #define FUNCTION_EPILOGUE(STREAM, SIZE)  \
-  output_epilogue ((STREAM), (SIZE))
-
-#define ELIGIBLE_FOR_EPILOGUE_DELAY(INSN,N) \
-  (get_attr_in_delay_slot(INSN) == IN_DELAY_SLOT_YES)  
-
-#define DELAY_SLOTS_FOR_EPILOGUE \
-  delay_slots_for_epilogue();
+  dump_constants(0);  
 
 /* Output assembler code for a block containing the constant parts
    of a trampoline, leaving space for the variable parts.
@@ -703,27 +721,19 @@ extern int current_function_anonymous_args;
 /* Maximum number of registers that can appear in a valid memory 
    address. */
 
-#define MAX_REGS_PER_ADDRESS 1
+#define MAX_REGS_PER_ADDRESS 4
 
 /* Recognize any constant value that is a valid address.  */
 
 #define CONSTANT_ADDRESS_P(X)  \
   (GET_CODE (X) == LABEL_REF)
-#if 0
-
-   || GET_CODE (X) == SYMBOL_REF       \
-   || GET_CODE (X) == CONST_INT        \
-   || GET_CODE (X) == CONST)
-
-#endif
 
 /* Nonzero if the constant value X is a legitimate general operand.
    It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.
 
-   On the SH, allow any thing but a double */
+   On the SH, allow anything but a double */
 
-#define LEGITIMATE_CONSTANT_P(X) \
-  (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode)
+#define LEGITIMATE_CONSTANT_P(X)  (GET_CODE(X) != CONST_DOUBLE)
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
@@ -733,24 +743,32 @@ extern int current_function_anonymous_args;
    The symbol REG_OK_STRICT causes the latter definition to be used.  */
 
 #ifndef REG_OK_STRICT
+
 /* Nonzero if X is a hard reg that can be used as a base reg
    or if it is a pseudo reg.  */
 #define REG_OK_FOR_BASE_P(X) \
-  (REGNO(X) <= 16 || REGNO(X) >= FIRST_PSEUDO_REGISTER)
+       (REGNO (X) <= 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
 
 /* Nonzero if X is a hard reg that can be used as an index
    or if it is a pseudo reg.  */
 #define REG_OK_FOR_INDEX_P(X) \
-    (REGNO(X)==0||REGNO(X)>=FIRST_PSEUDO_REGISTER)
-#define REG_OK_FOR_PRE_POST_P(X) (REGNO(X) <= 16)
+       (REGNO (X) == 0 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
+
+#define REG_OK_FOR_PRE_POST_P(X) \
+       (REGNO (X) <= 16)
+
 #else
 
 /* Nonzero if X is a hard reg that can be used as a base reg.  */
-#define REG_OK_FOR_BASE_P(X)  REGNO_OK_FOR_BASE_P (REGNO (X))
+#define REG_OK_FOR_BASE_P(X)   \
+       REGNO_OK_FOR_BASE_P (REGNO (X))
+
 /* Nonzero if X is a hard reg that can be used as an index.  */
-#define REG_OK_FOR_INDEX_P(X)  REGNO_OK_FOR_INDEX_P (REGNO (X))
+#define REG_OK_FOR_INDEX_P(X)  \
+       REGNO_OK_FOR_INDEX_P (REGNO (X))
+
 #define REG_OK_FOR_PRE_POST_P(X)  \
-        (REGNO (X) <= 16 || (unsigned) reg_renumber[REGNO (X)] <=16)
+       (REGNO (X) <= 16 || (unsigned) reg_renumber[REGNO (X)] <=16)
 #endif
 \f
 /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
@@ -759,6 +777,7 @@ extern int current_function_anonymous_args;
    that wants to use this address.
 
    The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS.  */
+
 #define BASE_REGISTER_RTX_P(X)  \
   (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X))
 
@@ -777,14 +796,20 @@ extern int current_function_anonymous_args;
          --REG
 */
 
-/* A legitimate index for a QI or HI is 0, SI and above can be any 
-   number 0..64 */
+/* The SH allows a displacement in a QI or HI amode, but only when the 
+   other operand is R0. GCC doesn't handle this very well, so we forgo
+   all of that.
+
+   A legitimate index for a QI or HI is 0, SI and above can be any 
+   number 0..63 */
 
 #define GO_IF_LEGITIMATE_INDEX(MODE, REGNO, OP, LABEL)  \
   do {                                                 \
     if (GET_CODE (OP) == CONST_INT)                    \
       {                                                        \
-       if (GET_MODE_SIZE (MODE) < 4 && INTVAL(OP) == 0)\
+       if (0&&GET_MODE_SIZE (MODE) == 2 && ((unsigned)INTVAL(OP)) <=30)\
+         goto LABEL;                                   \
+       if (0&&GET_MODE_SIZE (MODE) == 1 && ((unsigned)INTVAL(OP)) <=15)\
          goto LABEL;                                   \
        if (GET_MODE_SIZE (MODE) >=4                    \
            && ((unsigned)INTVAL(OP)) < 64)             \
@@ -793,32 +818,37 @@ extern int current_function_anonymous_args;
   } while(0)
 
 
-
-#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \
-{                                                                      \
-  if (BASE_REGISTER_RTX_P (X))                                         \
-    goto LABEL;                                                                \
-  else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC)       \
-          && GET_CODE (XEXP (X, 0)) == REG                             \
-          && REG_OK_FOR_PRE_POST_P (XEXP (X, 0)))                      \
-    goto LABEL;                                                                \
-  else if (GET_CODE (X) == PLUS)                                       \
-    {                                                                  \
-      rtx xop0 = XEXP(X,0);                                            \
-      rtx xop1 = XEXP(X,1);                                            \
-      if (BASE_REGISTER_RTX_P (xop0))                                  \
-       GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL);       \
-      else if (BASE_REGISTER_RTX_P (xop1))                             \
-       GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL);       \
-    }                                                                  \
-  else if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_DEC)       \
-          && GET_CODE (XEXP (X, 0)) == REG                             \
-          && REG_OK_FOR_PRE_POST_P (XEXP (X, 0)))                      \
-    goto LABEL;                                                                \
-}
-
-\f
-/* Try machine-dependent ways of modifying an illegitimate address
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL)                  \
+{                                                                \
+  if (BASE_REGISTER_RTX_P (X))                                   \
+    goto LABEL;                                                          \
+  else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC)  \
+          && GET_CODE (XEXP (X, 0)) == REG                       \
+          && REG_OK_FOR_PRE_POST_P (XEXP (X, 0)))                \
+    goto LABEL;                                                          \
+  else if (GET_CODE (X) == PLUS || GET_CODE(X) == LO_SUM)        \
+    {                                                            \
+      rtx xop0 = XEXP(X,0);                                      \
+      rtx xop1 = XEXP(X,1);                                      \
+      if (GET_MODE_SIZE(MODE) >= 4 && BASE_REGISTER_RTX_P (xop0)) \
+       GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \
+      if (GET_MODE_SIZE(MODE) >= 4 && BASE_REGISTER_RTX_P (xop1)) \
+       GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \
+      if (GET_MODE_SIZE(MODE)<=4) {                              \
+       if(BASE_REGISTER_RTX_P(xop1) &&                           \
+          INDEX_REGISTER_RTX_P(xop0)) goto LABEL;                \
+       if(INDEX_REGISTER_RTX_P(xop1) &&                          \
+          BASE_REGISTER_RTX_P(xop0)) goto LABEL;                 \
+      }                                                                  \
+    }                                                            \
+  else if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_DEC)  \
+          && GET_CODE (XEXP (X, 0)) == REG                       \
+          && REG_OK_FOR_PRE_POST_P (XEXP (X, 0)))                \
+    goto LABEL;                                                   \
+}                                                                 
+                                                                  
+\f                                                                 
+/* Try machine-dependent ways of modifying an illegitimate address 
    to be legitimate.  If we find one, return the new, valid address.
    This macro is used in only one place: `memory_address' in explow.c.
 
@@ -926,17 +956,21 @@ extern int current_function_anonymous_args;
     if (CONST_OK_FOR_I (INTVAL(RTX)))           \
       return 1;                                        \
     else                                       \
-      return 5;                                        \
+      return 8;                                        \
   case CONST:                                  \
   case LABEL_REF:                              \
   case SYMBOL_REF:                             \
-    return 6;                                  \
+    return 5;                                  \
   case CONST_DOUBLE:                           \
       return 10;
 
 #define RTX_COSTS(X, CODE, OUTER_CODE)                 \
   case MULT:                                           \
-    return COSTS_N_INSNS (TARGET_HAS_MULSI3 ? 2 : 20);         \
+    return COSTS_N_INSNS (multcosts (X));              \
+  case ASHIFT:                                         \
+  case ASHIFTRT:                                       \
+  case LSHIFT:                                         \
+    return COSTS_N_INSNS (shiftcosts (X)) ;            \
   case DIV:                                            \
   case UDIV:                                           \
   case MOD:                                            \
@@ -954,14 +988,18 @@ extern int current_function_anonymous_args;
 */
 
 #define REGISTER_MOVE_COST(SRCCLASS, DSTCLASS)  \
-    ((DSTCLASS ==T_REGS) ? 10 : 2)
+       ((DSTCLASS == T_REGS) ? 10 : 1)
 \f
 /* Assembler output control */
 
 /* The text to go at the start of the assembler file */
-#define ASM_FILE_START(STREAM) \
-  fprintf (STREAM,"! GCC for the Hitachi Super-H\n");          \
-  output_file_directive (STREAM, main_input_filename);
+#define ASM_FILE_START(STREAM)                                                         \
+  output_file_start (STREAM, f_options, sizeof f_options / sizeof f_options[0], \
+                    W_options, sizeof W_options / sizeof W_options[0]);        
+
+
+#define ASM_FILE_END(STREAM) \
+  dump_constants(0);  
 
 #define ASM_APP_ON  ""
 #define ASM_APP_OFF  ""
@@ -971,9 +1009,78 @@ extern int current_function_anonymous_args;
 
 
 /* Switch to the text or data segment.  */
-#define TEXT_SECTION_ASM_OP  ".text"
-#define DATA_SECTION_ASM_OP  ".data"
+#define TEXT_SECTION_ASM_OP  "\t.text"
+#define DATA_SECTION_ASM_OP  "\t.data"
+#define CTORS_SECTION_ASM_OP "\t.section\t.ctors\n"
+#define DTORS_SECTION_ASM_OP "\t.section\t.dtors\n"
+
+#define EXTRA_SECTIONS in_ctors, in_dtors
+#define EXTRA_SECTION_FUNCTIONS                              \
+void                                                        \
+ctors_section()                                             \
+{                                                           \
+  if (in_section != in_ctors)                               \
+    {                                                       \
+      fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP);  \
+      in_section = in_ctors;                                \
+    }                                                       \
+}                                                           \
+void                                                        \
+dtors_section()                                             \
+{                                                           \
+  if (in_section != in_dtors)                               \
+    {                                                       \
+      fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP);  \
+      in_section = in_dtors;                                \
+    }                                                       \
+}                                                            
+
+#define ASM_OUTPUT_SECTION(file, nam) \
+   do { fprintf (file, "\t.section\t%s\n", nam); } while(0) 
+
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME)      \
+   do { ctors_section();  fprintf(FILE,"\t.long\t_%s\n", NAME); } while (0)
+
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME)       \
+   do {  dtors_section();  fprintf(FILE,"\t.long\t_%s\n", NAME); } while (0)
+
+
+#undef DO_GLOBAL_CTORS_BODY                     
+#define DO_GLOBAL_CTORS_BODY                   \
+{                                              \
+  typedef (*pfunc)();                          \
+  extern pfunc __ctors[];                      \
+  extern pfunc __ctors_end[];                  \
+  pfunc *p;                                    \
+  for (p = __ctors; p < __ctors_end; p++)      \
+    {                                          \
+      (*p)();                                  \
+    }                                          \
+}                                              
+
+#undef DO_GLOBAL_DTORS_BODY                     
+#define DO_GLOBAL_DTORS_BODY                    \
+{                                              \
+  typedef (*pfunc)();                          \
+  extern pfunc __dtors[];                      \
+  extern pfunc __dtors_end[];                  \
+  pfunc *p;                                    \
+  for (p = __dtors; p < __dtors_end; p++)      \
+    {                                          \
+      (*p)();                                  \
+    }                                          \
+}                                               
+
+
+
+#define ASM_OUTPUT_REG_PUSH(file, v) \
+  fprintf (file, "\tmov.l      r%s,-@r15\n", v);
 
+#define ASM_OUTPUT_REG_POP(file, v) \
+  fprintf (file, "\tmov.l      @r15+,r%s\n", v);
+
+
+  
 /* The assembler's names for the registers.  RFP need not always be used as
    the Real framepointer; it can also be used as a normal general register.
    Note that the name `fp' is horribly misleading since `fp' is in fact only
@@ -1048,22 +1155,20 @@ extern int current_function_anonymous_args;
 
 /* This is how to output an assembler line defining a `double' */
 
-#define ASM_OUTPUT_DOUBLE(FILE,VALUE)                                  \
-      {                                                                        \
-       long t[2];                                                      \
-       REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t);                       \
-       fprintf (FILE, "\t.long\t0x%lx\n\t.long\t0x%lx\n",              \
-                 t[0], t[1]);                                          \
-      }                                                                        \
+#define ASM_OUTPUT_DOUBLE(FILE,VALUE)                  \
+do { char dstr[30];                                    \
+     REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr);   \
+     fprintf (FILE, "\t.double %s\n", dstr);           \
+   } while (0)
+
 
 /* This is how to output an assembler line defining a `float' constant.  */
+#define ASM_OUTPUT_FLOAT(FILE,VALUE)           \
+do { char dstr[30];                                    \
+     REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr);   \
+     fprintf (FILE, "\t.float %s\n", dstr);            \
+   } while (0)
 
-#define ASM_OUTPUT_FLOAT(FILE,VALUE)                                   \
-  {                                                                    \
-       long t;                                                         \
-       REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t);                       \
-       fprintf (FILE, "\t.long\t0x%lx\n", t);                          \
-  }                                                                    \
 
 #define ASM_OUTPUT_INT(STREAM, EXP)    \
   (fprintf (STREAM, "\t.long\t"),              \
@@ -1123,7 +1228,7 @@ extern int current_function_anonymous_args;
 /* Only perform branch elimination (by making instructions conditional) if
    we're optimising.  Otherwise it's of no use anyway.  */
 #define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS)  \
-    final_prescan_insn (INSN, OPVEC, NOPERANDS)
+     final_prescan_insn (INSN, OPVEC, NOPERANDS)
 
 /* Print operand X (an rtx) in assembler syntax to file FILE.
    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
@@ -1136,7 +1241,7 @@ extern int current_function_anonymous_args;
 #define PRINT_OPERAND_ADDRESS(STREAM,X)  print_operand_address (STREAM, X)
 
 #define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
-  ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR) == '!')
+  ((CHAR)=='.' || (CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR) == '!')
 
 \f
 /* Define the information needed to generate branch insns.  This is stored
@@ -1147,7 +1252,7 @@ extern struct rtx_def *sh_compare_op0;
 extern struct rtx_def *sh_compare_op1;
 extern struct rtx_def *prepare_scc_operands();
 
-
+extern enum attr_cpu sh_cpu;   /* target cpu */
 
 /* Declare functions defined in sh.c and used in templates. */
 
@@ -1159,3 +1264,8 @@ extern char *output_movepcrel();
 
 #define ADJUST_INSN_LENGTH(insn, length) \
   adjust_insn_length (insn, insn_lengths)
+
+
+
+
+
index 2c8f661..5ba2573 100644 (file)
 ;; Attributes
 ;; -------------------------------------------------------------------------
 
-(define_attr "type" "cbranch,ctable,jump,arith,other"
+; Target CPU.
+
+(define_attr "cpu" "sh0,sh1,sh2,sh3"
+  (const (symbol_ref "sh_cpu")))
+
+(define_attr "type" "cbranch,ctable,jump,arith,other,load,store,move,smpy,dmpy,return,pload"
   (const_string "other"))
 
 ; If a conditional branch destination is within -100..100 bytes away 
                                      (const_int 4)
                                      (const_int 6))
         ] (const_int 2)))
+
+;; (define_function_unit {name} {num-units} {n-users} {test}
+;;                       {ready-delay} {issue-delay} [{conflict-list}])
                                      
+(define_function_unit "memory" 1 1 (eq_attr "type" "load") 1 0)
+(define_function_unit "mpy"    1 1 (eq_attr "type" "smpy") 3 0)
+(define_function_unit "mpy"    1 1 (eq_attr "type" "dmpy") 5 0)
 
 (define_attr "needs_delay_slot" "yes,no"
-  (cond [(eq_attr "type" "jump") (const_string "yes")]
+  (cond [(eq_attr "type" "jump") (const_string "yes")
+        (eq_attr "type" "return") (const_string "yes")]
        (const_string "no")))
 
+(define_delay 
+  (eq_attr "needs_delay_slot" "yes") 
+  [(eq_attr "in_delay_slot" "yes") (nil) (nil)])
+
+
 (define_attr "dump" "yes,no,must" (const_string "no"))
 (define_attr "constneed" "yes,no" (const_string "no"))
 (define_attr "smallestsize" "" (const_int 2))
 (define_attr "in_delay_slot" "maybe,yes,no" 
   (cond [(eq_attr "type" "cbranch") (const_string "no")
         (eq_attr "type" "jump") (const_string "no")
+        (eq_attr "type" "pload") (const_string "no")
+        (eq_attr "type" "return") (const_string "no")
         (eq_attr "length" "2") (const_string "yes")
         (eq_attr "length" "4,6,8,10,12") (const_string "no")
         ] (const_string "yes")))
 
 
-(define_delay (eq_attr "needs_delay_slot" "yes")
-  [(eq_attr "in_delay_slot" "yes") (nil) (nil)])
-
-
 \f
 ;; -------------------------------------------------------------------------
 ;; SImode signed integer comparisons
 
 (define_insn "cmplesi_t"
   [(set (reg:SI 18) (le (match_operand:SI 0 "arith_reg_operand" "r")
-                 (match_operand:SI 1 "arith_reg_operand" "r")))]
+                         (match_operand:SI 1 "arith_reg_operand" "r")))]
   ""
   "cmp/ge      %0,%1")
 
    (set_attr "type" "arith")])
 
 (define_insn "subsi3"
-  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-       (minus:SI (match_operand:SI 1 "arith_reg_operand" "0")
-                 (match_operand:SI 2 "arith_reg_operand" "r")))]
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
+       (minus:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
+                 (match_operand:SI 2 "arith_operand" "r,I")))]
   ""
-  "sub %2,%0"
+  "@
+       sub     %2,%0
+       add     %M2,%0"
   [(set_attr "type" "arith")])
 
 \f
                 (zero_extend:SI
                  (match_operand:HI 2 "arith_reg_operand" "r"))))]
   ""
-  "mulu        %2,%1")
+  "mulu        %2,%1"
+  [(set_attr "type" "smpy")])
 
 (define_insn ""
   [(set (reg:SI 21)
                 (sign_extend:SI
                  (match_operand:HI 2 "arith_reg_operand" "r"))))]
   ""
-  "muls        %2,%1")
+  "muls        %2,%1"
+  [(set_attr "type" "smpy")])
 
 (define_expand "mulhisi3"
   [(set (reg:SI 21)
   ""
   "")
 
-(define_insn ""
-  [(set (reg:SI 21)
-       (mult:SI (match_operand:SI 1 "arith_reg_operand" "r")
-                 (match_operand:SI 2 "arith_reg_operand" "r")))]
-  "TARGET_HAS_MULSI3"
-  "muls.l      %2,%1")
-
-(define_expand "mulsi3"
-  [(set (reg:SI 21)
-       (mult:SI  (match_operand:SI 1 "arith_reg_operand" "r")
-                 (match_operand:SI 2 "arith_reg_operand" "r")))
-   (set (match_operand:SI 0 "arith_reg_operand" "=r")
-       (reg:SI 20))]
-  "TARGET_HAS_MULSI3"
-  "")
-
-(define_insn ""
-  [(set (reg:DI 20)
-       (mult:DI (sign_extend:DI
-                 (match_operand:SI 1 "arith_reg_operand" "r"))
-                (sign_extend:DI
-                 (match_operand:SI 2 "arith_reg_operand" "r"))))]
-  "TARGET_HAS_MULSI3"
-  "dmuls.l     %2,%1")
-
-(define_expand "mulsidi3"
-  [(set (reg:DI 20)
-       (mult:DI (sign_extend:DI
-                 (match_operand:SI 1 "arith_reg_operand" "r"))
-                (sign_extend:DI
-                 (match_operand:SI 2 "arith_reg_operand" "r"))))
-   (set (match_operand:DI 0 "arith_reg_operand" "=r")
-       (reg:DI 20))]
-  "TARGET_HAS_MULSI3"
-  "")
-
-(define_insn ""
-  [(set (reg:DI 20)
-       (mult:DI (zero_extend:DI
-                 (match_operand:SI 1 "arith_reg_operand" "r"))
-                (zero_extend:DI
-                 (match_operand:SI 2 "arith_reg_operand" "r"))))]
-  "TARGET_HAS_MULSI3"
-  "dmulu.l     %2,%1")
-
-(define_expand "umulsidi3"
-  [(set (reg:DI 20)
-       (mult:DI (zero_extend:DI
-                 (match_operand:SI 1 "arith_reg_operand" "r"))
-                (zero_extend:DI
-                 (match_operand:SI 2 "arith_reg_operand" "r"))))
-   (set (match_operand:DI 0 "arith_reg_operand" "=r")
-       (reg:DI 20))]
-  "TARGET_HAS_MULSI3"
-  "")
 \f
 ;; -------------------------------------------------------------------------
 ;; Logical operations
 ;; Shifts and rotates
 ;; -------------------------------------------------------------------------
 
+(define_insn "rotlsi3_k"
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
+       (rotate:SI (match_operand:SI 1 "arith_reg_operand" "0")
+                  (const_int 1)))
+   (clobber (reg:SI 18))]
+  ""
+  "rotl        %0")
+
+(define_expand "rotlsi3"
+  [(parallel[(set (match_operand:SI 0 "arith_reg_operand" "")
+                 (rotate:SI (match_operand:SI 1 "arith_reg_operand" "")
+                            (match_operand:SI 2 "immediate_operand" "")))
+            (clobber (reg:SI 18))])]
+  ""
+  "{ if (GET_CODE(operands[2]) != CONST_INT || INTVAL(operands[2]) != 1) FAIL;}")
+
+(define_insn "rotrsi3_k"
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
+       (rotatert:SI (match_operand:SI 1 "arith_reg_operand" "0")
+                    (const_int 1)))
+   (clobber (reg:SI 18))]
+  ""
+  "rotr        %0")
+
+(define_expand "rotrsi3"
+  [(parallel[(set (match_operand:SI 0 "arith_reg_operand" "")
+                  (rotatert:SI (match_operand:SI 1 "arith_reg_operand" "")
+                               (match_operand:SI 2 "immediate_operand" "")))
+             (clobber (reg:SI 18))])]
+  ""
+  "{ if (GET_CODE(operands[2]) != CONST_INT || INTVAL(operands[2]) != 1) FAIL;}")
+
 (define_insn "ashlsi3_k"
   [(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
        (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
-                  (match_operand:SI 2 "immediate_operand" "L,n")))]
+                  (match_operand:SI 2 "immediate_operand" "K,n")))
+   (clobber (reg:SI 18))]
   ""
-  "*return output_shift(\"shll\", operands[0], operands[2]);"
+  "*return output_shift(\"shll\", operands[0], operands[2], ASHIFT);"
   [(set_attr "length" "2,12")
    (set_attr "in_delay_slot" "yes,no")
    (set_attr "type" "arith")])
 
 (define_expand "ashlsi3"
-  [(set (match_operand:SI 0 "arith_reg_operand" "")
-       (ashift:SI (match_operand:SI 1 "arith_reg_operand" "")
-                  (match_operand:SI 2 "immediate_operand" "")))]
+  [(parallel[(set (match_operand:SI 0 "arith_reg_operand" "")
+                 (ashift:SI (match_operand:SI 1 "arith_reg_operand" "")
+                            (match_operand:SI 2 "immediate_operand" "")))
+            (clobber (reg:SI 18))])]
   ""
-  "if (!ok_shift_value(operands[2])) FAIL;")
+  "if (!ok_shift_value(operands[2], ASHIFT)) FAIL;")
 
 (define_insn "ashrsi3_k"
   [(set (match_operand:SI 0 "arith_reg_operand" "=r")
        (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
-                    (const_int 1)))]
+                    (const_int 1)))
+   (clobber (reg:SI 18))]
   ""
   "shar        %0"
   [(set_attr "type" "arith")])
 
 (define_expand "ashrsi3"
-  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-       (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "r")
-                    (match_operand:SI 2 "nonmemory_operand" "M")))]
+  [(parallel[(set (match_operand:SI 0 "arith_reg_operand" "=r")
+                 (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "r")
+                              (match_operand:SI 2 "nonmemory_operand" "M")))
+            (clobber (reg:SI 18))])]
   ""
   "
 {
 ")
 
 (define_insn "lshrsi3_k"
-  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-       (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
-                    (match_operand:SI 2 "immediate_operand" "L")))]
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
+       (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
+                    (match_operand:SI 2 "immediate_operand" "K,n")))
+   (clobber (reg:SI 18))]
   ""
-  "* return output_shift (\"shlr\", operands[0], operands[2]);"
-  [(set_attr "length" "12")
-   (set_attr "in_delay_slot" "no")
+  "* return output_shift (\"shlr\", operands[0], operands[2], LSHIFTRT);"
+  [(set_attr "length" "2,12")
+   (set_attr "in_delay_slot" "yes,no")
    (set_attr "type" "arith")])
 
 (define_expand "lshrsi3"
-  [(set (match_operand:SI 0 "arith_reg_operand" "")
-       (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "")
-                    (match_operand:SI 2 "nonmemory_operand" "")))]
+  [(parallel[(set (match_operand:SI 0 "arith_reg_operand" "")
+                 (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "")
+                              (match_operand:SI 2 "nonmemory_operand" "")))
+            (clobber (reg:SI 18))])]
   ""
   "if (!ok_shift_value (operands[2])) FAIL; ")
 
 
 (define_insn "lshrdi3_k"
   [(set (match_operand:DI 0 "arith_reg_operand" "=r")
-                  (lshiftrt:DI (match_operand:DI 1 "arith_reg_operand" "0")
-                             (match_operand:DI 2 "immediate_operand" "I")))
-      (clobber (reg:SI 18))]
+       (lshiftrt:DI (match_operand:DI 1 "arith_reg_operand" "0")
+                    (match_operand:DI 2 "immediate_operand" "I")))
+   (clobber (reg:SI 18))]
   ""
   "shlr        %0\;rotcr       %R0"
   [(set_attr "length" "4")])
 ;; -------------------------------------------------------------------------
 
 (define_insn ""
-  [(set (match_operand:SI 0 "push_operand" "=<")
-       (match_operand:SI 1 "arith_reg_operand" "r"))]
-   ""
-   "mov.l      %1,%0")
+  [(set (match_operand:SI 0 "push_operand" "=<,<")
+       (match_operand:SI 1 "arith_reg_operand" "r,l"))]
+  ""
+  "@
+       mov.l   %1,%0
+       sts.l   pr,%0"
+  [(set_attr "type" "store")])
 
-(define_insn "movsi_pcrel"
-  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-       (match_operand:SI 1 "hard_immediate_operand" "i"))]
+(define_insn ""
+  [(set        (match_operand:SI 0 "arith_reg_operand" "=r,l")
+       (match_operand:SI 1 "pop_operand" "=>,>"))]
   ""
-  "* return output_movepcrel (insn, operands, SImode);"
-  [(set_attr "length" "2")
-   (set_attr "in_delay_slot" "no")
-   (set_attr "constneed" "yes")
-   (set_attr "smallestsize" "2")
-   (set_attr "largestsize" "8")])
-               
+  "@
+       mov.l   %1,%0
+       lds.l   %1,pr"
+  [(set_attr "type" "load,pload")])
+
+(define_insn "push"
+  [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+       (match_operand:SI 0 "register_operand" "r,l"))]
+  ""
+  "@
+       mov.l   %0,@-r15
+       sts.l   pr,@-r15")
+
+(define_insn "pop"
+  [(set (match_operand:SI 0 "register_operand" "=r,l")
+       (mem:SI (post_inc:SI (reg:SI 15))))]
+  ""
+  "@
+       mov.l   @r15+,%0
+       lds.l   @r15+,pr"
+  [(set_attr "type" "load,pload")])
+
+; some constants are easier to generate with alu operations
+; rather than loading from memory
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operand:SI 1 "painful_immediate_operand" "i"))]
+  ""
+  [(set (match_dup 0) (const_int 127))
+   (set (match_dup 0) (plus:SI (match_dup 0)
+                              (match_dup 2)))]
+  "operands[2] = GEN_INT (INTVAL(operands[1]) - 127);" )
+
 (define_insn "movsi_i"
-  [(set (match_operand:SI 0 "general_operand" "=r,r,r,m,l,r,r,r,t")
-       (match_operand:SI 1 "general_operand"  "r,I,m,r,r,l,t,x,r"))]
+  [(set (match_operand:SI 0 "general_operand" "=r,r,r,m,l,r,r,r,t,x")
+       (match_operand:SI 1 "general_movsrc_operand"  "r,I,m,r,r,l,t,x,r,r"))]
   ""
   "@
        mov     %1,%0
        mov     %1,%0
        mov.l   %1,%0
        mov.l   %1,%0
-       mov     %1,%0
-       mov     %1,%0
+       lds     %1,%0
+       sts     %1,%0
         movt   %0
        sts     %1,%0
-       tst     %1,%1\;bt       T%*\;bra        F%*\;sett\;T%*:clrt\;F%*:%^"
-       [(set_attr "length" "2,2,2,2,2,2,2,2,10")])
+       tst     %1,%1\;bt       T%*\;bra        F%*\;sett\;T%*:clrt\;F%*:%^
+       lds     %1,%0"
+  [(set_attr "length" "2,2,2,2,2,2,2,2,10,2")
+   (set_attr "type" "move,move,load,pload,move,move,move,move,move,move")])
+
+(define_insn "movsi_pcrel"
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
+       (match_operand:SI 1 "hard_immediate_operand" "i"))]
+  ""
+  "* return output_movepcrel (insn, operands, SImode);"
+  [(set_attr "length" "2")
+   (set_attr "in_delay_slot" "no")
+   (set_attr "constneed" "yes")
+   (set_attr "smallestsize" "2")
+   (set_attr "largestsize" "8")
+   (set_attr "type" "load")])
 
 (define_expand "movsi"
   [(set (match_operand:SI 0 "general_operand" "")
        (match_operand:SI 1 "general_operand" ""))]
   ""
-  "{ prepare_move_operands(operands, SImode); } ")
+  "{ if(prepare_move_operands(operands, SImode)) DONE; } ")
 
 (define_insn "movqi_i"
-  [(set (match_operand:QI 0 "general_operand" "=r,r,z,m,r,m,r,r")
-       (match_operand:QI 1 "general_operand"  "r,n,m,z,m,r,x,t"))]
+  [(set (match_operand:QI 0 "general_operand" "=r,r,r,m,r,m,r,r")
+       (match_operand:QI 1 "general_operand"  "r,n,m,r,m,r,x,t"))]
   ""
   "@
        mov     %1,%0
        mov     %1,%0
-       mov.b   %1,%0 !4
-       mov.b   %1,%0 !5
-       mov.b   %1,%0 !6
-       mov.b   %1,%0 ! 7
+       mov.b   %1,%0 
+       mov.b   %1,%0 
+       mov.b   %1,%0 
+       mov.b   %1,%0 
        sts     %1,%0
        movt    %0")
 
    (set_attr "in_delay_slot" "no")
    (set_attr "constneed" "yes")
    (set_attr "smallestsize" "2")
-   (set_attr "largestsize" "8")])
+   (set_attr "largestsize" "8")
+   (set_attr "type" "load")])
 
 (define_insn "movhi_i"
   [(set (match_operand:HI 0 "general_operand" "=r,r,m,z,m,r,r")
        mov.w   %1,%0
        mov.w   %1,%0
        sts     %1,%0
-       movt    %0")
+       movt    %0"
+  [(set_attr "type" "move,load,store,load,store,move,move")])
 
 (define_expand "movhi"
   [(set (match_operand:HI 0 "general_operand" "")
        (match_operand:DI 1 "arith_reg_operand" "r"))]
    ""
    "mov.l      %R1,%0\;mov.l   %1,%0"
-   [(set_attr "length" "4")])
+   [(set_attr "length" "4")
+    (set_attr "type" "store")])
 
 (define_insn "movdi_pcrel"
   [(set (match_operand:DI 0 "arith_reg_operand" "=r")
    (set_attr "constneed" "yes")
    (set_attr "smallestsize" "4")
    (set_attr "constantsize" "8")
-   (set_attr "largestsize" "18")])
+   (set_attr "largestsize" "18")
+   (set_attr "type" "load")])
 
 (define_insn "movdi_k"
   [(set (match_operand:DI 0 "general_operand" "=r,r,m,r,r,m,r")
        (match_operand:DI 1 "general_operand" "r,m,r,I,m,r,x"))]
   ""
   "* return output_movedouble(operands, DImode);"
-  [(set_attr "length" "4")])
+  [(set_attr "length" "4")
+   (set_attr "type" "move,load,store,move,load,store,load")])
+
 
 (define_expand "movdi"
   [(set (match_operand:DI 0 "general_operand" "")
        (match_operand:DF 1 "arith_reg_operand" "r"))]
    ""
    "mov.l      %R1,%0\;mov.l   %1,%0"
-   [(set_attr "length" "4")])
+   [(set_attr "length" "4")
+    (set_attr "type" "store")])
 
 (define_insn "movdf_pcrel"
   [(set (match_operand:DF 0 "arith_reg_operand" "=r")
    (set_attr "constneed" "yes")
    (set_attr "smallestsize" "4")
    (set_attr "constantsize" "8")
-   (set_attr "largestsize" "18")])
+   (set_attr "largestsize" "18")
+   (set_attr "type" "load")])
 
 (define_insn "movdf_k"
   [(set (match_operand:DF 0 "general_operand" "=r,r,m")
        (match_operand:DF 1 "general_operand" "r,m,r"))]
   ""
   "* return output_movedouble(operands, DFmode);"
-  [(set_attr "length" "4")])
+  [(set_attr "length" "4")
+   (set_attr "type" "move,load,store")])
 
 (define_expand "movdf"
   [(set (match_operand:DF 0 "general_operand" "")
   [(set (match_operand:SF 0 "push_operand" "=<")
        (match_operand:SF 1 "arith_reg_operand" "r"))]
    ""
-   "mov.l      %1,%0")
+   "mov.l      %1,%0"
+  [(set_attr "type" "store")])
 
 (define_insn "movsf_pcrel"
   [(set (match_operand:SF 0 "arith_reg_operand" "=r")
    (set_attr "in_delay_slot" "no")
    (set_attr "constneed" "yes")
    (set_attr "smallestsize" "2")
-   (set_attr "largestsize" "8")])
+   (set_attr "largestsize" "8")
+   (set_attr "type" "load")])
                
 (define_insn "movsf_i"
   [(set (match_operand:SF 0 "general_operand" "=r,r,r,m,l,r,m,r")
        mov     %1,%0
        mov.l   %1,%0
        mov.l   %1,%0
+       lds     %1,%0
+       sts     %1,%0
        mov     %1,%0
-       mov     %1,%0
-       mov     %1,%0
-       mov     %1,%0")
+       mov     %1,%0"
+  [(set_attr "type" "move,move,load,store,move,move,move,move")])
 
 (define_expand "movsf"
   [(set (match_operand:SF 0 "general_operand" "")
   [(set (pc)
        (match_operand:SI 0 "arith_reg_operand" "r"))]
   ""
-  "jmp @%0"
+  "jmp @%0%#"
   [(set_attr "needs_delay_slot" "yes")
    (set_attr "in_delay_slot" "no")
    (set_attr "length" "4")])
    (set_attr "in_delay_slot" "no")
    (set_attr "type" "jump")
    (set_attr "dump" "no")])
+
+(define_insn "return"
+ [(return)]
+ "reload_completed"
+ "rts  %#"
+ [(set_attr "type" "return")
+  (set_attr "needs_delay_slot" "yes")
+  (set_attr "dump" "yes")])
+
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  "sh_expand_prologue (); DONE;")
+
+(define_expand "epilogue"
+  [(return)]
+  ""
+  "sh_expand_epilogue ();")
+
+(define_insn "blockage"
+  [(unspec_volatile [(const_int 0)] 0)]
+  ""
+  ""
+  [(set_attr "length" "0")])
+
 \f
 ;; ------------------------------------------------------------------------
 ;; Scc instructions
   ""
   "operands[1] = prepare_scc_operands (EQ);")
 
+; these patterns give better code then gcc invents if
+; left to its own devices
+
 (define_insn "anddi3"
   [(set (match_operand:DI 0 "arith_reg_operand" "=r")
        (and:DI (match_operand:DI 1 "arith_reg_operand" "%0")
   ""
   "
 {
-  rtx src_ptr = copy_to_mode_reg(Pmode,XEXP(operands[1], 0));
-  rtx dst_ptr = copy_to_mode_reg(Pmode,XEXP(operands[0], 0));
-  int maxsize = GET_CODE (operands[2]) == CONST_INT    
-       ? MAX (INTVAL (operands[2]), INTVAL (operands[3])) : 1;
-  enum machine_mode mode = 
-     (maxsize >= 4) ? SImode :
-       (maxsize >= 2) ? HImode :
-         QImode;
-
-  rtx tmpreg = gen_reg_rtx(mode);
-  rtx increment =  GEN_INT(GET_MODE_SIZE(mode));
-  rtx length = operands[2];
-  rtx label = gen_label_rtx();
-  rtx end_src_ptr = gen_reg_rtx(Pmode);
-
-  /* If done first rtl emmiting stage we can't generate a loop */
-  /*  if    (!rtx_equal_function_value_matters)
-      FAIL;*/
-  
-  if (GET_CODE (length) != CONST_INT)
-    length = convert_to_mode (Pmode, length, 1);
-
-  if (!arith_operand (length, SImode))
-       length = force_reg (SImode, length);
-       
-  emit_insn(gen_rtx(SET,
-                   VOIDmode, 
-                   end_src_ptr,
-                   gen_rtx(PLUS, Pmode, src_ptr, length)));
-
-
-  emit_label(label);
-  emit_move_insn(tmpreg, gen_rtx(MEM, mode, src_ptr));
-
-
-  emit_insn(gen_rtx(SET,
-                   VOIDmode,
-                   src_ptr,
-                   gen_rtx(PLUS, Pmode, src_ptr, increment)));
-
-  emit_move_insn(gen_rtx(MEM, mode, dst_ptr), tmpreg);
-
-  emit_insn(gen_rtx(SET, 
-                   VOIDmode,
-                   dst_ptr,
-                   gen_rtx(PLUS, Pmode, dst_ptr, increment)));
-
-  sh_compare_op0 = src_ptr;
-  sh_compare_op1 = end_src_ptr;
-  
-  emit_insn(gen_cmpeqsi_t(src_ptr, end_src_ptr));
-  emit_jump_insn(gen_bne(label));
-  emit_insn(gen_rtx(SET, VOIDmode, dst_ptr, dst_ptr));
-  
-  DONE;        
-}
-")
+  rtx dest_mem = operands[0];
+  rtx src_mem = operands[1];
+  operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
+  operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
+  expand_block_move (dest_mem, src_mem, operands);
+  DONE;
+}")
 
 
 
   "REGNO(operands[1]) != REGNO(operands[0])"
   "mov.l       @%1+,%0")
 
+(define_peephole
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (match_operand:QI 1 "general_operand" "g"))
+   (set (match_operand:SI 2 "register_operand" "=r")
+       (sign_extend:SI (match_dup 0)))]
+  "REGNO(operands[0]) == REGNO(operands[2])"
+  "mov.b       %1,%0")
+
+(define_peephole 
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (match_operand:QI 1 "general_operand" "g"))
+   (set (match_operand:SI 2 "register_operand" "=r")
+       (sign_extend:SI (match_dup 0)))]
+  "REGNO(operands[0]) != REGNO(operands[2]) 
+   && dead_or_set_p (insn, operands[0])"
+  "mov.b       %1,%2")
+
+; notice when a mov.b could be done with a displacement
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_dup 0)
+                (match_operand:SI 1 "byte_index_operand" "i")))
+   (set (mem:QI (match_dup 0)) (reg:QI 0))]
+  "dead_or_set_p(insn, operands[0])"
+  "mov.b       r0,@(%O1,%0)")
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_dup 0)
+                (match_operand:SI 1 "byte_index_operand" "i")))
+   (set (reg:QI 0) (mem:QI (match_dup 0)))]
+  "dead_or_set_p(insn, operands[0])"
+  "mov.b       @(%O1,%0),r0")
+  
+
+
 
index 924edd0..468ad98 100644 (file)
@@ -1,15 +1,5 @@
 LIBGCC1 = libgcc1.null
-T_CFLAGS = -DDONT_HAVE_STDIO -DDONT_HAVE_SETJMP  -Dinhibit_libc
-LIBGCC2_CFLAGS=-g -fno-omit-frame-pointer -O2 $(GCC_CFLAGS) 
-
-# These are really part of libgcc1, but this will cause them to be
-# built correctly, so... [taken from t-ose68k]
-LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
-dp-bit.c: $(srcdir)/config/fp-bit.c
-       cat $(srcdir)/config/fp-bit.c >> dp-bit.c
-
-fp-bit.c: $(srcdir)/config/fp-bit.c
-       echo '#define FLOAT' > fp-bit.c
-       cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+T_CFLAGS = -DDONT_HAVE_STDIO -DDONT_HAVE_SETJMP  -Dinhibit_libc 
+LIBGCC2_CFLAGS=-g -O5 $(GCC_CFLAGS) 
 
 
index 8c422b8..148ff57 100644 (file)
@@ -1,6 +1,6 @@
 /* Configuration for GNU C-compiler for Hitachi SH.
    Copyright (C) 1993 Free Software Foundation, Inc.
-   This file is part of GNU CC.
+This file is part of GNU CC.
 
 GNU CC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -26,6 +26,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define HOST_BITS_PER_INT 32
 #define HOST_BITS_PER_LONG 32
 
+/* If compiled with GNU C, use the built-in alloca.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#endif
+
 /* target machine dependencies.
    tm.h is a symbolic link to the actual target specific file.  */
 #include "tm.h"