]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/config/h8300/h8300.c
Fix typos in comments.
[gcc.git] / gcc / config / h8300 / h8300.c
index 26f630efbd92f8f89c559d217a9b2c475962b079..a14155a03c546a610c971d5d3ad3814c3b75a85c 100644 (file)
@@ -1,8 +1,7 @@
 /* Subroutines for insn-output.c for Hitachi H8/300.
-   Copyright (C) 1992,1993 Free Software Foundation, Inc.
-
-   Contributed by Steve Chamberlain (sac@cygnus.com) and
-   Jim Wilson (wilson@cygnus.com).
+   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+   Contributed by Steve Chamberlain (sac@cygnus.com),
+   Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).
 
 This file is part of GNU CC.
 
@@ -40,42 +39,85 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 void print_operand_address ();
 char *index ();
 
+/* CPU_TYPE, says what cpu we're compiling for.  */
+int cpu_type;
+
 /* True if a #pragma interrupt has been seen for the current function.  */
 int pragma_interrupt;
 
 /* True if a #pragma saveall has been seen for the current function.  */
 int pragma_saveall;
 
-char *names_big[] 
- = {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"};
+static char *names_big[] =
+{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"};
+
+static char *names_extended[] =
+{"er0", "er1", "er2", "er3", "er4", "er5", "er6", "er7"};
+
+static char *names_upper_extended[] =
+{"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7"};
+
+/* Points to one of the above.  */
+/* ??? The above could be put in an array indexed by CPU_TYPE.  */
+char **h8_reg_names;
+
+/* Various operations needed by the following, indexed by CPU_TYPE.  */
+/* ??? The h8/300 assembler doesn't understand pop.w (yet).  */
+
+static char *h8_push_ops[2] =
+{"push", "push.l"};
+static char *h8_pop_ops[2] =
+{"pop", "pop.l"};
+static char *h8_mov_ops[2] =
+{"mov.w", "mov.l"};
+
+char *h8_push_op, *h8_pop_op, *h8_mov_op;
+
+/* Initialize various cpu specific globals at start up.  */
+
+void
+h8300_init_once ()
+{
+  if (TARGET_H8300)
+    {
+      cpu_type = (int) CPU_H8300;
+      h8_reg_names = names_big;
+    }
+  else
+    {
+      cpu_type = (int) CPU_H8300H;
+      h8_reg_names = names_extended;
+    }
+  h8_push_op = h8_push_ops[cpu_type];
+  h8_pop_op = h8_pop_ops[cpu_type];
+  h8_mov_op = h8_mov_ops[cpu_type];
+}
 
 char *
 byte_reg (x, b)
      rtx x;
      int b;
 {
-  static char *names_small[] 
-    =  {"r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h",
-       "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7lBAD", "r7hBAD"};
+  static char *names_small[] =
+  {"r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h",
+   "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7lBAD", "r7hBAD"};
 
   return names_small[REGNO (x) * 2 + b];
 }
 
 /* REGNO must be saved/restored across calls if this macro is true.  */
-static int 
-word_reg_used (regno)
-int regno;
-{
-  if (regno < 7  
-      && (pragma_interrupt || pragma_saveall 
-         || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno])
-         || (regs_ever_live[regno] & ! call_used_regs[regno])))
-    return 1;
-  return 0;
-}
+
+#define WORD_REG_USED(regno)                                   \
+  (regno < 7 &&                                                        \
+   (pragma_interrupt                                           \
+    || pragma_saveall                                          \
+    || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno])        \
+    || (regs_ever_live[regno] & !call_used_regs[regno])))
 
 /* Output assembly language to FILE for the operation OP with operand size
-   SIZE.  */
+   SIZE to adjust the stack pointer.  */
+/* ??? FPED is currently unused.  */
+
 static void
 dosize (file, op, size, fped)
      FILE *file;
@@ -86,6 +128,7 @@ dosize (file, op, size, fped)
   switch (size)
     {
     case 4:
+      /* ??? TARGET_H8300H can do this in one insn.  */
     case 3:
       fprintf (file, "\t%ss\t#%d,sp\n", op, 2);
       size -= 2;
@@ -98,66 +141,112 @@ dosize (file, op, size, fped)
     case 0:
       break;
     default:
-      fprintf (file, "\tmov.w\t#%d,r5\n\t%s.w\tr5,sp\n", size, op);
+      if (TARGET_H8300)
+       fprintf (file, "\tmov.w\t#%d,r3\n\t%s.w\tr3,sp\n", size, op);
+      else
+       fprintf (file, "\t%s\t#%d,sp\n", op, size);
       size = 0;
       break;
     }
 }
 
 /* Output assembly language code for the function prologue.  */
-static int push_order[FIRST_PSEUDO_REGISTER] 
-  = {6, 5, 4, 3, 2, 1, 0, -1, -1};
-static int pop_order[FIRST_PSEUDO_REGISTER] 
-  = {0, 1, 2, 3, 4, 5, 6, -1, -1};
+static int push_order[FIRST_PSEUDO_REGISTER] =
+{6, 5, 4, 3, 2, 1, 0, -1, -1};
+static int pop_order[FIRST_PSEUDO_REGISTER] =
+{0, 1, 2, 3, 4, 5, 6, -1, -1};
 
 /* This is what the stack looks like after the prolog of 
    a function with a frame has been set up:
 
-       <pushed args>
-       return pc
-   fp->        old fp
-       <locals>
-       <saved register-0> 
-       <saved register-1> 
-   sp->        <saved register-n>
-
+   <args>
+   PC
+   FP                  <- fp
+   <locals>
+   <saved registers>   <- sp
 
    This is what the stack looks like after the prolog of
    a function which doesn't have a frame:
 
-       <pushed args>
-       return pc
-       <locals>
-       <saved register-0>
-   sp-> <saved register-n>
+   <args>
+   PC
+   <locals>
+   <saved registers>           <- sp
 */
 
+int current_function_anonymous_args;
+
+/* Extra arguments to pop, in words (IE: 2 bytes for 300, 4 for 300h */
+static int extra_pop;
+
 void
 function_prologue (file, size)
      FILE *file;
      int size;
 {
   register int mask = 0;
-  int fsize = (size + 1) & -2;
+  int fsize = (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8;
   int idx;
+  extra_pop = 0;
 
-  if (frame_pointer_needed)
+  if (current_function_anonymous_args && TARGET_QUICKCALL)
     {
-      /* Push the fp.  */
-      fprintf (file, "\tpush\t%s\n", names_big[FRAME_POINTER_REGNUM]);
-      fprintf (file, "\tmov.w\tr7,r6\n");
+      /* Push regs as if done by caller, and move around return address.  */
+
+      switch (current_function_args_info.nbytes / UNITS_PER_WORD)
+       {
+       case 0:
+         /* get ret addr */
+         fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]);
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[2]);
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[1]);
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[0]);
+         /* push it again */
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[3]);
+         extra_pop = 3;
+         break;
+       case 1:
+         /* get ret addr */
+         fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]);
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[2]);
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[1]);
+         /* push it again */
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[3]);
+         extra_pop = 2;
+         break;
+       case 2:
+         /* get ret addr */
+         fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]);
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[2]);
+         /* push it again */
+         fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[3]);
+         extra_pop = 1;
+         break;
+       default:
+         fprintf (file, "; varargs\n");
+         break;
+       }
+    }
 
-      /* Leave room for the locals.  */
+  if (frame_pointer_needed)
+    {
+      /* Push fp */
+      fprintf (file, "\t%s\t%s\n", h8_push_op,
+              h8_reg_names[FRAME_POINTER_REGNUM]);
+      fprintf (file, "\t%s\t%s,%s\n", h8_mov_op,
+              h8_reg_names[STACK_POINTER_REGNUM],
+              h8_reg_names[FRAME_POINTER_REGNUM]);
+
+      /* leave room for locals */
       dosize (file, "sub", fsize, 1);
 
-      /* Push the rest of the registers */
-      for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) 
+      /* Push the rest of the registers */
+      for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++)
        {
          int regno = push_order[idx];
 
-         if (regno >= 0 && word_reg_used (regno)
-             && regno != FRAME_POINTER_REGNUM)
-           fprintf (file, "\tpush\t%s\n", names_big[regno]);
+         if (regno >= 0 && WORD_REG_USED (regno) && regno != FRAME_POINTER_REGNUM)
+           fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[regno]);
        }
     }
   else
@@ -167,8 +256,8 @@ function_prologue (file, size)
        {
          int regno = push_order[idx];
 
-         if (regno >= 0 && word_reg_used (regno))
-           fprintf (file, "\tpush\t%s\n", names_big[regno]);
+         if (regno >= 0 && WORD_REG_USED (regno))
+           fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[regno]);
        }
     }
 }
@@ -182,7 +271,7 @@ function_epilogue (file, size)
 {
   register int regno;
   register int mask = 0;
-  int fsize = (size + 1) & -2;
+  int fsize = (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8;
   int nregs;
   int offset;
   int idx;
@@ -198,43 +287,87 @@ function_epilogue (file, size)
 
   if (frame_pointer_needed)
     {
-      /* Pop saved registers */
+      /* Pop saved registers */
       for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++)
        {
          regno = pop_order[idx];
-         if (regno >= 0 && regno != FRAME_POINTER_REGNUM
-             && word_reg_used (regno))
-           fprintf (file, "\tpop\t%s\n", names_big[regno]);
+         if (regno >= 0 && regno != FRAME_POINTER_REGNUM && WORD_REG_USED (regno))
+           fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[regno]);
        }
-      /* Deallocate locals.  */
+      /* deallocate locals */
       dosize (file, "add", fsize, 1);
-      /* Pop frame pointer.  */
-      fprintf (file, "\tpop\t%s\n", names_big[FRAME_POINTER_REGNUM]);
+      /* pop frame pointer */
+      fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[FRAME_POINTER_REGNUM]);
     }
   else
     {
-      /* Deallocate locals and pop saved registers.  */
+      /* pop saved registers */
       for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++)
        {
          regno = pop_order[idx];
-         if (regno >= 0 && word_reg_used (regno))
-           fprintf (file, "\tpop\t%s\n", names_big[regno]);
+         if (regno >= 0 && WORD_REG_USED (regno))
+           fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[regno]);
        }
+      /* deallocate locals */
       dosize (file, "add", fsize, 0);
     }
-  if (pragma_interrupt)
-    fprintf (file, "\trte\n");
+
+  if (extra_pop)
+    {
+      fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]);
+      while (extra_pop)
+       {
+         fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[2]);
+         extra_pop--;
+       }
+      fprintf (file, "\tjmp    @%s\n", h8_reg_names[3]);
+    }
   else
-    fprintf (file, "\trts\n");
+    {
+      if (pragma_interrupt)
+       fprintf (file, "\trte\n");
+      else
+       fprintf (file, "\trts\n");
+    }
 
   pragma_interrupt = 0;
   pragma_saveall = 0;
+
+  current_function_anonymous_args = 0;
+}
+
+/* Output assembly code for the start of the file.  */
+
+asm_file_start (file)
+     FILE *file;
+{
+  fprintf (file, ";\tGCC For the Hitachi H8/300\n");
+  fprintf (file, ";\tBy Hitachi America Ltd and Cygnus Support\n");
+  fprintf (file, ";\trelease F-1\n");
+  if (optimize)
+    fprintf (file, "; -O%d\n", optimize);
+  if (TARGET_H8300H)
+    fprintf (file, "\n\t.h8300h\n");
+  else
+    fprintf (file, "\n\n");
+  output_file_directive (file, main_input_filename);
+}
+
+/* Output assembly language code for the end of file.  */
+
+void
+asm_file_end (file)
+     FILE *file;
+{
+  fprintf (file, "\t.end\n");
 }
 \f
-/* Return true if VALUE is a valid constant for constraint 'P'.  */
+/* Return true if VALUE is a valid constant for constraint 'P'.
+   IE: VALUE is a power of two <= 2**15.  */
 
 int
-potl8 (value)
+small_power_of_two (value)
+     int value;
 {
   switch (value)
     {
@@ -246,18 +379,6 @@ potl8 (value)
     case 32:
     case 64:
     case 128:
-      return 1;
-    }
-  return 0;
-}
-
-/* Return true if VALUE is a valid constant for constraint 'O'.  */
-int
-potg8 (value)
-     int value;
-{
-  switch (value)
-    {
     case 256:
     case 512:
     case 1024:
@@ -271,48 +392,167 @@ potg8 (value)
   return 0;
 }
 
+/* Return true if VALUE is a valid constant for constraint 'O', which
+   means that the constant would be ok to use as a bit for a bclr
+   instruction.  */
+
+int
+ok_for_bclr (value)
+     int value;
+{
+  return small_power_of_two ((~value) & 0xff);
+}
+
 /* Return true is OP is a valid source operand for an integer move
    instruction.  */
+
 int
 general_operand_src (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  /* We can't have a pre-dec as a source.  */
-  if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == PRE_DEC)
-    return 0;
+  if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC)
+    return 1;
   return general_operand (op, mode);
 }
 
 /* Return true if OP is a valid destination operand for an integer move
    instruction.  */
+
 int
 general_operand_dst (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  /* We can't have a post-inc as a dest.  */
-  if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC)
-    return 0;
+  if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == PRE_DEC)
+    return 1;
   return general_operand (op, mode);
 }
-\f
+
+/* Return true if OP is a const valid for a bit clear instruction.  */
+
+int
+o_operand (operand, mode)
+     rtx operand;
+     enum machine_mode mode;
+{
+  return (GET_CODE (operand) == CONST_INT
+         && CONST_OK_FOR_O (INTVAL (operand)));
+}
+
+/* Return true if OP is a const valid for a bit set or bit xor instruction.  */
+
+int
+p_operand (operand, mode)
+     rtx operand;
+     enum machine_mode mode;
+{
+  return (GET_CODE (operand) == CONST_INT
+         && CONST_OK_FOR_P (INTVAL (operand)));
+}
+
+/* Return true if OP is a valid call operand.  */
+
+int
+call_insn_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) == MEM)
+    {
+      rtx inside = XEXP (op, 0);
+      if (register_operand (inside, Pmode))
+       return 1;
+      if (CONSTANT_ADDRESS_P (inside))
+       return 1;
+    }
+  return 0;
+}
+
+/* Return true if OP is a valid jump operand.  */
+
+int
+jump_address_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) == REG)
+    return mode == Pmode;
+
+  if (GET_CODE (op) == MEM)
+    {
+      rtx inside = XEXP (op, 0);
+      if (register_operand (inside, Pmode))
+       return 1;
+      if (CONSTANT_ADDRESS_P (inside))
+       return 1;
+    }
+  return 0;
+}
+
+/* Recognize valid operands for bitfield instructions.  */
+
+extern int rtx_equal_function_value_matters;
+
+int
+bit_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  /* We can except any general operand, expept that MEM operands must
+     be limited to those that use addresses valid for the 'U' constraint.  */
+  if (!general_operand (op, mode))
+    return 0;
+
+  /* Accept any mem during RTL generation.  Otherwise, the code that does
+     insv and extzv will think that we can not handle memory.  However,
+     to avoid reload problems, we only accept 'U' MEM operands after RTL
+     generation.  This means that any named pattern which uses this predicate
+     must force its operands to match 'U' before emitting RTL.  */
+
+  if (GET_CODE (op) == REG)
+    return 1;
+  if (GET_CODE (op) == SUBREG)
+    return 1;
+  if (!rtx_equal_function_value_matters)
+    {
+      /* We're building rtl */
+      return GET_CODE (op) == MEM;
+    }
+  else
+    {
+      return (GET_CODE (op) == MEM
+             && EXTRA_CONSTRAINT (op, 'U'));
+    }
+}
+
+/* Recognize valid operators for bit test.  */
+
+int
+eq_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  return (GET_CODE (x) == EQ || GET_CODE (x) == NE);
+}
+
 /* Handle machine specific pragmas for compatibility with existing
-   compilers for the H8/300
+   compilers for the H8/300.
 
    pragma saveall generates prolog/epilog code which saves and
    restores all the registers on function entry.
-   
+
    pragma interrupt saves and restores all registers, and exits with
    an rte instruction rather than an rts.  A pointer to a function
    with this attribute may be safely used in an interrupt vector.  */
+
 int
 handle_pragma (file)
      FILE *file;
 {
   int c;
   char pbuf[20];
-  int psize;
+  int psize = 0;
 
   c = getc (file);
   while (c == ' ' || c == '\t')
@@ -321,12 +561,13 @@ handle_pragma (file)
   if (c == '\n' || c == EOF)
     return c;
 
-  for (psize = 0; psize < sizeof (pbuf) - 1 && isalpha (c); psize++)
+  /* The only pragmas we understand are interrupt and saveall.  */
+  while (psize < sizeof (pbuf) - 1
+        && isalpha (c))
     {
-      pbuf[psize] = c;
+      pbuf[psize++] = c;
       c = getc (file);
     }
-
   pbuf[psize] = 0;
 
   if (strcmp (pbuf, "interrupt") == 0)
@@ -335,6 +576,28 @@ handle_pragma (file)
   if (strcmp (pbuf, "saveall") == 0)
     pragma_saveall = 1;
 
+  /* ??? This is deprecated.  Delete for gcc 2.8.  */
+  if (strcmp (pbuf, "section") == 0)
+    {
+      static int printed_p = 0;
+      if (!printed_p)
+       {
+         warning ("#pragma section is deprecated, use section attributes");
+         printed_p = 1;
+       }
+      while (c && !isalpha (c))
+       c = getc (file);
+      psize = 0;
+      while (psize < sizeof (pbuf) - 1
+            && isalpha (c) || isdigit (c) || c == '_')
+       {
+         pbuf[psize++] = c;
+         c = getc (file);
+       }
+      pbuf[psize] = 0;
+      named_section (NULL_TREE, pbuf);
+    }
+  ungetc (c, file);
   return c;
 }
 \f
@@ -342,6 +605,29 @@ handle_pragma (file)
    the rtx to represent where it is passed.  CUM represents the state after
    the last argument.  NAMED is not used.  */
 
+static char *hand_list[] =
+{
+  "__main",
+  "__cmpsi2",
+  "__divhi3",
+  "__modhi3",
+  "__udivhi3",
+  "__umodhi3",
+  "__divsi3",
+  "__modsi3",
+  "__udivsi3",
+  "__umodsi3",
+  "__mulhi3",
+  "__mulsi3",
+  "__reg_memcpy",
+  "__reg_memset",
+  "__ucmpsi2",
+  0,
+};
+
+/* Return an RTX to represent where a value with mode MODE will be returned
+   from a function.  If the result is 0, the argument is pushed.  */
+
 rtx
 function_arg (cum, mode, type, named)
      CUMULATIVE_ARGS *cum;
@@ -350,83 +636,154 @@ function_arg (cum, mode, type, named)
      int named;
 {
   rtx result = 0;
-  int libcall = 0;
+  char *fname;
+  int regpass = 0;
+
+  /* Pass 3 regs worth of data in regs when user asked on the command line.  */
+  if (TARGET_QUICKCALL)
+    regpass = 3;
+
+  /* If calling hand written assembler, use 4 regs of args.  */
+
+  if (cum->libcall)
+    {
+      char **p;
 
-  /* Right now reload has a problem with reg passing with small reg
-     classes.  */
+      fname = XSTR (cum->libcall, 0);
+
+      /* See if this libcall is one of the hand coded ones.  */
+
+      for (p = hand_list; *p && strcmp (*p, fname) != 0; p++)
+       ;
+
+      if (*p)
+       regpass = 4;
+    }
+
+  if (regpass)
+    {
+      int size;
+
+      if (mode == BLKmode)
+       size = int_size_in_bytes (type);
+      else
+       size = GET_MODE_SIZE (mode);
 
-  if (cum->libcall || (named && TARGET_QUICKCALL))
-    libcall = 1;
+      if (size + cum->nbytes > regpass * UNITS_PER_WORD)
+       {
+         result = 0;
+       }
+      else
+       {
+         switch (cum->nbytes / UNITS_PER_WORD)
+           {
+           case 0:
+             result = gen_rtx (REG, mode, 0);
+             break;
+           case 1:
+             result = gen_rtx (REG, mode, 1);
+             break;
+           case 2:
+             result = gen_rtx (REG, mode, 2);
+             break;
+           case 3:
+             result = gen_rtx (REG, mode, 3);
+             break;
+           default:
+             result = 0;
+           }
+       }
+    }
 
-  if (TARGET_NOQUICK)
-    libcall = 0;
+  return result;
+}
+\f
+/* Return the cost of the rtx R with code CODE.  */
 
-  if (mode != VOIDmode && libcall && mode != DFmode && mode != SFmode)
+int
+const_costs (r, c)
+     rtx r;
+     enum rtx_code c;
+{
+  switch (c)
     {
-      switch (cum->nbytes)
+    case CONST_INT:
+      switch (INTVAL (r))
        {
        case 0:
-         result = gen_rtx (REG, mode, 0);
-         break;
+       case 1:
        case 2:
-         result = gen_rtx (REG, mode, 1);
-         break;
-       case 4:
-         result = gen_rtx (REG, mode, 4);
-         break;
-       case 6:
-         result = gen_rtx (REG, mode, 5);
-         break;
-       default:
+       case -1:
+       case -2:
          return 0;
+       default:
+         return 1;
        }
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      return 3;
+
+    case CONST_DOUBLE:
+      return 20;
+
+    default:
+      return 4;
     }
-  return result;
 }
-
+\f
 /* Documentation for the machine specific operand escapes:
 
+   'A' print rn in h8/300 mode, erN in H8/300H mode
    'C' print (operand - 2).
-   'E' low byte of reg or -ve lsb of constant
-   'F' high byte of reg of -ve  msb of constant
-
-   'G' negate constant
+   'E' like s but negative.
+   'F' like t but negative.
+   'G' constant just the negative
    'L' fake label, changed after used twice.
    'M' turn a 'M' constant into its negative mod 2.
+   'P' if operand is incing/decing sp, print .w, otherwise .b.
+   'S' print operand as a long word
    'T' print operand as a word
-   'V' print log2 of constant - used for bset instructions
-   'X' 8 bit register or other operand
-
+   'U' if operand is incing/decing sp, print l, otherwise nothing.
+   'V' find the set bit, and print its number.
+   'W' find the clear bit, and print its number.
+   'X' print operand as a byte
    'Y' print either l or h depending on whether last 'Z' operand < 8 or >= 8.
-   'Z' print int & 7
-
-   'e' first word of 32 bit value
-   'f' second word of 32 bit value
-
+   'Z' print int & 7.
+   'b' print the bit opcode
+   'c' print the ibit opcode
+   'd' bcc if EQ, bcs if NE
+   'e' first word of 32 bit value - if reg, then least reg. if mem
+       then least. if const then most sig word
+   'f' second word of 32 bit value - if reg, then biggest reg. if mem
+       then +2. if const then least sig word
+   'g' bcs if EQ, bcc if NE
    'j' print operand as condition code.
    'k' print operand as reverse condition code.
-
-   's' low byte of 16 bit value
-   't' high byte of 16 bit value
-
-   'w' 1st byte of 32 bit value           zzzzzzzz yyyyyyyy xxxxxxxx wwwwwwww
-   'x' 2nd byte of 32 bit value
-   'y' 3rd byte of 32 bit value
-   'z' 4th byte of 32 bit value
-
- */
+   's' print as low byte of 16 bit value
+   't' print as high byte of 16 bit value
+   'w' print as low byte of 32 bit value
+   'x' print as 2nd byte of 32 bit value
+   'y' print as 3rd byte of 32 bit value
+   'z' print as msb of 32 bit value
+*/
 
 /* Return assembly language string which identifies a comparison type.  */
 
-char *
+static char *
 cond_string (code)
      enum rtx_code code;
 {
   switch (code)
     {
     case NE:
+      if (cc_prev_status.flags & CC_DONE_CBIT)
+       return "cs";
       return "ne";
     case EQ:
+      if (cc_prev_status.flags & CC_DONE_CBIT)
+       return "cc";
       return "eq";
     case GE:
       return "ge";
@@ -465,149 +822,184 @@ print_operand (file, x, code)
   static char *last_p;
 
   /* This is used for communication between the 'Z' and 'Y' codes.  */
+  /* ??? 'V' and 'W' use it too.  */
   static int bitint;
 
   switch (code)
     {
-    case 'L':
-      /* 'L' must always be used twice in a single pattern.  It generates
-        the same lable twice, and then will generate a unique label the
-        next time it is used.  */
-      asm_fprintf (file, "tl%d", (lab++) / 2);
-      break;
-
-    case 'X':
+    case 'A':
       if (GET_CODE (x) == REG)
-       fprintf (file, "%s", byte_reg (x, 0));
+       fprintf (file, "%s", h8_reg_names[REGNO (x)]);
       else
        goto def;
       break;
-
+    case 'C':
+      fprintf (file, "#%d", INTVAL (x) - 2);
+      break;
+    case 'E':
+      switch (GET_CODE (x))
+       {
+       case REG:
+         fprintf (file, "%sl", names_big[REGNO (x)]);
+         break;
+       case CONST_INT:
+         fprintf (file, "#%d", (-INTVAL (x)) & 0xff);
+         break;
+       default:
+         abort ();
+       }
+      break;
+    case 'F':
+      switch (GET_CODE (x))
+       {
+       case REG:
+         fprintf (file, "%sh", names_big[REGNO (x)]);
+         break;
+       case CONST_INT:
+         fprintf (file, "#%d", ((-INTVAL (x)) & 0xff00) >> 8);
+         break;
+       default:
+         abort ();
+       }
+      break;
     case 'G':
       if (GET_CODE (x) != CONST_INT)
        abort ();
       fprintf (file, "#%d", 0xff & (-INTVAL (x)));
       break;
-
-    case 'T':
-      if (GET_CODE (x) == REG)
-       fprintf (file, "%s", names_big[REGNO (x)]);
-      else
-       goto def;
-      break;
-
-    case 'w':
-      if (GET_CODE (x) == CONST_INT)
-       fprintf (file, "#%d", INTVAL (x) & 0xff);
-      else
-       fprintf (file, "%s", byte_reg (x, 2));
+    case 'L':
+      /* 'L' must always be used twice in a single pattern.  It generates
+        the same label twice, and then will generate a unique label the
+        next time it is used.  */
+      asm_fprintf (file, "tl%d", (lab++) / 2);
       break;
-
-    case 'x':
-      if (GET_CODE (x) == CONST_INT)
-       fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff);
-      else
-       fprintf (file, "%s", byte_reg (x, 3));
+    case 'M':
+      /* For 3/-3 and 4/-4, the other 2 is handled separately.  */
+      switch (INTVAL (x))
+       {
+       case 2:
+       case 4:
+       case -2:
+       case -4:
+         fprintf (file, "#2");
+         break;
+       case 1:
+       case 3:
+       case -1:
+       case -3:
+         fprintf (file, "#1");
+         break;
+       default:
+         abort ();
+       }
       break;
-
-    case 'y':
-      if (GET_CODE (x) == CONST_INT)
-       fprintf (file, "#%d", (INTVAL (x) >> 16) & 0xff);
+    case 'P':
+      if (REGNO (XEXP (XEXP (x, 0), 0)) == STACK_POINTER_REGNUM)
+       {
+         last_p = "";
+         fprintf (file, ".w");
+       }
       else
-       fprintf (file, "%s", byte_reg (x, 0));
+       {
+         last_p = "l";
+         fprintf (file, ".b");
+       }
       break;
-
-    case 'z':
-      if (GET_CODE (x) == CONST_INT)
-       fprintf (file, "#%d", (INTVAL (x) >> 24) & 0xff);
+    case 'S':
+      if (GET_CODE (x) == REG)
+       fprintf (file, "%s", names_extended[REGNO (x)]);
       else
-       fprintf (file, "%s", byte_reg (x, 1));
+       goto def;
       break;
-
-      /* FOR 16 bits.  */
-    case 't':
-      if (GET_CODE (x) == CONST_INT)
-       fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff);
+    case 'T':
+      if (GET_CODE (x) == REG)
+       fprintf (file, "%s", names_big[REGNO (x)]);
       else
-       fprintf (file, "%s", byte_reg (x, 1));
+       goto def;
       break;
-
-    case 's':
-      if (GET_CODE (x) == CONST_INT)
-       fprintf (file, "#%d", (INTVAL (x)) & 0xff);
-      else
-       fprintf (file, "%s", byte_reg (x, 0));
+    case 'U':
+      fprintf (file, "%s%s", names_big[REGNO (x)], last_p);
       break;
-
-    case 'u':
-      if (GET_CODE (x) != CONST_INT)
+    case 'V':
+      bitint = exact_log2 (INTVAL (x));
+      if (bitint == -1)
        abort ();
-      fprintf (file, "%d", INTVAL (x));
-      break;
-
-    case 'Z':
-      bitint = INTVAL (x);
       fprintf (file, "#%d", bitint & 7);
       break;
-
-    case 'Y':
-      fprintf (file, "%c", bitint > 7 ? 'h' : 'l');
-      break;
-
-    case 'O':
+    case 'W':
       bitint = exact_log2 ((~INTVAL (x)) & 0xff);
       if (bitint == -1)
        abort ();
       fprintf (file, "#%d", bitint & 7);
       break;
-
-    case 'V':
-      bitint = exact_log2 (INTVAL (x));
+    case 'X':
+      if (GET_CODE (x) == REG)
+       fprintf (file, "%s", byte_reg (x, 0));
+      else
+       goto def;
+      break;
+    case 'Y':
       if (bitint == -1)
        abort ();
+      if (GET_CODE (x) == REG)
+       fprintf (file, "%s%c", names_big[REGNO (x)], bitint > 7 ? 'h' : 'l');
+      else
+       print_operand (file, x, 0);
+      bitint = -1;
+      break;
+    case 'Z':
+      bitint = INTVAL (x);
       fprintf (file, "#%d", bitint & 7);
       break;
-
-    case 'P':
-      if (REGNO (XEXP (XEXP (x, 0), 0)) == STACK_POINTER_REGNUM)
+    case 'b':
+      switch (GET_CODE (x))
        {
-         last_p = "";
-         fprintf (file, ".w");
+       case IOR:
+         fprintf (file, "bor");
+         break;
+       case XOR:
+         fprintf (file, "bxor");
+         break;
+       case AND:
+         fprintf (file, "band");
+         break;
        }
-      else
+      break;
+    case 'c':
+      switch (GET_CODE (x))
        {
-         last_p = "l";
-         fprintf (file, ".b");
+       case IOR:
+         fprintf (file, "bior");
+         break;
+       case XOR:
+         fprintf (file, "bixor");
+         break;
+       case AND:
+         fprintf (file, "biand");
+         break;
        }
       break;
-
-    case 'U':
-      fprintf (file, "%s%s", names_big[REGNO (x)], last_p);
-      break;
-
-    case 'M':
-      /* For -4 and -2, the other 2 is handled separately.  */
-      switch (INTVAL (x))
+    case 'd':
+      switch (GET_CODE (x))
        {
-       case -2:
-       case -4:
-         fprintf (file, "#2");
+       case EQ:
+         fprintf (file, "bcc");
          break;
-       case -1:
-       case -3:
-         fprintf (file, "#1");
+       case NE:
+         fprintf (file, "bcs");
          break;
-
        default:
          abort ();
        }
       break;
-
     case 'e':
       switch (GET_CODE (x))
        {
        case REG:
-         fprintf (file, "%s", names_big[REGNO (x)]);
+         if (TARGET_H8300)
+           fprintf (file, "%s", names_big[REGNO (x)]);
+         else
+           fprintf (file, "%s", names_upper_extended[REGNO (x)]);
          break;
        case MEM:
          x = adj_offsettable_operand (x, 0);
@@ -621,77 +1013,111 @@ print_operand (file, x, code)
          break;
        }
       break;
-
     case 'f':
       switch (GET_CODE (x))
        {
        case REG:
-         fprintf (file, "%s", names_big[REGNO (x) + 1]);
+         if (TARGET_H8300)
+           fprintf (file, "%s", names_big[REGNO (x) + 1]);
+         else
+           fprintf (file, "%s", names_big[REGNO (x)]);
          break;
-
        case MEM:
          x = adj_offsettable_operand (x, 2);
          print_operand (file, x, 0);
          break;
-
        case CONST_INT:
          fprintf (file, "#%d", INTVAL (x) & 0xffff);
          break;
-
-       default:
-         abort ();
-       }
-      break;
-
-    case 'C':
-      fprintf (file, "#%d", INTVAL (x) - 2);
-      break;
-
-    case 'E':
-      switch (GET_CODE (x))
-       {
-       case REG:
-         fprintf (file, "%sl", names_big[REGNO (x)]);
-         break;
-
-       case CONST_INT:
-         fprintf (file, "#%d", (-INTVAL (x)) & 0xff);
-         break;
-
        default:
          abort ();
        }
       break;
-
-    case 'F':
+    case 'g':
       switch (GET_CODE (x))
        {
-       case REG:
-         fprintf (file, "%sh", names_big[REGNO (x)]);
+       case NE:
+         fprintf (file, "bcc");
          break;
-
-       case CONST_INT:
-         fprintf (file, "#%d", ((-INTVAL (x)) & 0xff00) >> 8);
+       case EQ:
+         fprintf (file, "bcs");
          break;
-
        default:
          abort ();
        }
       break;
-
     case 'j':
       asm_fprintf (file, cond_string (GET_CODE (x)));
       break;
-
     case 'k':
       asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x))));
       break;
-    def: ;
+    case 's':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "#%d", (INTVAL (x)) & 0xff);
+      else
+       fprintf (file, "%s", byte_reg (x, 0));
+      break;
+    case 't':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff);
+      else
+       fprintf (file, "%s", byte_reg (x, 1));
+      break;
+    case 'u':
+      if (GET_CODE (x) != CONST_INT)
+       abort ();
+      fprintf (file, "%d", INTVAL (x));
+      break;
+    case 'w':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "#%d", INTVAL (x) & 0xff);
+      else
+       fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 2 : 0));
+      break;
+    case 'x':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff);
+      else
+       fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 3 : 1));
+      break;
+    case 'y':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "#%d", (INTVAL (x) >> 16) & 0xff);
+      else
+       fprintf (file, "%s", byte_reg (x, 0));
+      break;
+    case 'z':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "#%d", (INTVAL (x) >> 24) & 0xff);
+      else
+       fprintf (file, "%s", byte_reg (x, 1));
+      break;
+
     default:
+    def:
       switch (GET_CODE (x))
        {
        case REG:
-         fprintf (file, "%s", names_big[REGNO (x)]);
+         switch (GET_MODE (x))
+           {
+           case QImode:
+#if 0                          /* Is it asm ("mov.b %0,r2l", ...) */
+             fprintf (file, "%s", byte_reg (x, 0));
+#else /* ... or is it asm ("mov.b %0l,r2l", ...) */
+             fprintf (file, "%s", names_big[REGNO (x)]);
+#endif
+             break;
+           case HImode:
+             fprintf (file, "%s", names_big[REGNO (x)]);
+             break;
+           case SImode:
+           case SFmode:
+             fprintf (file, "%s", names_extended[REGNO (x)]);
+             break;
+           default:
+             abort ();
+           }
          break;
 
        case MEM:
@@ -720,15 +1146,15 @@ print_operand_address (file, addr)
   switch (GET_CODE (addr))
     {
     case REG:
-      fprintf (file, "%s", names_big[REGNO (addr)]);
+      fprintf (file, "%s", h8_reg_names[REGNO (addr)]);
       break;
 
     case PRE_DEC:
-      fprintf (file, "-%s", names_big[REGNO (XEXP (addr, 0))]);
+      fprintf (file, "-%s", h8_reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
     case POST_INC:
-      fprintf (file, "%s+", names_big[REGNO (XEXP (addr, 0))]);
+      fprintf (file, "%s+", h8_reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
     case PLUS:
@@ -751,15 +1177,22 @@ print_operand_address (file, addr)
       break;
 
     case CONST_INT:
-      if (INTVAL (addr) < 0)
-       {
-         int v = -INTVAL (addr);
-
-         fprintf (file, "-%d", v);
-       }
-      else
-       fprintf (file, "%d", INTVAL (addr));
-      break;
+      {
+       /* Since the h8/300 only has 16 bit pointers, negative values are also
+          those >= 32768.  This happens for example with pointer minus a
+          constant.  We don't want to turn (char *p - 2) into
+          (char *p + 65534) because loop unrolling can build upon this
+          (IE: char *p + 131068).  */
+       int n = INTVAL (addr);
+       if (TARGET_H8300)
+         n = (int) (short) n;
+       if (n < 0)
+         /* ??? Why the special case for -ve values? */
+         fprintf (file, "-%d", -n);
+       else
+         fprintf (file, "%d", n);
+       break;
+      }
 
     default:
       output_addr_const (file, addr);
@@ -782,139 +1215,833 @@ final_prescan_insn (insn, operand, num_operands)
 
   int uid = INSN_UID (insn);
 
+  if (TARGET_RTL_DUMP)
+    {
+      fprintf (asm_out_file, "\n****************");
+      print_rtl (asm_out_file, PATTERN (insn));
+      fprintf (asm_out_file, "\n");
+    }
+
   if (TARGET_ADDRESSES)
     {
-      fprintf (asm_out_file, "; %d %d\n", insn_addresses[uid],
+      fprintf (asm_out_file, "; 0x%x %d\n", insn_addresses[uid],
               insn_addresses[uid] - last_insn_address);
       last_insn_address = insn_addresses[uid];
     }
 }
 
-static void
-shift_n_bits (lval, operand, f, notzero)
-     rtx lval;
-     rtx operand;
-     rtx (*f) ();
-     int notzero;
+/* Prepare for an SI sized move.  */
+
+int
+do_movsi (operands)
+     rtx operands[];
 {
-  rtx label = gen_label_rtx ();
-  rtx bot = gen_label_rtx ();
+  rtx src = operands[1];
+  rtx dst = operands[0];
+  if (!reload_in_progress && !reload_completed)
+    {
+      if (!register_operand (dst, GET_MODE (dst)))
+       {
+         rtx tmp = gen_reg_rtx (GET_MODE (dst));
+         emit_move_insn (tmp, src);
+         operands[1] = tmp;
+       }
+    }
+  return 0;
+}
+
+/* Function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET).
+   Define the offset between two registers, one to be eliminated, and the other
+   its replacement, at the start of a routine.  */
 
-  if (! notzero)
+int
+initial_offset (from, to)
+{
+  int offset = 0;
+
+  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+    offset = UNITS_PER_WORD + frame_pointer_needed * UNITS_PER_WORD;
+  else
     {
-      /* Have to put a zero test at the top.  */
-      emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, lval));
-      emit_jump_insn (gen_beq (bot));
+      int regno;
+
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       if ((regs_ever_live[regno]
+            && (!call_used_regs[regno] || regno == FRAME_POINTER_REGNUM)))
+         offset += UNITS_PER_WORD;
+
+      /* See the comments for get_frame_size.  We need to round it up to
+        STACK_BOUNDARY.  */
+
+      offset += ((get_frame_size () + STACK_BOUNDARY / BITS_PER_UNIT - 1)
+                & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1));
+
+      if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+       offset += UNITS_PER_WORD;       /* Skip saved PC */
+    }
+  return offset;
+}
+
+/* Update the condition code from the insn.  */
+
+int
+notice_update_cc (body, insn)
+     rtx body;
+     rtx insn;
+{
+  switch (get_attr_cc (insn))
+    {
+    case CC_NONE:
+      /* Insn does not affect the CC at all */
+      break;
+
+    case CC_NONE_0HIT:
+      /* Insn does not change the CC, but the 0't operand has been changed.  */
+
+      if (cc_status.value1 != 0
+         && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
+       cc_status.value1 = 0;
+
+      if (cc_status.value2 != 0
+         && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
+       cc_status.value2 = 0;
+
+      break;
+
+    case CC_SET:
+      /* Insn sets CC to recog_operand[0], but overflow is impossible.  */
+      CC_STATUS_INIT;
+      cc_status.flags |= CC_NO_OVERFLOW;
+      cc_status.value1 = recog_operand[0];
+      break;
+
+    case CC_COMPARE:
+      /* The insn is a compare instruction */
+      CC_STATUS_INIT;
+      cc_status.value1 = SET_SRC (body);
+      break;
+
+    case CC_CBIT:
+      CC_STATUS_INIT;
+      cc_status.flags |= CC_DONE_CBIT;
+      cc_status.value1 = 0;
+      break;
+
+    case CC_WHOOPS:
+    case CC_CLOBBER:
+      /* Insn clobbers CC. */
+      CC_STATUS_INIT;
+      break;
     }
-  emit_label (label);
-  f (operand);
-  emit_insn (gen_rtx (SET, QImode, lval,
-                     gen_rtx (MINUS, QImode, lval, const1_rtx)));
-  emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, lval));
-  emit_jump_insn (gen_bne (label));
+}
+
+/* Recognize valid operators for bit instructions */
+
+int
+bit_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (x);
 
-  emit_label (bot);
-  /* We can't end an expand with a label.  */
-  emit_move_insn (operand, operand);
+  return (code == XOR
+         || code == AND
+         || code == IOR);
 }
+\f
+/* Shifts.
+
+   We devote a fair bit of code to getting efficient shifts since we can only
+   shift one bit at a time.  See the .md file for more comments.
+
+   Here are some thoughts on what the absolutely positively best code is.
+   "Best" here means some rational trade-off between code size and speed,
+   where speed is more preferred but not at the expense of generating 20 insns.
+
+   H8/300 QImode shifts
+   1-4   - do them inline
+   5-6   - ASHIFT | LSHIFTRT: rotate, mask off other bits
+           ASHIFTRT: loop
+   7     - ASHIFT | LSHIFTRT: rotate, mask off other bits
+           ASHIFTRT: shll, subx (propagate carry bit to all bits)
+
+   H8/300 HImode shifts
+   1-4   - do them inline
+   5-6   - loop
+   7     - shift other way once, move byte into place, move carry bit into place
+   8     - move byte, zero (ASHIFT | LSHIFTRT) or sign extend other (ASHIFTRT)
+   9     - inline shift 1-4, move byte, set other byte
+   13-14 - ASHIFT | LSHIFTRT: rotate 3/2, mask, move byte, set other byte to 0
+         - ASHIFTRT: loop
+   15    - ASHIFT | LSHIFTRT: rotate 1, mask, move byte, set other byte to 0
+         - ASHIFTRT: shll, subx, set other byte
+
+   H8/300 SImode shifts
+   1-2   - do them inline
+   3-6   - loop
+   7     - shift other way once, move bytes into place,
+           move carry into place (possibly with sign extension)
+   8     - move bytes into place, zero or sign extend other
+   9-14  - loop
+   15    - shift other way once, move word into place, move carry into place
+   16    - move word, zero or sign extend other
+   17-23 - loop
+   24    - move bytes into place, zero or sign extend other
+   25-27 - loop
+   28-30 - ASHIFT | LSHIFTRT: rotate top byte, mask, move byte into place,
+                              zero others
+           ASHIFTRT: loop
+   31    - ASHIFT | LSHIFTRT: rotate top byte, mask, byte byte into place,
+                              zero others
+           ASHIFTRT: shll top byte, subx, copy to other bytes
+
+   H8/300H QImode shifts
+   - same as H8/300
+
+   H8/300H HImode shifts
+   - same as H8/300
+
+   H8/300H SImode shifts
+   (These are complicated by the fact that we don't have byte level access to
+   the top word.)
+   A word is: bytes 3,2,1,0 (msb -> lsb), word 1,0 (msw -> lsw)
+   1-4   - do them inline
+   5-14  - loop
+   15    - shift other way once, move word into place, move carry into place
+           (with sign extension for ASHIFTRT)
+   16    - move word into place, zero or sign extend other
+   17-23 - loop
+   24    - ASHIFT: move byte 0(msb) to byte 1, zero byte 0,
+                   move word 0 to word 1, zero word 0
+           LSHIFTRT: move word 1 to word 0, move byte 1 to byte 0,
+                     zero word 1, zero byte 1
+           ASHIFTRT: move word 1 to word 0, move byte 1 to byte 0,
+                     sign extend byte 0, sign extend word 0
+   25-27 - either loop, or
+           do 24 bit shift, inline rest
+   28-30 - ASHIFT: rotate 4/3/2, mask
+           LSHIFTRT: rotate 4/3/2, mask
+           ASHIFTRT: loop
+   31    - shll, subx byte 0, sign extend byte 0, sign extend word 0
+
+   Don't Panic!!!
+
+   All of these haven't been implemented.  I've just documented them and
+   provided hooks so they can be.
+*/
 
 int
-can_shift (code, operands, f, limit, fby_eight)
+nshift_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  switch (GET_CODE (x))
+    {
+    case ASHIFTRT:
+    case LSHIFTRT:
+    case ASHIFT:
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Called from the .md file to emit code to do shifts.
+   Returns a boolean indicating success
+   (currently this is always TRUE).  */
+
+int
+expand_a_shift (mode, code, operands)
+     enum machine_mode mode;
      int code;
      rtx operands[];
-     rtx (*f) ();
-     int limit;
-     rtx (*fby_eight) ();
 {
   extern int rtx_equal_function_value_matters;
 
   emit_move_insn (operands[0], operands[1]);
 
-  if (GET_CODE (operands[2]) != CONST_INT)
-    {
-      rtx lval;
+  /* need a loop to get all the bits we want  - we generate the
+     code at emit time, but need to allocate a scratch reg now  */
+
+  emit_insn (gen_rtx
+            (PARALLEL, VOIDmode,
+             gen_rtvec (2,
+                        gen_rtx (SET, VOIDmode, operands[0],
+                                 gen_rtx (code, mode, operands[0], operands[2])),
+                        gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, QImode, 0)))));
+
+  return 1;
+}
+
+/* Shift algorithm determination.
+
+   There are various ways of doing a shift:
+   SHIFT_INLINE: If the amount is small enough, just generate as many one-bit
+                 shifts as we need.
+   SHIFT_ROT_AND: If the amount is large but close to either end, rotate the
+                  necessary bits into position and then set the rest to zero.
+   SHIFT_SPECIAL: Hand crafted assembler.
+   SHIFT_LOOP:    If the above methods fail, just loop.  */
+
+enum shift_alg
+{
+  SHIFT_INLINE,
+  SHIFT_ROT_AND,
+  SHIFT_SPECIAL,
+  SHIFT_LOOP,
+  SHIFT_MAX
+};
+
+/* Symbols of the various shifts which can be used as indices.  */
+
+enum shift_type
+  {
+    SHIFT_ASHIFT, SHIFT_LSHIFTRT, SHIFT_ASHIFTRT
+  };
+
+/* Symbols of the various modes which can be used as indices.  */
+
+enum shift_mode
+  {
+    QIshift, HIshift, SIshift
+  };
+
+/* For single bit shift insns, record assembler and whether the condition code
+   is valid afterwards.  */
+
+struct shift_insn
+{
+  char *assembler;
+  int cc_valid;
+};
+
+/* Assembler instruction shift table.
+
+   These tables are used to look up the basic shifts.
+   They are indexed by cpu, shift_type, and mode.
+*/
 
-      /* Can't define expand a loop after rtl generation.  */
-      if (! rtx_equal_function_value_matters)
-       return 0;
+static const struct shift_insn shift_one[2][3][3] =
+{
+/* H8/300 */
+  {
+/* SHIFT_ASHIFT */
+    {
+      { "shal %X0", 1 },
+      { "add.w %T0,%T0\t; shal.w", 1 },
+      { "add.w %f0,%f0\t; shal.l\n\taddx %y0,%y0\n\taddx %z0,%z0\t; end shal.l", 0 }
+    },
+/* SHIFT_LSHIFTRT */
+    {
+      { "shlr %X0", 1 },
+      { "shlr %t0\t; shlr.w\n\trotxr %s0\t; end shlr.w", 0 },
+      { "shlr %z0\t; shlr.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shlr.l", 0 }
+    },
+/* SHIFT_ASHIFTRT */
+    {
+      { "shar %X0", 1 },
+      { "shar %t0\t; shar.w\n\trotxr %s0\t; end shar.w", 0 },
+      { "shar %z0\t; shar.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shar.l", 0 }
+    }
+  },
+/* H8/300H */
+  {
+/* SHIFT_ASHIFT */
+    {
+      { "shal.b %X0", 1 },
+      { "shal.w %T0", 1 },
+      { "shal.l %S0", 1 }
+    },
+/* SHIFT_LSHIFTRT */
+    {
+      { "shlr.b %X0", 1 },
+      { "shlr.w %T0", 1 },
+      { "shlr.l %S0", 1 }
+    },
+/* SHIFT_ASHIFTRT */
+    {
+      { "shar.b %X0", 1 },
+      { "shar.w %T0", 1 },
+      { "shar.l %S0", 1 }
+    }
+  }
+};
 
-      lval = gen_reg_rtx (QImode);
+/* Rotates are organized by which shift they'll be used in implementing.
+   There's no need to record whether the cc is valid afterwards because
+   it is the AND insn that will decide this.  */
 
-      convert_move (lval, operands[2], 1);
-      shift_n_bits (lval, operands[0], f, 0);
+static const char *const rotate_one[2][3][3] =
+{
+/* H8/300 */
+  {
+/* SHIFT_ASHIFT */
+    {
+      "rotr %X0",
+      "shlr %t0\t; rotr.w\n\trotxr %s0\n\tbst #7,%t0\t; end rotr.w",
+      0
+    },
+/* SHIFT_LSHIFTRT */
+    {
+      "rotl %X0",
+      "shll %s0\t; rotl.w\n\trotxl %t0\n\tbst #0,%s0\t; end rotl.w",
+      0
+    },
+/* SHIFT_ASHIFTRT */
+    {
+      "rotl %X0",
+      "shll %s0\t; rotl.w\n\trotxl %t0\n\tbst #0,%s0\t; end rotl.w",
+      0
     }
-  else
+  },
+/* H8/300H */
+  {
+/* SHIFT_ASHIFT */
+    {
+      "rotr.b %X0",
+      "rotr.w %T0",
+      "rotr.l %S0"
+    },
+/* SHIFT_LSHIFTRT */
     {
-      int i;
+      "rotl.b %X0",
+      "rotl.w %T0",
+      "rotl.l %S0"
+    },
+/* SHIFT_ASHIFTRT */
+    {
+      "rotl.b %X0",
+      "rotl.w %T0",
+      "rotl.l %S0"
+    }
+  }
+};
+
+/* Given CPU, MODE, SHIFT_TYPE, and shift count COUNT, determine the best
+   algorithm for doing the shift.  The assembler code is stored in ASSEMBLER.
+   We don't achieve maximum efficiency in all cases, but the hooks are here
+   to do so.
+
+   For now we just use lots of switch statements.  Since we don't even come
+   close to supporting all the cases, this is simplest.  If this function ever
+   gets too big, perhaps resort to a more table based lookup.  Of course,
+   at this point you may just wish to do it all in rtl.
+
+   WARNING: The constraints on insns shiftbyn_QI/HI/SI assume shifts of
+   1,2,3,4 will be inlined (1,2 for SI).  */
+
+static enum shift_alg
+get_shift_alg (cpu, shift_type, mode, count, assembler_p, cc_valid_p)
+     enum attr_cpu cpu;
+     enum shift_type shift_type;
+     enum machine_mode mode;
+     int count;
+     const char **assembler_p;
+     int *cc_valid_p;
+{
+  /* The default is to loop.  */
+  enum shift_alg alg = SHIFT_LOOP;
+  enum shift_mode shift_mode;
+
+  /* We don't handle negative shifts or shifts greater than the word size,
+     they should have been handled already.  */
 
-      i = INTVAL (operands[2]);
-      if (i >= 8 && fby_eight)
+  if (count < 0 || count > GET_MODE_BITSIZE (mode))
+    abort ();
+
+  switch (mode)
+    {
+    case QImode:
+      shift_mode = QIshift;
+      break;
+    case HImode:
+      shift_mode = HIshift;
+      break;
+    case SImode:
+      shift_mode = SIshift;
+      break;
+    default:
+      abort ();
+    }
+
+  /* Assume either SHIFT_LOOP or SHIFT_INLINE.
+     It is up to the caller to know that looping clobbers cc.  */
+  *assembler_p = shift_one[cpu][shift_type][shift_mode].assembler;
+  *cc_valid_p = shift_one[cpu][shift_type][shift_mode].cc_valid;
+
+  /* Now look for cases we want to optimize.  */
+
+  switch (shift_mode)
+    {
+    case QIshift:
+      if (count <= 4)
+       return SHIFT_INLINE;
+      else if (count <= 6)
        {
-         fby_eight (operands[0]);
-         i -= 8;
+         if (shift_type == SHIFT_ASHIFTRT)
+           {
+             return SHIFT_LOOP;
+           }
+         else
+           {
+             *assembler_p = rotate_one[cpu][shift_type][shift_mode];
+             *cc_valid_p = 0;
+             return SHIFT_ROT_AND;
+           }
        }
-      if (i > limit)
+      else if (count == 7)
        {
-         rtx lval;
-
-         /* Can't define expand a loop after rtl generation.  */
-         if (! rtx_equal_function_value_matters)
-           return 0;
-         lval = gen_reg_rtx (QImode);
-         emit_move_insn (lval, gen_rtx (CONST_INT, VOIDmode, i));
-         shift_n_bits (lval, operands[0], f, 1);
+         if (shift_type == SHIFT_ASHIFTRT)
+           {
+             *assembler_p = "shll %X0\t; shar.b(7)\n\tsubx %X0,%X0\t; end shar.b(7)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           }
+         else
+           {
+             *assembler_p = rotate_one[cpu][shift_type][shift_mode];
+             *cc_valid_p = 0;
+             return SHIFT_ROT_AND;
+           }
        }
-      else
+      break;
+    case HIshift:
+      if (count <= 4)
+       return SHIFT_INLINE;
+      else if (count == 8)
+       {
+         switch (shift_type)
+           {
+           case SHIFT_ASHIFT:
+             *assembler_p = "mov.b %s0,%t0\t; shal.w(8)\n\tsub.b %s0,%s0\t; end shal.w(8)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           case SHIFT_LSHIFTRT:
+             *assembler_p = "mov.b %t0,%s0\t; shlr.w(8)\n\tsub.b %t0,%t0\t; end shlr.w(8)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           case SHIFT_ASHIFTRT:
+             if (cpu == CPU_H8300)
+               *assembler_p = "mov.b %t0,%s0\t; shar.w(8)\n\tshll %t0\n\tsubx %t0,%t0\t; end shar.w(8)";
+             else
+               *assembler_p = "mov.b %t0,%s0\t; shar.w(8)\n\texts.w %T0\t; end shar.w(8)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           }
+         abort ();
+       }
+      else if (count == 15)
        {
-         while (i--)
-           f (operands[0]);
+         if (shift_type == SHIFT_ASHIFTRT)
+           {
+             *assembler_p = "shll %t0,%t0\t; shar.w(15)\n\tsubx %t0,%t0\n\tmov.b %t0,%s0\t; end shar.w(15)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           }
+         else
+           {
+             *assembler_p = rotate_one[cpu][shift_type][shift_mode];
+             *cc_valid_p = 0;
+             return SHIFT_ROT_AND;
+           }
        }
+      break;
+    case SIshift:
+      if (count <= (cpu == CPU_H8300 ? 2 : 4))
+       return SHIFT_INLINE;
+      else if (count == 8)
+       {
+         if (cpu == CPU_H8300)
+           {
+             switch (shift_type)
+               {
+               case SHIFT_ASHIFT:
+                 *assembler_p = "mov.b %y0,%z0\t; shal.l(8)\n\tmov.b %x0,%y0\n\tmov.b %w0,%x0\n\tsub.b %w0,%w0\t; end shal.l(8)";
+                 *cc_valid_p = 0;
+                 return SHIFT_SPECIAL;
+               case SHIFT_LSHIFTRT:
+                 *assembler_p = "mov.b %x0,%w0\t; shlr.l(8)\n\tmov.b %y0,%x0\n\tmov.b %z0,%y0\n\tsub.b %z0,%z0\t; end shlr.l(8)";
+                 *cc_valid_p = 0;
+                 return SHIFT_SPECIAL;
+               case SHIFT_ASHIFTRT:
+                 *assembler_p = "mov.b %x0,%w0\t; shar.l(8)\n\tmov.b %y0,%x0\n\tmov.b %z0,%y0\n\tshll %z0\n\tsubx %z0,%z0; end shar.l(8)";
+                 *cc_valid_p = 0;
+                 return SHIFT_SPECIAL;
+               }
+           }
+         else                  /* CPU_H8300H */
+           /* We don't have byte level access to the high word so this isn't
+              easy to do.  For now, just loop.  */
+           ;
+       }
+      else if (count == 16)
+       {
+         switch (shift_type)
+           {
+           case SHIFT_ASHIFT:
+             *assembler_p = "mov.w %f0,%e0\t; shal.l(16)\n\tsub.w %f0,%f0\t; end shal.l(16)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           case SHIFT_LSHIFTRT:
+             *assembler_p = "mov.w %e0,%f0\t; shlr.l(16)\n\tsub.w %e0,%e0\t; end shlr.l(16)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           case SHIFT_ASHIFTRT:
+             if (cpu == CPU_H8300)
+               *assembler_p = "mov.w %e0,%f0\t; shar.l(16)\n\tshll %z0\n\tsubx %z0,%z0\n\tmov.b %z0,%y0\t; end shar.l(16)";
+             else
+               *assembler_p = "mov.w %e0,%f0\t; shar.l(16)\n\texts.l %S0\t; end shar.l(16)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           }
+       }
+      else if (count >= 28 && count <= 30)
+       {
+         if (shift_type == SHIFT_ASHIFTRT)
+           {
+             return SHIFT_LOOP;
+           }
+         else
+           {
+             if (cpu == CPU_H8300)
+               return SHIFT_LOOP;
+             else
+               {
+                 *assembler_p = rotate_one[cpu][shift_type][shift_mode];
+                 *cc_valid_p = 0;
+                 return SHIFT_ROT_AND;
+               }
+           }
+       }
+      else if (count == 31)
+       {
+         if (shift_type == SHIFT_ASHIFTRT)
+           {
+             if (cpu == CPU_H8300)
+               *assembler_p = "shll %z0\t; shar.l(31)\n\tsubx %w0,%w0\n\tmov.b %w0,%x0\n\tmov.w %f0,%e0\t; end shar.l(31)";
+             else
+               *assembler_p = "shll %e0\t; shar.l(31)\n\tsubx %w0,%w0\n\tmov.b %w0,%x0\n\tmov.w %f0,%e0\t; end shar.l(31)";
+             *cc_valid_p = 0;
+             return SHIFT_SPECIAL;
+           }
+         else
+           {
+             if (cpu == CPU_H8300)
+               {
+                 if (shift_type == SHIFT_ASHIFT)
+                   *assembler_p = "sub.w %e0,%e0\t; shal.l(31)\n\tshlr %w0\n\tmov.w %e0,%f0\n\trotxr %z0\t; end shal.l(31)";
+                 else
+                   *assembler_p = "sub.w %f0,%f0\t; shlr.l(31)\n\tshll %z0\n\tmov.w %f0,%e0\n\trotxl %w0\t; end shlr.l(31)";
+                 *cc_valid_p = 0;
+                 return SHIFT_SPECIAL;
+               }
+             else
+               {
+                 *assembler_p = rotate_one[cpu][shift_type][shift_mode];
+                 *cc_valid_p = 0;
+                 return SHIFT_ROT_AND;
+               }
+           }
+       }
+      break;
+    default:
+      abort ();
     }
-  return 1;
+
+  return alg;
 }
 
-int
-domovsi (operands)
-     rtx operands[];
+/* Emit the assembler code for doing shifts.  */
+
+char *
+emit_a_shift (insn, operands)
+     rtx insn;
+     rtx *operands;
 {
-  rtx src = operands[1];
-  rtx dst = operands[0];
+  static int loopend_lab;
+  char *assembler;
+  int cc_valid;
+  rtx inside = PATTERN (insn);
+  rtx shift = operands[3];
+  enum machine_mode mode = GET_MODE (shift);
+  enum rtx_code code = GET_CODE (shift);
+  enum shift_type shift_type;
+  enum shift_mode shift_mode;
+
+  loopend_lab++;
+
+  switch (mode)
+    {
+    case QImode:
+      shift_mode = QIshift;
+      break;
+    case HImode:
+      shift_mode = HIshift;
+      break;
+    case SImode:
+      shift_mode = SIshift;
+      break;
+    default:
+      abort ();
+    }
 
-  if (push_operand (dst, GET_MODE (dst)))
+  switch (code)
     {
-      /* Source must be a reg.  */
-      if (! REG_P (src))
-       {
-         rtx tmp = gen_reg_rtx (GET_MODE (dst));
+    case ASHIFTRT:
+      shift_type = SHIFT_ASHIFTRT;
+      break;
+    case LSHIFTRT:
+      shift_type = SHIFT_LSHIFTRT;
+      break;
+    case ASHIFT:
+      shift_type = SHIFT_ASHIFT;
+      break;
+    default:
+      abort ();
+    }
 
-         emit_move_insn (tmp, src);
-         operands[1] = tmp;
+  if (GET_CODE (operands[2]) != CONST_INT)
+    {
+      /* Indexing by reg, so have to loop and test at top */
+      output_asm_insn ("mov.b  %X2,%X4", operands);
+      fprintf (asm_out_file, "\tble    .Lle%d\n", loopend_lab);
+
+      /* Get the assembler code to do one shift.  */
+      get_shift_alg (cpu_type, shift_type, mode, 1, &assembler, &cc_valid);
+    }
+  else
+    {
+      int n = INTVAL (operands[2]);
+      enum shift_alg alg;
+
+      /* If the count is negative, make it 0.  */
+      if (n < 0)
+       n = 0;
+      /* If the count is too big, truncate it.
+         ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to
+        do the intuitive thing.  */
+      else if (n > GET_MODE_BITSIZE (mode))
+       n = GET_MODE_BITSIZE (mode);
+
+      alg = get_shift_alg (cpu_type, shift_type, mode, n, &assembler, &cc_valid);
+
+      switch (alg)
+       {
+       case SHIFT_INLINE:
+         while (--n >= 0)
+           output_asm_insn (assembler, operands);
+         if (cc_valid)
+           cc_status.value1 = operands[0];
+         return "";
+       case SHIFT_ROT_AND:
+         {
+           int m = GET_MODE_BITSIZE (mode) - n;
+           int mask = (shift_type == SHIFT_ASHIFT
+                       ? ((1 << GET_MODE_BITSIZE (mode) - n) - 1) << n
+                       : (1 << GET_MODE_BITSIZE (mode) - n) - 1);
+           char insn_buf[200];
+           /* Not all possibilities of rotate are supported.  They shouldn't
+              be generated, but let's watch for 'em.  */
+           if (assembler == 0)
+             abort ();
+           while (--m >= 0)
+             output_asm_insn (assembler, operands);
+           if (TARGET_H8300)
+             {
+               switch (mode)
+                 {
+                 case QImode:
+                   sprintf (insn_buf, "and #%d,%%X0\t; end shift %d via rotate+and",
+                            mask, n);
+                   cc_status.value1 = operands[0];
+                   break;
+                 case HImode:
+                   sprintf (insn_buf, "and #%d,%%s0\n\tand #%d,%%t0\t; end shift %d via rotate+and",
+                            mask & 255, mask >> 8, n);
+                   break;
+                 case SImode:
+                   abort ();
+                 }
+             }
+           else
+             {
+               sprintf (insn_buf, "and.%c #%d,%%%c0",
+                        "bwl"[shift_mode], mask,
+                        mode == QImode ? 'X' : mode == HImode ? 'T' : 'S');
+               cc_status.value1 = operands[0];
+             }
+           output_asm_insn (insn_buf, operands);
+           return "";
+         }
+       case SHIFT_SPECIAL:
+         output_asm_insn (assembler, operands);
+         return "";
        }
+
+      /* Need a loop, move limit to tmp reg */
+      fprintf (asm_out_file, "\tmov.b  #%d,%sl\n", n, names_big[REGNO (operands[4])]);
     }
-  return 0;
+
+  fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
+  output_asm_insn (assembler, operands);
+  output_asm_insn ("add        #0xff,%X4", operands);
+  fprintf (asm_out_file, "\tbne        .Llt%d\n", loopend_lab);
+  fprintf (asm_out_file, ".Lle%d:\n", loopend_lab);
+
+  return "";
 }
+\f
+/* Fix the operands of a gen_xxx so that it could become a bit
+  operating insn.  */
 
 int
-io (FROM, TO)
+fix_bit_operand (operands, what, type)
+     rtx *operands;
+     char what;
+     enum rtx_code type;
 {
-  int OFFSET = 0;
+  /* The bit_operand predicate accepts any memory durint RTL generation, but
+     only 'U' memory afterwards, so if this is a MEM operand, we must force
+     it to be valid for 'U' by reloading the address.  */
 
-  if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM)
-    (OFFSET) = 2 + frame_pointer_needed * 2;
-  else
+  if (GET_CODE (operands[2]) == CONST_INT)
     {
-      int regno;
-      int offset = 0;
-
-      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-       if ((regs_ever_live[regno]
-            && (! call_used_regs[regno] || regno == FRAME_POINTER_REGNUM)))
-         offset += 2;
+      if (CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), what))
+       {
+         /* Ok to have a memory dest.  */
+         if (GET_CODE (operands[0]) == MEM && !EXTRA_CONSTRAINT (operands[0], 'U'))
+           {
+             rtx mem;
+             mem = gen_rtx (MEM, GET_MODE (operands[0]),
+                          copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
+             RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[0]);
+             MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[0]);
+             MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]);
+             operands[0] = mem;
+           }
+
+         if (GET_CODE (operands[1]) == MEM && !EXTRA_CONSTRAINT (operands[1], 'U'))
+           {
+             rtx mem;
+             mem = gen_rtx (MEM, GET_MODE (operands[1]),
+                          copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+             RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[1]);
+             MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[1]);
+             MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]);
+             operands[1] = mem;
+           }
+         return 0;
+       }
+    }
 
-      (OFFSET) = offset + get_frame_size ();
+  /* Dest and src op must be register.  */
 
-      if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)
-       (OFFSET) += 2;          /* Skip saved PC.  */
-    }
-  return OFFSET;
+  operands[1] = force_reg (QImode, operands[1]);
+  {
+    rtx res = gen_reg_rtx (QImode);
+    emit_insn (gen_rtx (SET, VOIDmode, res, gen_rtx (type, QImode, operands[1], operands[2])));
+    emit_insn (gen_rtx (SET, VOIDmode, operands[0], res));
+  }
+  return 1;
 }
This page took 0.077211 seconds and 5 git commands to generate.