*** empty log message ***
authorsac <sac@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 22 Jul 1994 06:12:36 +0000 (06:12 +0000)
committersac <sac@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 22 Jul 1994 06:12:36 +0000 (06:12 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@7790 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md

index 5999f8a..28d0d4b 100644 (file)
@@ -65,12 +65,12 @@ rtx sh_compare_op1;
 
 int regno_reg_class[FIRST_PSEUDO_REGISTER] =
 {
-  R0_REGS,      GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+  R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
-  GENERAL_REGS, PR_REGS,      T_REGS,       NO_REGS, 
-  MAC_REGS,     MAC_REGS,
+  GENERAL_REGS, PR_REGS, T_REGS, NO_REGS,
+  MAC_REGS, MAC_REGS,
 };
 
 /* Provide reg_class from a letter such as appears in the machine
@@ -104,12 +104,12 @@ enum reg_class reg_class_from_letter[] =
 
 int hard_regno_mode_ok[] =
 {
-  REG_EVEN,   REG_ODD,   REG_EVEN,   REG_ODD,
-  REG_EVEN,   REG_ODD,   REG_EVEN,   REG_ODD,
-  REG_EVEN,   REG_ODD,   REG_EVEN,   REG_ODD,
-  REG_EVEN,   REG_ODD,   REG_EVEN,   REG_ODD,
-  REG,         0,        SI_ONLY,    SI_ONLY,
-  SI_ONLY,    SI_ONLY
+  REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
+  REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
+  REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
+  REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
+  REG, 0, SI_ONLY, SI_ONLY,
+  SI_ONLY, SI_ONLY
 };
 
 /* Local label counter, used for constants in the pool and inside
@@ -120,9 +120,9 @@ static int lf = 100;
 /* Number of bytes pushed for anonymous args, used to pass information
    between expand_prologue and expand_epilogue. */
 static int extra_push;
-
 \f
 
+
 void
 push (rn)
      int rn;
@@ -132,6 +132,7 @@ push (rn)
 
 void
 pop (rn)
+     int rn;
 {
   emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
 }
@@ -299,7 +300,6 @@ print_operand_address (stream, x)
 
          default:
            debug_rtx (x);
-
            abort ();
          }
       }
@@ -354,9 +354,9 @@ print_operand (stream, x, code)
       break;
     case '@':
       if (pragma_interrupt)
-       fprintf (stream,"rte");
+       fprintf (stream, "rte");
       else
-       fprintf (stream,"rts");
+       fprintf (stream, "rts");
       break;
     case '#':
       /* Output a nop if there's nothing in the delay slot */
@@ -405,7 +405,9 @@ print_operand (stream, x, code)
 }
 \f
 
+static int
 sextb (x)
+  int x;
 {
   x &= 0xff;
   if (x > 127)
@@ -420,7 +422,7 @@ sextb (x)
 /* Take a move with integer constant source in OPERANDS, see if it can be generated by
    devious shifting.  If so, generate the instruction sequence and return 1, otherwise
    return 0.
-   
+
     OPERANDS[0] Destination register
     OPERANDS[1] Source constant
 
@@ -442,7 +444,7 @@ sextb (x)
    00000000 00000000 11111111 1NNNNNNNN load and zero extend word
 
 
-*/   
+*/
 
 static int
 synth_constant (operands, mode)
@@ -452,7 +454,7 @@ synth_constant (operands, mode)
   rtx dst;
   int i = INTVAL (operands[1]) & 0xffffffff;
 
-  if (CONST_OK_FOR_I (i)) 
+  if (CONST_OK_FOR_I (i))
     return 0;
 
   if (TARGET_CLEN0 && mode != QImode)
@@ -460,11 +462,11 @@ synth_constant (operands, mode)
 
   if (mode != SImode)
     {
-      if (reload_in_progress) 
+      if (reload_in_progress)
        return 0;
       dst = gen_reg_rtx (SImode);
     }
-  else 
+  else
     {
       dst = operands[0];
     }
@@ -592,10 +594,8 @@ expand_block_move (operands)
     }
   if (mode == SImode && constp && (bytes % 4 == 0))
     {
-      char entry[30];
       tree entry_name;
       rtx func_addr_rtx;
-      int groups;
       rtx r4 = gen_rtx (REG, SImode, 4);
       rtx r5 = gen_rtx (REG, SImode, 5);
       rtx r6 = gen_rtx (REG, SImode, 6);
@@ -670,7 +670,7 @@ prepare_move_operands (operands, mode)
       /* copy the source to a register */
       operands[1] = copy_to_mode_reg (mode, operands[1]);
     }
-  if ((mode == DImode || mode == SImode || mode == HImode || mode == QImode) 
+  if ((mode == DImode || mode == SImode || mode == HImode || mode == QImode)
       && GET_CODE (operands[1]) == CONST_INT)
     {
       return synth_constant (operands, mode);
@@ -740,6 +740,7 @@ prepare_move_operands (operands, mode)
    compare has been done.  */
 rtx
 prepare_scc_operands (code)
+     int code;
 {
   if (GET_CODE (sh_compare_op0) != REG
       || REGNO (sh_compare_op0) != T_REG)
@@ -863,6 +864,10 @@ output_movedouble (insn, operands, mode)
        {
          return "mov.l %1,%0\n\tmov.l  %1+4,%R0";
        }
+      else if (GET_CODE (inside) == POST_INC)
+       {
+         return "mov.l %1,%0\n\tmov.l  %1,%R0 !mdi\n";
+       }
       else
        abort ();
 
@@ -1022,11 +1027,6 @@ output_far_jump (insn, op)
 {
   rtx thislab = gen_label_rtx ();
 
-  /* See if we can grab a reg from the prev insn */
-  rtx gotone = 0;
-  rtx prev = PREV_INSN (insn);
-  rtx link;
-
   if (dbr_sequence_length ())
     {
       /* Something to go in what would have been the delay
@@ -1041,7 +1041,8 @@ output_far_jump (insn, op)
       for (i = 0; i < 8; i++)
        {
          vec[1] = gen_rtx (REG, SImode, i);
-         if (!reg_referenced_p (vec[1], PATTERN (XVECEXP (final_sequence, 0, 1))))
+         if (!reg_referenced_p (vec[1],
+                                PATTERN (XVECEXP (final_sequence, 0, 1))))
            break;
        }
 
@@ -1072,9 +1073,8 @@ output_branch (logic, insn)
 {
   extern rtx recog_operand[];
   int label = lf++;
-  int rn = -1;
-  int need_save;
-/*  fprintf (asm_out_file, "! pc %04x\n", insn_addresses[INSN_UID (insn)]);*/
+
+  /*  fprintf (asm_out_file, "! pc %04x\n", insn_addresses[INSN_UID (insn)]);*/
 
   switch (get_attr_length (insn))
     {
@@ -1245,7 +1245,7 @@ add_constant (x, mode)
 
 /* Dump out interesting debug info */
 
-rtx
+void
 final_prescan_insn (insn, opvec, noperands)
      rtx insn;
      rtx *opvec;
@@ -1258,9 +1258,9 @@ final_prescan_insn (insn, opvec, noperands)
               insn_addresses[INSN_UID (insn)]);
     }
 }
+\f
 
 
-\f
 
 /* Stuff taken from m88k.c */
 
@@ -1365,7 +1365,7 @@ output_file_start (file, f_options, f_len, W_options, W_len)
   data_section ();
 
 
-  pos = fprintf (file, "\n! Hitachi SH cc1 (%s) (release D-1) arguments:", version_string);
+  pos = fprintf (file, "\n! Hitachi SH cc1 (%s) (release E-2) arguments:", version_string);
   output_options (file, f_options, f_len, W_options, W_len,
                  pos, 75, " ", "\n! ", "\n\n");
 }
@@ -1393,7 +1393,7 @@ shiftcosts (RTX)
   return 1;
 }
 
-int 
+int
 andcosts (RTX)
      rtx RTX;
 {
@@ -1410,28 +1410,33 @@ andcosts (RTX)
   return 5;
 }
 
-int howshift (i)
-int i;
+int 
+howshift (i)
+     int i;
 {
   int total = 0;
   while (i > 0)
     {
-      if (i >= 16) {
-       total++;
-       i -= 16;
-      }
-      else if (i >= 8) {
-       total++;
-       i -= 8;
-      }
-      else if (i >= 2) {
-       total++;
-       i -= 2;
-      }
-      else if (i>=1) {
-       total++;
-       i--;
-      }
+      if (i >= 16)
+       {
+         total++;
+         i -= 16;
+       }
+      else if (i >= 8)
+       {
+         total++;
+         i -= 8;
+       }
+      else if (i >= 2)
+       {
+         total++;
+         i -= 2;
+       }
+      else if (i >= 1)
+       {
+         total++;
+         i--;
+       }
     }
   return total;
 }
@@ -1442,14 +1447,14 @@ multcosts (RTX)
      rtx RTX;
 {
   /* If mult by a power of 2 then work out how we'd shift to make it */
-  int insn_cost;
-  
+  int insn_cost = 0;
+
   if (GET_CODE (XEXP (RTX, 1)) == CONST_INT)
     {
       int i = exact_log2 (INTVAL (XEXP (RTX, 1)));
-      if (i >= 0) 
+      if (i >= 0)
        insn_cost = howshift (i);
-      else 
+      else
        insn_cost = 100000;
     }
   if (TARGET_SH2)
@@ -1458,7 +1463,7 @@ multcosts (RTX)
         read of the mac reg, but count more because of the latency and extra reg
         usage */
       if (TARGET_SMALLCODE)
-         return 2;
+       return 2;
       if (insn_cost > 5)
        return 5;
       return insn_cost;
@@ -1467,7 +1472,7 @@ multcosts (RTX)
   /* If we we're aiming at small code, then just count the number of
      insns in a multiply call sequence */
 
-  if (TARGET_SMALLCODE) 
+  if (TARGET_SMALLCODE)
     {
       if (insn_cost > 6)
        return 6;
@@ -1627,7 +1632,6 @@ dump_table (scan)
      rtx scan;
 {
   int i;
-  int pass;
   int need_align = 1;
 
 
@@ -1706,6 +1710,10 @@ fixit (src, mode)
     {
       return 1;
     }
+  if (GET_CODE (src) == LABEL_REF)
+    {
+      return 1;
+    }
   if (GET_CODE (src) == CONST_INT)
     {
       /* All QI insns are ok */
@@ -1740,17 +1748,18 @@ hi_const (src)
 /* Find the last barrier less than MAX_COUNT bytes from FROM, or create one.
    If an HI move is found, then make sure that MAX_COUNT_HI isn't broken from that one. */
 
+static rtx from;
 static
 rtx
-find_barrier (from)
-     rtx from;
+find_barrier (from_)
+     rtx from_;
 {
   int count_si = 0;
   int count_hi = 0;
   int found_hi = 0;
   int found_si = 0;
   rtx found_barrier = 0;
-
+from = from_;
   while (from
         && count_si < max_count_si
         && count_hi < max_count_hi)
@@ -1786,11 +1795,14 @@ find_barrier (from)
 
   if (!found_barrier)
     {
-      /* Insert a jump around the barrier here */
+      /* We didn't find a barrier in time to 
+        dump our stuff, so we'll make one */
       rtx label = gen_label_rtx ();
       /* Walk back to be just before any jump */
+         from = PREV_INSN (from);
       while (GET_CODE (from) == JUMP_INSN
-            || GET_CODE (from) == NOTE)
+            || GET_CODE (from) == NOTE
+            || GET_CODE (from) == CODE_LABEL)
        {
          from = PREV_INSN (from);
        }
@@ -1836,7 +1848,6 @@ machine_dependent_reorg (first)
      rtx first;
 {
   rtx insn;
-  int limit;
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       if (broken_move (insn))
@@ -1895,7 +1906,7 @@ machine_dependent_reorg (first)
 
 /* Called from the md file, set up the operands of a compare instruction */
 
-int
+void
 from_compare (operands, code)
      rtx *operands;
      int code;
@@ -1905,7 +1916,7 @@ from_compare (operands, code)
       /* Force args into regs, since we can't use constants here */
       sh_compare_op0 = force_reg (SImode, sh_compare_op0);
       if (sh_compare_op1 != const0_rtx)
-       sh_compare_op1 = force_reg (SImode, sh_compare_op1);    
+       sh_compare_op1 = force_reg (SImode, sh_compare_op1);
     }
   operands[1] = sh_compare_op0;
   operands[2] = sh_compare_op1;
@@ -1923,33 +1934,67 @@ equality_operator (x, mode)
 }
 
 
-/* Framefull frame looks like:
-
-   arg-5
-   arg-4
-   [ if current_function_anonymous_args
-   arg-3
-   arg-2
-   arg-1
-   arg-0 ]
-   saved-fp
-   saved-r10
-   saved-r11
-   saved-r12
-   saved-pr
-   local-n
-   ..
-   local-1
-   local-0        <- fp points here
+/* Add this function to the list of ones seen - temporary
+   gross hack to try out bsrs. */
+struct flist
+{
+  char *name;
+  struct flist *next;
+};
+struct flist *head;
 
+static void
+add_function (name)
+     char *name;
+{
+  struct flist *n = (struct flist *) xmalloc (sizeof (struct flist));
+  int l = strlen (name) + 1;
+  n->name = xmalloc (l);
+  memcpy (n->name, name, l);
+  n->next = head;
+  head = n;
+}
 
-   If TARGET_SMALLCALL, then the preserved registers are pushed by a
-   wrapper before the routine is entered, so the regs are always pushed
-   and there are two pr's on the stack - the caller and the wrapper.
- */
+static int
+seen_function (name)
+     char *name;
+{
+  struct flist *p = head;
+  for (p = head; p; p = p->next)
+    {
+      if (strcmp (p->name, name) == 0)
+       return 1;
+    }
+  return 0;
+}
+
+ /* Framefull frame looks like:
+
+    arg-5
+    arg-4
+    [ if current_function_anonymous_args
+    arg-3
+    arg-2
+    arg-1
+    arg-0 ]
+    saved-fp
+    saved-r10
+    saved-r11
+    saved-r12
+    saved-pr
+    local-n
+    ..
+    local-1
+    local-0        <- fp points here
 
 
-/* Code to generate prologue and epilogue sequences */
+    If TARGET_SMALLCALL, then the preserved registers are pushed by a
+    wrapper before the routine is entered, so the regs are always pushed
+    and there are two pr's on the stack - the caller and the wrapper.
+  */
+
+
+ /* Code to generate prologue and epilogue sequences */
 
 
 void
@@ -1957,7 +2002,7 @@ sh_expand_prologue ()
 {
   int live_regs_mask;
   int d;
-
+  extern tree current_function_decl;
   live_regs_mask = calc_live_regs (&d);
 
   /* We have pretend args if we had an object sent partially in registers
@@ -1984,6 +2029,12 @@ sh_expand_prologue ()
     {
       emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
     }
+  if (TARGET_BSR)
+    {
+      add_function (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
+    }
+
+
 }
 
 void
@@ -2027,11 +2078,14 @@ sh_expand_epilogue ()
 
 int
 initial_elimination_offset (from, to)
+     int from;
+     int to;
 {
   int regs_saved;
-  int regs_saved_mask = calc_live_regs (&regs_saved);
   int total_saved_regs_space;
   int total_auto_space = get_frame_size ();
+
+  calc_live_regs (&regs_saved);
   total_saved_regs_space = (regs_saved) * 4;
 
   if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
@@ -2074,12 +2128,12 @@ handle_pragma (file)
       if (psize == 9 && strncmp (pbuf, "interrupt", 9) == 0)
        {
          pragma_interrupt = 1;
-         return;
+         return c;
        }
       if (psize == 5 && strncmp (pbuf, "trapa", 5) == 0)
        {
          pragma_interrupt = pragma_trapa = 1;
-         return;
+         return c;
        }
       c = getc (file);
     }
@@ -2088,7 +2142,7 @@ handle_pragma (file)
 \f
 /* insn expand helpers */
 
-/* Emit insns to perform a call. 
+/* Emit insns to perform a call.
    If TARGET_SHORTADDR then use a bsr. If TARGET_SMALLCALL, then load the
    target address into r1 and call __saveargs, otherwise
    perform the standard call sequence */
@@ -2103,29 +2157,29 @@ expand_acall (isa_retval, operands)
   rtx call_target = operands[isa_retval + 0];
   rtx numargs = operands[isa_retval + 1];
 
-  if (TARGET_BSR)
+  if (TARGET_BSR && bsr_operand (call_target, VOIDmode))
     {
       call = gen_rtx (CALL, VOIDmode, call_target, numargs);
     }
-  else {
-
-    if (GET_CODE (call_target) == MEM)
-      {
-       call_target = force_reg (Pmode,
-                                XEXP (call_target, 0));
-      }
-    if (TARGET_SMALLCALL)
-      {
-       rtx tmp = gen_reg_rtx (SImode);
-       rtx r1 = gen_rtx (REG, SImode, 1);
-       emit_move_insn (tmp, gen_rtx (SYMBOL_REF, SImode, "__saveargs"));
-       emit_move_insn (r1, call_target);
-       emit_insn (gen_rtx (USE, VOIDmode, r1));
-       call_target = tmp;
-      }
+  else
+    {
+      if (GET_CODE (call_target) == MEM)
+       {
+         call_target = force_reg (Pmode,
+                                  XEXP (call_target, 0));
+       }
+      if (TARGET_SMALLCALL)
+       {
+         rtx tmp = gen_reg_rtx (SImode);
+         rtx r1 = gen_rtx (REG, SImode, 1);
+         emit_move_insn (tmp, gen_rtx (SYMBOL_REF, SImode, "__saveargs"));
+         emit_move_insn (r1, call_target);
+         emit_insn (gen_rtx (USE, VOIDmode, r1));
+         call_target = tmp;
+       }
 
-    call = gen_rtx (CALL, VOIDmode, gen_rtx (MEM, SImode, call_target), numargs);
-  }
+      call = gen_rtx (CALL, VOIDmode, gen_rtx (MEM, SImode, call_target), numargs);
+    }
   if (isa_retval)
     {
       call = gen_rtx (SET, VOIDmode, ret, call);
@@ -2134,7 +2188,7 @@ expand_acall (isa_retval, operands)
   emit_call_insn (gen_rtx (PARALLEL, VOIDmode,
                           gen_rtvec (2,
                                      call,
-                                     gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 17)))));
+                 gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 17)))));
 
 }
 \f
@@ -2156,10 +2210,18 @@ general_movsrc_operand (op, mode)
       GET_CODE (XEXP (op, 0)) == LABEL_REF)
     return 1;
 
-  /* No predec allowed */
+  /* No post inc allowed */
 
   if (GET_CODE (op) == MEM
-      && GET_CODE (XEXP (op, 0)) == PRE_DEC)
+      && (GET_CODE (XEXP (op, 0)) == POST_DEC
+         || GET_CODE (XEXP (op, 0)) == PRE_INC
+         || GET_CODE (XEXP (op, 0)) == PRE_DEC))
+    return 0;
+
+  /* Can't do that with large modes */
+  if (GET_CODE (op) == MEM
+      && GET_CODE (XEXP (op, 0)) == POST_INC
+      && GET_MODE_SIZE (mode) > 4)
     return 0;
 
   if ((mode == QImode || mode == HImode)
@@ -2185,12 +2247,18 @@ general_movdst_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
+  /* No pre dec allowed */
   if (GET_CODE (op) == MEM
       && (GET_CODE (XEXP (op, 0)) == PRE_INC
          || GET_CODE (XEXP (op, 0)) == POST_INC
          || GET_CODE (XEXP (op, 0)) == POST_DEC))
     return 0;
 
+  if (GET_CODE (op) == MEM
+      && GET_CODE (XEXP (op, 0)) == PRE_DEC
+      && GET_MODE_SIZE (mode) > 4)
+    return 0;
+
   return general_operand (op, mode);
 }
 
@@ -2200,11 +2268,19 @@ general_movdst_operand (op, mode)
 
 int
 bsr_operand (op, mode)
-rtx op;
-enum machine_mode mode;
+     rtx op;
+     enum machine_mode mode;
 {
-  if (GET_CODE (op) == SYMBOL_REF)
-    return 1;
+  if (TARGET_BSR)
+    {
+      if (GET_CODE (op) == SYMBOL_REF)
+       {
+         if (!strcmp (XSTR (op, 0),
+                     IDENTIFIER_POINTER (DECL_NAME (current_function_decl))))
+           return 1;
+         return (seen_function (XSTR (op, 0)));
+       }
+    }
   return 0;
 }
 
@@ -2329,7 +2405,7 @@ mac_operand (op, mode)
   if (arith_reg_operand (op, mode))
     return 1;
 #if 0
-  Turned off till mac is understood 
+  Turned off till mac is understood
   if (GET_CODE (op) == MEM)
     return 1;
 #endif
@@ -2349,27 +2425,27 @@ mac_operand (op, mode)
    NAMED is nonzero if this argument is a named parameter
     (otherwise it is an extra parameter matching an ellipsis).  */
 
-rtx 
+rtx
 sh_function_arg (cum, mode, type, named)
-CUMULATIVE_ARGS cum;
-enum machine_mode mode;
-tree type;
-int named;
+     CUMULATIVE_ARGS cum;
+     enum machine_mode mode;
+     tree type;
+     int named;
 {
   if (named)
     {
-      int rr =  (ROUND_REG ((cum), (mode)));
+      int rr = (ROUND_REG ((cum), (mode)));
 
       if (rr < NPARM_REGS)
        {
-         return ((((mode) != BLKmode                                   
-                   && ((type)==0 || ! TREE_ADDRESSABLE ((tree)(type))) 
-                   && ((type)==0 || (mode) != BLKmode                  
-                       || (TYPE_ALIGN ((type)) % PARM_BOUNDARY == 0))  
-                   ? gen_rtx (REG, (mode),                             
-                              (FIRST_PARM_REG + rr)): 0)));
+         return ((((mode) != BLKmode
+                   && ((type) == 0 || !TREE_ADDRESSABLE ((tree) (type)))
+                   && ((type) == 0 || (mode) != BLKmode
+                       || (TYPE_ALIGN ((type)) % PARM_BOUNDARY == 0))
+                   ? gen_rtx (REG, (mode),
+                              (FIRST_PARM_REG + rr)) : 0)));
 
-       }               
+       }
     }
   return 0;
 }
@@ -2387,18 +2463,17 @@ sh_function_arg_partial_nregs (CUM, MODE, TYPE, NAMED)
      tree TYPE;
      int NAMED;
 {
-  if ((CUM) < NPARM_REGS)                                                      
-    {
-      if (((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE)))                     
-         && ((TYPE)==0 || (MODE) != BLKmode                                    
-             || (TYPE_ALIGN ((TYPE)) % PARM_BOUNDARY == 0))                    
-         && ((CUM) + ((MODE) == BLKmode                                        
-                      ? ROUND_ADVANCE (int_size_in_bytes (TYPE))               
-                      : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) - NPARM_REGS > 0))
+  if ((CUM) < NPARM_REGS)
+    {
+      if (((TYPE) == 0 || !TREE_ADDRESSABLE ((tree) (TYPE)))
+         && ((TYPE) == 0 || (MODE) != BLKmode
+             || (TYPE_ALIGN ((TYPE)) % PARM_BOUNDARY == 0))
+         && ((CUM) + ((MODE) == BLKmode
+                      ? ROUND_ADVANCE (int_size_in_bytes (TYPE))
+                 : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) - NPARM_REGS > 0))
        {
          return NPARM_REGS - CUM;
        }
     }
   return 0;
 }
-
index 23259cb..aafa931 100644 (file)
@@ -1,4 +1,5 @@
-/* Definitions of target machine for GNU compiler, for Hitachi Super-H.
+/* Definitions of target machine for GNU compiler, 
+   for Hitachi Super-H.
    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
 
    Contributed by Steve Chamberlain (sac@cygnus.com)
@@ -83,6 +84,7 @@ extern int target_flags;
 #define CONSTLEN_0_BIT  (1<<25)
 #define BSR_BIT        (1<<26)
 #define SHORTADDR_BIT   (1<<27)
+#define PACKSTRUCT_BIT  (1<<28)
 
 /* Nonzero if we should generate code using type 0 insns */
 #define TARGET_SH0 (target_flags & SH0_BIT)
@@ -141,11 +143,14 @@ extern int target_flags;
 
 /* Nonzero if using Hitachi's calling convention */
 #define TARGET_HITACHI                 (target_flags & HITACHI_BIT)
+
 #define TARGET_PARANOID        (target_flags & PARANOID_BIT)
 #define TARGET_RETR2           (target_flags & RETR2_BIT)
 #define TARGET_SHORTADDR       (target_flags & SHORTADDR_BIT)
 #define TARGET_BSR             (target_flags & BSR_BIT)
 
+/* Nonzero if packing structures as small as they'll go (incompatible with Hitachi's compiler) */
+#define TARGET_PACKSTRUCT       (target_flags & PACKSTRUCT_BIT)
 
 #define TARGET_SWITCHES                \
 { {"isize",    ( ISIZE_BIT) },         \
@@ -170,10 +175,11 @@ extern int target_flags;
   {"r2",       ( RETR2_BIT) },         \
   {"shortaddr", ( SHORTADDR_BIT) },     \
   {"bsr",       ( BSR_BIT) },          \
+  {"packstruct",( PACKSTRUCT_BIT) },    \
   {"",         TARGET_DEFAULT}         \
 }
 
-#define TARGET_DEFAULT  (FAST_BIT)
+#define TARGET_DEFAULT  (FAST_BIT | BIGTABLE_BIT)
 
 /* Macro to define table for command options with values.  */
 #define TARGET_OPTIONS \
@@ -206,7 +212,7 @@ do {                                                                \
   if (max_hi)                                                  \
     max_count_hi = atoi (max_hi);                              \
   else                                                         \
-    max_count_hi = 505;                                                \
+    max_count_hi = 500;                                                \
   if (TARGET_BSR)                                               \
      flag_no_function_cse = 1;                                  \
 } while (0)
@@ -264,9 +270,6 @@ do {                                                                \
 /* The best alignment to use in cases where we have a choice.  */
 #define FASTEST_ALIGNMENT 32
 
-/* Every structures size must be a multiple of 32 bits.  */
-#define STRUCTURE_SIZE_BOUNDARY 32
-
 /* Make strings word-aligned so strcpy from constants will be faster.  */
 #define CONSTANT_ALIGNMENT(EXP, ALIGN)  \
   ((TREE_CODE (EXP) == STRING_CST      \
@@ -279,6 +282,11 @@ do {                                                               \
    && TYPE_MODE (TREE_TYPE (TYPE)) == QImode   \
    && (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN))
 
+/* Number of bits which any structure or union's size must be a
+   multiple of.  Each structure or union's size is rounded up to a
+   multiple of this. */
+#define STRUCTURE_SIZE_BOUNDARY (TARGET_PACKSTRUCT ? 8 : 32)
+
 /* Set this nonzero if move instructions will actually fail to work
    when given unaligned data.  */
 #define STRICT_ALIGNMENT 1
@@ -305,9 +313,7 @@ do {                                                                \
    The hardware registers are assigned numbers for the compiler
    from 0 to just below FIRST_PSEUDO_REGISTER.
    All registers that the compiler knows about must be given numbers,
-   even those that are not normally considered general registers.
-
-*/
+   even those that are not normally considered general registers. */
 
 #define AP_REG   16  
 #define PR_REG   17
@@ -867,7 +873,7 @@ extern int current_function_anonymous_args;
 /* Nonzero if the constant value X is a legitimate general operand. */
 
 #define LEGITIMATE_CONSTANT_P(X) \
-  (GET_CODE(X) != CONST_DOUBLE && GET_CODE(X) != LABEL_REF)
+  (GET_CODE(X) != CONST_DOUBLE /*&& GET_CODE(X) != LABEL_REF*/)
 
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
@@ -877,9 +883,9 @@ extern int current_function_anonymous_args;
    them unless they have been allocated suitable hard regs.
    The symbol REG_OK_STRICT causes the latter definition to be used.  */
 
-#define MODE_DISP_OK_4(X,MODE) ((GET_MODE_SIZE(MODE)==4) && ((unsigned)INTVAL(X)<64))
-#define MODE_DISP_OK_8(X,MODE) ((GET_MODE_SIZE(MODE)==8) && ((unsigned)INTVAL(X)<60))
-#define MODE_DISP_OK_2(X,MODE) ((GET_MODE_SIZE(MODE)==2) && ((unsigned)INTVAL(X)<32) && TARGET_TRYR0)
+#define MODE_DISP_OK_4(X,MODE) ((GET_MODE_SIZE(MODE)==4) && ((unsigned)INTVAL(X)<64) && (!(INTVAL(X) &3)))
+#define MODE_DISP_OK_8(X,MODE) ((GET_MODE_SIZE(MODE)==8) && ((unsigned)INTVAL(X)<60) && (!(INTVAL(X) &3)))
+#define MODE_DISP_OK_2(X,MODE) ((GET_MODE_SIZE(MODE)==2) && ((unsigned)INTVAL(X)<32) && TARGET_TRYR0 && (!INTVAL(X) &1))
 #define MODE_DISP_OK_1(X,MODE) ((GET_MODE_SIZE(MODE)==1) && ((unsigned)INTVAL(X)<16) && TARGET_TRYR0)
 
 #ifndef REG_OK_STRICT
@@ -896,7 +902,7 @@ extern int current_function_anonymous_args;
   (REGNO (X) == 0 || REGNO(X) >= FIRST_PSEUDO_REGISTER)
 
 #define REG_OK_FOR_PRE_POST_P(X) \
-       (REG_OK_FOR_INDEX_P (X))
+       (REG_OK_FOR_BASE_P (X))
 
 #else
 /* Nonzero if X is a hard reg that can be used as a base reg.  */
@@ -908,7 +914,7 @@ extern int current_function_anonymous_args;
        REGNO_OK_FOR_INDEX_P (REGNO (X))
 
 #define REG_OK_FOR_PRE_POST_P(X)  \
-       (REGNO_OK_FOR_INDEX_P (REGNO (X)))
+       (REGNO_OK_FOR_BASE_P (REGNO (X)))
 #endif
 
 /* The Q is a pc relative load operand */
@@ -1039,7 +1045,7 @@ extern int current_function_anonymous_args;
 /* Define this if the tablejump instruction expects the table
    to contain offsets from the address of the table.
    Do not define this if the table should contain absolute addresses.  */
-#define CASE_VECTOR_PC_RELATIVE 
+/*#define CASE_VECTOR_PC_RELATIVE */
 
 /* Specify the tree operation to be used to convert reals to integers.  */
 #define IMPLICIT_FIX_EXPR  FIX_ROUND_EXPR
@@ -1053,6 +1059,9 @@ extern int current_function_anonymous_args;
 /* The type of size_t unsigned int.  */
 #define SIZE_TYPE "unsigned int"
 
+#define WCHAR_TYPE "short unsigned int"
+#define WCHAR_TYPE_SIZE 16
+
 /* Don't cse the address of the function being compiled.  */
 /*#define NO_RECURSIVE_FUNCTION_CSE 1*/
 
@@ -1195,13 +1204,14 @@ extern int current_function_anonymous_args;
 
 /* How to change between sections. */
 
-#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 INIT_SECTION_ASM_OP    "\t.section\t.init\n"
-#define EXTRA_SECTIONS                 in_ctors, in_dtors
-
+#define TEXT_SECTION_ASM_OP            "\t.text"
+#define DATA_SECTION_ASM_OP            "\t.data"
+#define READONLY_DATA_SECTION_ASM_OP   "\t.section\t.rdata\n"
+#define CTORS_SECTION_ASM_OP           "\t.section\t.ctors\n"
+#define DTORS_SECTION_ASM_OP           "\t.section\t.dtors\n"
+#define INIT_SECTION_ASM_OP            "\t.section\t.init\n"
+#define EXTRA_SECTIONS                         in_ctors, in_dtors, in_rdata
+#define READONLY_DATA_SECTION          rdata_section
 #define EXTRA_SECTION_FUNCTIONS                              \
 void                                                        \
 ctors_section()                                             \
@@ -1220,6 +1230,15 @@ dtors_section()                                       \
       fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP);  \
       in_section = in_dtors;                                \
     }                                                       \
+}                                                            \
+void                                                        \
+rdata_section()                                             \
+{                                                           \
+  if (in_section != in_rdata)                               \
+    {                                                       \
+      fprintf (asm_out_file, "%s\n", READONLY_DATA_SECTION_ASM_OP);  \
+      in_section = in_rdata;                                \
+    }                                                       \
 }                                                            
 
 /* Assemble generic sections.
@@ -1462,7 +1481,7 @@ extern char *output_far_jump();
 
 #define TARGET_MEM_FUNCTIONS
 
-#define HANDLE_PRAGMA(finput) handle_pragma (finput)
+#define HANDLE_PRAGMA(finput) return handle_pragma (finput)
 
 /* Set when processing a function with pragma interrupt turned on. */
 
index 794fe45..397fc0f 100644 (file)
   (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" "pcloadsi") (const_string "no")
+        (eq_attr "type" "pcloadhi") (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")))
 
+
 \f
 ;; -------------------------------------------------------------------------
 ;; SImode signed integer comparisons
 ;; Addition instructions
 ;; -------------------------------------------------------------------------
 
-(define_insn "addc"
-  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-       (plus:SI (reg:SI 18)
-                (plus:SI (match_operand:SI 1 "arith_reg_operand" "%0")
-                         (match_operand:SI 2 "arith_reg_operand" "r"))))
-   (set (reg:SI 18) (gt:SI (match_dup 1) (match_dup 0)))]
-  ""
-  "addc        %2,%0")
 
 
 ;; this should be a define split.
 
+
+
+(define_insn "addc"
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
+       (plus:SI (match_dup 0)
+                (plus:SI (match_operand:SI 1 "arith_reg_operand" "r")
+                         (reg:SI 18))))
+   (clobber (reg:SI 18))]
+  ""
+  "addc        %1,%0")
+
 (define_expand "adddi3"
   [(set (match_operand:DI 0 "register_operand" "")
        (plus:DI (match_operand:DI 1 "register_operand" "")
   ""
   "
 {
-  rtx low_a = gen_rtx (SUBREG, SImode, operands[1], 1);
-  rtx low_b = gen_rtx (SUBREG, SImode, operands[2], 1);
-  rtx low_s = gen_rtx (SUBREG, SImode, operands[0], 1);
+  rtx low_a = operand_subword (operands[1], 1, 1, DImode);
+  rtx low_b = operand_subword (operands[2], 1, 1, DImode);
+  rtx low_s = operand_subword (operands[0], 1, 1, DImode);
 
-  rtx high_a = gen_rtx (SUBREG, SImode, operands[1], 0);
-  rtx high_b = gen_rtx (SUBREG, SImode, operands[2], 0);
-  rtx high_s = gen_rtx (SUBREG, SImode, operands[0], 0);
+  rtx high_a = operand_subword (operands[1], 0, 1, DImode);
+  rtx high_b = operand_subword (operands[2], 0, 1, DImode);
+  rtx high_s = operand_subword (operands[0], 0, 1, DImode);
 
   emit_insn (gen_clrt ());
-  emit_insn (gen_addc (low_s, low_a, low_b));
-  emit_insn (gen_addc (high_s, high_a, high_b));
+
+  emit_move_insn (low_s, low_a);
+  emit_insn (gen_addc (low_s, low_b));
+  emit_move_insn (high_s, high_a);
+  emit_insn (gen_addc (high_s, high_b));
 
   DONE;
 }")
 ;; Subtraction instructions
 ;; -------------------------------------------------------------------------
 
-(define_insn "subdi3"
-  [(set (match_operand:DI 0 "arith_reg_operand" "=r")
-       (minus:DI (match_operand:DI 1 "arith_reg_operand" "0")
-                 (match_operand:DI 2 "arith_reg_operand" "r")))
+
+(define_insn "subc"
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
+       (minus:SI (match_operand:SI 1 "arith_reg_operand" "%0")
+                 (plus:SI  (match_operand:SI 2 "arith_reg_operand" "r")
+                           (reg:SI 18))))
    (clobber (reg:SI 18))]
   ""
-  "clrt\;subc  %R2,%R0\;subc   %2,%0"
-  [(set_attr "length" "6")
-   (set_attr "in_delay_slot" "no")
-   (set_attr "type" "arith")])
+  "subc        %2,%0")
+
+(define_expand "subdi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (plus:DI (match_operand:DI 1 "register_operand" "")
+                (match_operand:DI 2 "register_operand" "")))]
+  ""
+  "
+{
+  rtx low_a = operand_subword (operands[1], 1, 1, DImode);
+  rtx low_b = operand_subword (operands[2], 1, 1, DImode);
+  rtx low_s = operand_subword (operands[0], 1, 1, DImode);
+
+  rtx high_a = operand_subword (operands[1], 0, 1, DImode);
+  rtx high_b = operand_subword (operands[2], 0, 1, DImode);
+  rtx high_s = operand_subword (operands[0], 0, 1, DImode);
+
+  emit_insn (gen_clrt ());
+  emit_insn (gen_subc (low_s, low_a, low_b));
+  emit_insn (gen_subc (high_s, high_a, high_b));
+
+  DONE;
+}")
 
 (define_insn "subsi3"
   [(set (match_operand:SI 0 "arith_reg_operand" "=r")
    (set (match_operand:SI 0 "arith_reg_operand" "=r")
        (reg:SI 21))]
   "TARGET_SH2"
-  "
-{
-  if (!TARGET_SH2)
-    {
-      emit_insn (gen_mulsi3_call (operands[0], operands[1], operands[2])); 
-      DONE; 
-    } 
-}")
+  "")
 
 (define_insn ""
   [(set (reg:DI 20)
 (define_insn "ashldi3_k"
   [(set (match_operand:DI 0 "arith_reg_operand" "=r")
        (ashift:DI (match_operand:DI 1 "arith_reg_operand" "0")
-                  (match_operand:DI 2 "immediate_operand" "I")))
+                  (const_int 1)))
    (clobber (reg:SI 18))]
   ""
   "shll        %R0\;rotcl      %0"
 (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")))
+                    (const_int 1)))
    (clobber (reg:SI 18))]
   ""
   "shlr        %0\;rotcr       %R0"
 (define_insn "ashrdi3_k"
   [(set (match_operand:DI 0 "arith_reg_operand" "=r")
        (ashiftrt:DI (match_operand:DI 1 "arith_reg_operand" "0")
-                    (match_operand:DI 2 "immediate_operand" "")))
+                    (const_int 1)))
    (clobber (reg:SI 18))]
   ""
   "shar        %0\;rotcr       %R0"
 ;; Unary arithmetic
 ;; -------------------------------------------------------------------------
 
-(define_insn "negdi2"
-  [(set (match_operand:DI 0 "arith_reg_operand" "=&r")
-       (neg:DI (match_operand:DI 1 "arith_reg_operand" "0")))
-   (clobber (reg:SI 18))]
+
+(define_insn "negc"
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
+       (neg:SI (plus:SI (reg:SI 18) (match_operand:SI 1 "arith_reg_operand" "r"))))]
   ""
-  "clrt\;negc  %R1,%R0\;negc   %1,%0"
-  [(set_attr "length" "6")
+  "negc        %1,%0"
+  [(set_attr "length" "2")
    (set_attr "type" "arith")])
 
+(define_expand "negdi2"
+  [(set (match_operand:DI 0 "arith_reg_operand" "=r")
+       (neg:DI (match_operand:DI 1 "arith_reg_operand" "r")))
+   (clobber (reg:SI 18))]
+  ""
+  "{
+   rtx low_src = operand_subword (operands[1], 1, 0, DImode);
+   rtx high_src = operand_subword (operands[1], 0, 0, DImode);
+
+   rtx low_dst = operand_subword (operands[0], 1, 1, DImode);
+   rtx high_dst = operand_subword (operands[0], 0, 1, DImode);
+
+   emit_insn (gen_clrt ());
+   emit_insn (gen_negc (low_dst, low_src));
+   emit_insn (gen_negc (high_dst, high_src));
+   DONE;
+   }
+   ")
+
+
 (define_insn "negsi2"
   [(set (match_operand:SI 0 "arith_reg_operand" "=r")
        (neg:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
   [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,r,r,r,<m,<,xl,xl,t,r")
        (match_operand:SI 1 "general_movsrc_operand" "Q,rI,>m,xl,t,r,xl,r,>,r,i"))]
   ""
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-      switch (get_attr_length(insn)) 
-       {
-       case 2:
-         return \"mov.l        %1,%0\";
-       case 12:
-         return \"mov.l        TA%*,%0\;bra    TB%*\;mov.l     @%0,%0\;.align 2\;TA%*: .long %1\;TB%*:%^\";
-       }
-    case 1: return \"mov       %1,%0\";
-    case 2: return \"mov.l     %1,%0\";
-    case 3: return \"sts       %1,%0\";
-    case 4: return \"movt      %0\";
-    case 5: return \"mov.l     %1,%0\";
-    case 6: return \"sts.l     %1,%0\";
-    case 7: return \"lds       %1,%0\";
-    case 8: return \"lds.l     %1,%0\";
-    case 9: return \"tst       %1,%1\;bt       T%*\;bra        F%*\;sett\;T%*:clrt\;F%*:%^\";
-    case 10: return \"fake %1,%0\";
-    }
-}"
-  [(set_attr "length" "*,2,2,2,2,2,2,2,2,6,2")
-   (set_attr "type" "pcloadsi,move,load,move,store,store,move,load,move,move,move")])
+  "@
+       mov.l   %1,%0
+       mov     %1,%0
+       mov.l   %1,%0
+       sts     %1,%0
+       movt    %0
+       mov.l   %1,%0
+       sts.l   %1,%0
+       lds     %1,%0
+       lds.l   %1,%0
+       tst     %1,%1\;bt       T%*\;bra        F%*\;sett\;T%*:clrt\;F%*:%^
+       fake %1,%0"
+  [(set_attr "type" "pcloadsi,move,load,move,store,store,move,load,move,move,move")])
                          
 (define_expand "movsi"
   [(set (match_operand:SI 0 "general_movdst_operand" "")
   [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,<m,r,r,l")
        (match_operand:HI 1 "general_movsrc_operand" "Q,rI,>m,t,r,i,l,r"))]
   ""
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-      switch (get_attr_length(insn)) 
-       {
-       case 2:
-         return \"mov.w        %1,%0\";
-       case 12:
-         return \"mov.l        TA%*,%0\;bra    TB%*\;mov.w     @%0,%0\;.align 2\;TA%*: .long %1\;TB%*:%^\";
-       }
-    case 1: return \"mov       %1,%0\";
-    case 2: return \"mov.w     %1,%0\";
-    case 3: return \"movt      %0\";
-    case 4: return \"mov.w     %1,%0\";
-    case 5: return \"fake %1,%0\";
-    case 6: return \"sts       %1,%0\";
-    case 7: return \"lds       %1,%0\";
-    }
-}"
+  "@
+       mov.w   %1,%0
+       mov     %1,%0
+       mov.w   %1,%0
+       movt    %0
+       mov.w   %1,%0
+       fake %1,%0
+       sts     %1,%0
+       lds     %1,%0"
   [(set_attr "length" "*,2,2,2,2,2,2,2")
    (set_attr "type" "pcloadhi,move,load,move,store,move,move,move")])
 
   [(set_attr "length" "*,4,4,4,4")
    (set_attr "type" "pcloadsi,move,load,store,move")])
 
+;; If the output is a register and the input is memory, we have to be careful
+;; and see which word needs to be loaded first.
+;;
+(define_split
+  [(set (match_operand:DI 0 "general_movdst_operand" "")
+       (match_operand:DI 1 "general_movsrc_operand" ""))]
+ "!  (GET_CODE (operands[0]) == REG
+                && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
+   && ! (GET_CODE (operands[1]) == REG
+         && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER)
+   && ! (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG
+   && ! reload_completed
+   && reg_overlap_mentioned_p (operands[0], operands[1]))"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 4) (match_dup 5))]
+  "
+{ if (GET_CODE (operands[0]) != REG
+      || ! refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+                             operands[1], 0))
+    {
+      operands[2] = operand_subword (operands[0], 0, 0, DImode);
+      operands[3] = operand_subword (operands[1], 0, 0, DImode);
+      operands[4] = operand_subword (operands[0], 1, 0, DImode);
+      operands[5] = operand_subword (operands[1], 1, 0, DImode);
+    }
+  else
+    {
+      operands[2] = operand_subword (operands[0], 1, 0, DImode);
+      operands[3] = operand_subword (operands[1], 1, 0, DImode);
+      operands[4] = operand_subword (operands[0], 0, 0, DImode);
+      operands[5] = operand_subword (operands[1], 0, 0, DImode);
+    }
+
+  if (operands[2] == 0 || operands[3] == 0
+      || operands[4] == 0 || operands[5] == 0)
+    FAIL;
+}")
 
        
 (define_expand "movdi"
   [(set_attr "length" "4")
    (set_attr "type" "move,load,store")])
 
+;; If the output is a register and the input is memory, we have to be careful
+;; and see which word needs to be loaded first.
+;;
+(define_split
+  [(set (match_operand:DF 0 "general_movdst_operand" "")
+       (match_operand:DF 1 "general_movsrc_operand" ""))]
+ "!  (GET_CODE (operands[0]) == REG
+                && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
+   && ! (GET_CODE (operands[1]) == REG
+         && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER)
+   && ! (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG
+   && ! reload_completed
+   && reg_overlap_mentioned_p (operands[0], operands[1]))"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 4) (match_dup 5))]
+  "
+{ if (GET_CODE (operands[0]) != REG
+      || ! refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+                             operands[1], 0))
+    {
+      operands[2] = operand_subword (operands[0], 0, 0, DFmode);
+      operands[3] = operand_subword (operands[1], 0, 0, DFmode);
+      operands[4] = operand_subword (operands[0], 1, 0, DFmode);
+      operands[5] = operand_subword (operands[1], 1, 0, DFmode);
+    }
+  else
+    {
+      operands[2] = operand_subword (operands[0], 1, 0, DFmode);
+      operands[3] = operand_subword (operands[1], 1, 0, DFmode);
+      operands[4] = operand_subword (operands[0], 0, 0, DFmode);
+      operands[5] = operand_subword (operands[1], 0, 0, DFmode);
+    }
+
+  if (operands[2] == 0 || operands[3] == 0
+      || operands[4] == 0 || operands[5] == 0)
+    FAIL;
+}")
+
+
 (define_expand "movdf"
   [(set (match_operand:DF 0 "general_movdst_operand" "")
        (match_operand:DF 1 "general_movsrc_operand" ""))]
                          (const_int 1))
                      (label_ref (match_operand 4 "" ""))
                      (pc)))
-   (set (match_dup 6) (plus:SI (match_dup 5) (match_dup 5)))
+   (parallel[(set (match_dup 5) (ashift:SI (match_dup 5) (const_int 2)))
+               (clobber (reg:SI 18))])
    (set (reg:SI 0) (label_ref (match_operand 3 "" "")))
-   (parallel[(set (reg:SI 0) (plus:SI (reg:SI 0)
-                                     (mem:HI (plus:SI (reg:SI 0)
-                                                      (match_dup 6)))))
-            (set (match_dup 6) (mem:HI (plus:SI (reg:SI 0) (match_dup 6))))])
+   (set (reg:SI 0) (mem:SI (plus:SI (reg:SI 0) (match_dup 5))))
+
+;;   (parallel[(set (reg:SI 0) (plus:SI (reg:SI 0)
+;;                                   (mem:HI (plus:SI (reg:SI 0)
+;;                                                    (match_dup 5)))))
+;;          (set (match_dup 6) (mem:HI (plus:SI (reg:SI 0) (match_dup 6))))])
    (set (pc) (reg:SI 0))]
   ""
   "
   operands[1] = copy_to_mode_reg (SImode, operands[1]);
   operands[2] = copy_to_mode_reg (SImode, operands[2]);
   operands[5] = gen_reg_rtx (SImode);
-  operands[6] = gen_reg_rtx (SImode);
+
 }")
 
 (define_insn "casesi_worker"
   "mov.w       @(r0,%0),%0\;add        %0,r0"
   [(set_attr "needs_delay_slot" "no")
    (set_attr "in_delay_slot" "no")
-   (set_attr "length" "6")])
+   (set_attr "length" "4")])
 
 
 (define_insn "return"