README.C4X: New file with information about the c4x ports.
authorMichael Hayes <mph@elec.canterbury.ac.nz>
Sat, 19 Sep 1998 00:03:07 +0000 (00:03 +0000)
committerJeff Law <law@gcc.gnu.org>
Sat, 19 Sep 1998 00:03:07 +0000 (18:03 -0600)
        * README.C4X: New file with information about the c4x ports.
        * ginclude/va-c4x.h: New file for c4x varargs support.
        * config/c4x: New directory with c4x port files.

From-SVN: r22475

gcc/ChangeLog
gcc/README.C4X [new file with mode: 0644]
gcc/config/c4x/c4x.c [new file with mode: 0644]
gcc/config/c4x/c4x.h [new file with mode: 0644]
gcc/config/c4x/c4x.md [new file with mode: 0644]
gcc/config/c4x/t-c4x [new file with mode: 0644]
gcc/config/c4x/xm-c4x.h [new file with mode: 0644]
gcc/ginclude/va-c4x.h [new file with mode: 0644]

index 4519495..6caede7 100644 (file)
@@ -1,3 +1,9 @@
+Sat Sep 19 01:00:32 1998  Michael Hayes  (mph@elec.canterbury.ac.nz)
+
+       * README.C4X: New file with information about the c4x ports.
+       * ginclude/va-c4x.h: New file for c4x varargs support.
+       * config/c4x: New directory with c4x port files.
+
 Fri Sep 18 22:52:05 1998  Jeffrey A Law  (law@cygnus.com)
 
        * reload.c (find_reloads): Do not replace a pseudo with 
diff --git a/gcc/README.C4X b/gcc/README.C4X
new file mode 100644 (file)
index 0000000..c8c5f22
--- /dev/null
@@ -0,0 +1,48 @@
+This file describes the implementation notes of the GNU C Compiler for
+the Texas Instruments Floating Point Digital Signal Processor
+families, TMS320C3x and TMS320C4x (including the C30, C31, C32, C40,
+and C44 chips).
+
+
+Currently, only two code variants are generated---those for the C3x
+and C4x architectures.  Note that the new operand combinations for
+parallel instructions, included in newer silicon revisions, are not
+yet supported.  These should be trivial to add for someone with the
+newer chips and the inclination.
+
+
+While the generated assembly code is fairly similar to that recognised
+by the TI assembler, there are a few differences (currently the machine
+option -mti, designed to enfore compatibility, is not fully
+implemented).  The major difference is the use of the ^ operator to
+load the 16 MSBs of an address or constant for the C4x.
+
+
+The generated assembly code requires the GNU assembler (GAS).  This is
+not currently included as part of the binutils package, due to the
+many hacks required to be compatible with TI's kludged COFF
+implementation, and the binutils not being designed for 32-bit bytes.
+Patches against binutils-2.7.2 can be obtained from
+ftp://ongaonga.chch.cri.nz/pub/c4x.  This site also has patches for
+the GNU debugger (GDB), incoporating a cycle accurate simulator that
+can display profiles and histories of code execution, detailing
+pipeline conflicts etc.
+
+
+GCC can be configured as a cross compiler for both the C3x and C4x
+architectures on the same system.  Use `configure --target=c4x' to
+configure GCC for both the C3x and C4x.  Then use the -m30 option to
+generate code for the C30 or -m40 (the default) for the C40.
+
+
+Further installation notes and other optimization patches for GCC can
+also be obtained from ftp://ongaonga.chch.cri.nz/pub/c4x.
+
+
+A Majordomo mailing list, gcc_c40@atlantek.com.au, exists to discuss
+related issues and suggestions for further optimizations.  To
+subscribe send a message with `subscribe gcc_c40' in the body to
+majordomo@atlantek.com.au.
+
+
+Michael Hayes,  16 Sep 98
diff --git a/gcc/config/c4x/c4x.c b/gcc/config/c4x/c4x.c
new file mode 100644 (file)
index 0000000..f6b75c1
--- /dev/null
@@ -0,0 +1,5597 @@
+/* Subroutines for assembler code output on the TMS320C[34]x
+   Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+
+   Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz)
+              and Herman Ten Brugge (Haj.Ten.Brugge@net.HCC.nl).
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Some output-actions in c4x.md need these.  */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "config.h"
+#include "gansidecl.h"
+#include "toplev.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "real.h"
+#include "insn-config.h"
+#include "insn-attr.h"
+#include "insn-codes.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "tree.h"
+#include "expr.h"
+#include "flags.h"
+#include "loop.h"
+#include "recog.h"
+#include "c-tree.h"
+
+extern void iteration_info (); /* in unroll.c */
+
+static int c4x_leaf_function;
+
+static char *float_reg_names[] = FLOAT_REGISTER_NAMES;
+
+/* Array of the smallest class containing reg number REGNO, indexed by
+   REGNO.  Used by REGNO_REG_CLASS in c4x.h.  We assume that all these
+   registers are available and set the class to NO_REGS for registers 
+   that the target switches say are unavailable.  */
+
+enum reg_class c4x_regclass_map[FIRST_PSEUDO_REGISTER] =
+{
+                                /* Reg          Modes           Saved  */
+  R0R1_REGS,                   /* R0           QI, QF, HF      No  */
+  R0R1_REGS,                   /* R1           QI, QF, HF      No  */
+  R2R3_REGS,                   /* R2           QI, QF, HF      No  */
+  R2R3_REGS,                   /* R3           QI, QF, HF      No  */
+  EXT_LOW_REGS,                        /* R4           QI, QF, HF      QI  */
+  EXT_LOW_REGS,                        /* R5           QI, QF, HF      QI  */
+  EXT_LOW_REGS,                        /* R6           QI, QF, HF      QF  */
+  EXT_LOW_REGS,                        /* R7           QI, QF, HF      QF  */
+  ADDR_REGS,                   /* AR0          QI              No  */
+  ADDR_REGS,                   /* AR1          QI              No  */
+  ADDR_REGS,                   /* AR2          QI              No  */
+  ADDR_REGS,                   /* AR3          QI              QI  */
+  ADDR_REGS,                   /* AR4          QI              QI  */
+  ADDR_REGS,                   /* AR5          QI              QI  */
+  ADDR_REGS,                   /* AR6          QI              QI  */
+  ADDR_REGS,                   /* AR7          QI              QI  */
+  DP_REG,                      /* DP           QI              No  */
+  INDEX_REGS,                  /* IR0          QI              No  */
+  INDEX_REGS,                  /* IR1          QI              No  */
+  BK_REG,                      /* BK           QI              QI  */
+  SP_REG,                      /* SP           QI              No  */
+  ST_REG,                      /* ST           CC              No  */
+  NO_REGS,                     /* DIE/IE                       No  */
+  NO_REGS,                     /* IIE/IF                       No  */
+  NO_REGS,                     /* IIF/IOF                      No  */
+  INT_REGS,                    /* RS           QI              No  */
+  INT_REGS,                    /* RE           QI              No  */
+  INT_REGS,                    /* RC           QI              No  */
+  EXT_REGS,                    /* R8           QI, QF, HF      QI  */
+  EXT_REGS,                    /* R9           QI, QF, HF      No  */
+  EXT_REGS,                    /* R10          QI, QF, HF      No  */
+  EXT_REGS,                    /* R11          QI, QF, HF      No  */
+};
+
+enum machine_mode c4x_caller_save_map[FIRST_PSEUDO_REGISTER] =
+{
+                                /* Reg          Modes           Saved  */
+  HFmode,                      /* R0           QI, QF, HF      No  */
+  HFmode,                      /* R1           QI, QF, HF      No  */
+  HFmode,                      /* R2           QI, QF, HF      No  */
+  HFmode,                      /* R3           QI, QF, HF      No  */
+  QFmode,                      /* R4           QI, QF, HF      QI  */
+  QFmode,                      /* R5           QI, QF, HF      QI  */
+  QImode,                      /* R6           QI, QF, HF      QF  */
+  QImode,                      /* R7           QI, QF, HF      QF  */
+  QImode,                      /* AR0          QI              No  */
+  QImode,                      /* AR1          QI              No  */
+  QImode,                      /* AR2          QI              No  */
+  QImode,                      /* AR3          QI              QI  */
+  QImode,                      /* AR4          QI              QI  */
+  QImode,                      /* AR5          QI              QI  */
+  QImode,                      /* AR6          QI              QI  */
+  QImode,                      /* AR7          QI              QI  */
+  VOIDmode,                    /* DP           QI              No  */
+  QImode,                      /* IR0          QI              No  */
+  QImode,                      /* IR1          QI              No  */
+  QImode,                      /* BK           QI              QI  */
+  VOIDmode,                    /* SP           QI              No  */
+  VOIDmode,                    /* ST           CC              No  */
+  VOIDmode,                    /* DIE/IE                       No  */
+  VOIDmode,                    /* IIE/IF                       No  */
+  VOIDmode,                    /* IIF/IOF                      No  */
+  QImode,                      /* RS           QI              No  */
+  QImode,                      /* RE           QI              No  */
+  QImode,                      /* RC           QI              No  */
+  QFmode,                      /* R8           QI, QF, HF      QI  */
+  HFmode,                      /* R9           QI, QF, HF      No  */
+  HFmode,                      /* R10          QI, QF, HF      No  */
+  HFmode,                      /* R11          QI, QF, HF      No  */
+};
+
+
+/* rptb_info has enough information to compute rtx for loop counter.  */
+typedef struct
+{
+  int loop_count;              /* Positive if loop count is constant */
+  /* The rest of fields are meaningless if loop_count is set */
+  rtx start_value;             /* Starting value for biv */
+  rtx end_value;               /* Limit for biv */
+  int swap_p;                  /* 1 for count down */
+  int incr;                    /* Increment for biv -- must be constant */
+  int shift;                   /* log2(incr) */
+  int off_by_one;              /* 1 for "<", 0 for "<=" */
+  int unsigned_p;              /* True if unsigned comparison at loop end */
+  rtx loop_start;
+}
+c4x_rptb_info_t;
+
+/* Test and compare insns in c4x.md store the information needed to
+   generate branch and scc insns here.  */
+
+struct rtx_def *c4x_compare_op0 = NULL_RTX;
+struct rtx_def *c4x_compare_op1 = NULL_RTX;
+
+char *c4x_rpts_cycles_string;
+int c4x_rpts_cycles = 0;       /* Max. cycles for RPTS */
+char *c4x_cpu_version_string;
+int c4x_cpu_version = 40;      /* CPU version C30/31/32/40/44 */
+
+/* Pragma definitions.  */
+
+tree code_tree = NULL_TREE;
+tree data_tree = NULL_TREE;
+tree pure_tree = NULL_TREE;
+tree noreturn_tree = NULL_TREE;
+tree interrupt_tree = NULL_TREE;
+
+static void
+c4x_dump (file, s)
+     FILE * file;
+     const char *s;
+     ...
+{
+#ifndef __STDC__
+  char *s;
+#endif
+  va_list ap;
+
+  if (!file)
+    return;
+
+  VA_START (ap, s);
+
+#ifndef __STDC__
+  s = va_arg (ap, char *);
+#endif
+
+  vfprintf (file, s, ap);
+  va_end (ap);
+}
+
+/* Override command line options.
+   Called once after all options have been parsed.
+   Mostly we process the processor
+   type and sometimes adjust other TARGET_ options.  */
+
+void
+c4x_override_options ()
+{
+  /* Convert foo / 8.0 into foo * 0.125, etc.  */
+  flag_fast_math = 1;
+
+  if (c4x_rpts_cycles_string)
+    c4x_rpts_cycles = atoi (c4x_rpts_cycles_string);
+  else
+    c4x_rpts_cycles = 0;
+
+  if (TARGET_C30)
+    c4x_cpu_version = 30;
+  else if (TARGET_C31)
+    c4x_cpu_version = 31;
+  else if (TARGET_C32)
+    c4x_cpu_version = 32;
+  else if (TARGET_C40)
+    c4x_cpu_version = 40;
+  else if (TARGET_C44)
+    c4x_cpu_version = 44;
+  else
+    c4x_cpu_version = 40;             
+
+  /* -mcpu=xx overrides -m40 etc.  */
+  if (c4x_cpu_version_string)
+    c4x_cpu_version = atoi (c4x_cpu_version_string);
+
+  target_flags &= ~(C30_FLAG | C31_FLAG | C32_FLAG | C40_FLAG | C44_FLAG);
+
+  switch (c4x_cpu_version)
+    {
+    case 30: target_flags |= C30_FLAG; break;
+    case 31: target_flags |= C31_FLAG; break;
+    case 32: target_flags |= C32_FLAG; break;
+    case 40: target_flags |= C40_FLAG; break;
+    case 44: target_flags |= C44_FLAG; break;
+    default:
+      warning ("Unknown CPU version %d, using 40.\n", c4x_cpu_version);
+      c4x_cpu_version = 40;
+      target_flags |= C40_FLAG;
+    }
+
+  if (TARGET_C30 || TARGET_C31 || TARGET_C32)
+    target_flags |= C3X_FLAG;
+  else
+    target_flags &= ~C3X_FLAG;
+
+}
+
+
+/* Write an ASCII string.  */
+
+#define C4X_ASCII_LIMIT 40
+
+void
+c4x_output_ascii (stream, ptr, len)
+     FILE *stream;
+     unsigned char *ptr;
+     int len;
+{
+  char sbuf[C4X_ASCII_LIMIT + 1];
+  int s, first, onlys;
+
+  if (len)
+    {
+      fprintf (stream, "\t.byte\t");
+      first = 1;
+    }
+
+  for (s = 0; len > 0; --len, ++ptr)
+    {
+      onlys = 0;
+
+      /* Escape " and \ with a \".  */
+      if (*ptr == '\"' || *ptr == '\\')
+       sbuf[s++] = '\\';
+
+      /* If printable - add to buff.  */
+      if (*ptr >= 0x20 && *ptr < 0x7f)
+       {
+         sbuf[s++] = *ptr;
+         if (s < C4X_ASCII_LIMIT - 1)
+           continue;
+         onlys = 1;
+       }
+      if (s)
+       {
+         if (first)
+           first = 0;
+         else
+           fputc (',', stream);
+
+         sbuf[s] = 0;
+         fprintf (stream, "\"%s\"", sbuf);
+         s = 0;
+       }
+      if (onlys)
+       continue;
+
+      if (first)
+       first = 0;
+      else
+       fputc (',', stream);
+
+      fprintf (stream, "%d", *ptr);
+    }
+  if (s)
+    {
+      if (!first)
+       fputc (',', stream);
+
+      sbuf[s] = 0;
+      fprintf (stream, "\"%s\"", sbuf);
+      s = 0;
+    }
+  fputc ('\n', stream);
+}
+
+
+int
+c4x_hard_regno_mode_ok (regno, mode)
+     int regno;
+     enum machine_mode mode;
+{
+  switch (mode)
+    {
+#if Pmode != QImode
+    case Pmode:                        /* Pointer (24/32 bits) */
+#endif
+    case QImode:               /* Integer (32 bits) */
+      return IS_INT_REG (regno);
+
+    case QFmode:               /* Float, Double (32 bits) */
+    case HFmode:               /* Long Double (40 bits) */
+      return IS_EXT_REG (regno);
+
+    case CCmode:               /* Condition Codes */
+    case CC_NOOVmode:          /* Condition Codes */
+      return IS_ST_REG (regno);
+
+    case HImode:               /* Long Long (64 bits) */
+      /* We need two registers to store long longs.  Note that 
+        it is much easier to constrain the first register
+        to start on an even boundary.  */
+      return IS_INT_REG (regno)
+       && IS_INT_REG (regno + 1)
+       && (regno & 1) == 0;
+
+    default:
+      return 0;                        /* We don't support these modes */
+    }
+
+  return 0;
+}
+
+
+/* The TI C3x C compiler register argument runtime model uses 6 registers,
+   AR2, R2, R3, RC, RS, RE.
+
+   The first two floating point arguments (float, double, long double)
+   that are found scanning from left to right are assigned to R2 and R3.
+
+   The remaining integer (char, short, int, long) or pointer arguments
+   are assigned to the remaining registers in the order AR2, R2, R3,
+   RC, RS, RE when scanning left to right, except for the last named
+   argument prior to an ellipsis denoting variable number of
+   arguments.  We don't have to worry about the latter condition since
+   function.c treats the last named argument as anonymous (unnamed).
+
+   All arguments that cannot be passed in registers are pushed onto
+   the stack in reverse order (right to left).  GCC handles that for us.
+
+   c4x_init_cumulative_args() is called at the start, so we can parse
+   the args to see how many floating point arguments and how many
+   integer (or pointer) arguments there are.  c4x_function_arg() is
+   then called (sometimes repeatedly) for each argument (parsed left
+   to right) to obtain the register to pass the argument in, or zero
+   if the argument is to be passed on the stack.  Once the compiler is
+   happy, c4x_function_arg_advance() is called.
+
+   Don't use R0 to pass arguments in, we use 0 to indicate a stack
+   argument.  */
+
+static int c4x_int_reglist[3][6] =
+{
+  {AR2_REGNO, R2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO},
+  {AR2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0},
+  {AR2_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0, 0}
+};
+
+static int c4x_fp_reglist[2] = {R2_REGNO, R3_REGNO};
+
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a
+   function whose data type is FNTYPE.
+   For a library call, FNTYPE is  0.  */
+
+void
+c4x_init_cumulative_args (cum, fntype, libname)
+     CUMULATIVE_ARGS *cum;     /* argument info to initialize */
+     tree fntype;              /* tree ptr for function decl */
+     rtx libname;              /* SYMBOL_REF of library name or 0 */
+{
+  tree param, next_param;
+
+  cum->floats = cum->ints = 0;
+  cum->init = 0;
+  cum->var = 0;
+  cum->args = 0;
+
+  if (TARGET_DEBUG)
+    {
+      fprintf (stderr, "\nc4x_init_cumulative_args (");
+      if (fntype)
+       {
+         tree ret_type = TREE_TYPE (fntype);
+
+         fprintf (stderr, "fntype code = %s, ret code = %s",
+                  tree_code_name[(int) TREE_CODE (fntype)],
+                  tree_code_name[(int) TREE_CODE (ret_type)]);
+       }
+      else
+       fprintf (stderr, "no fntype");
+
+      if (libname)
+       fprintf (stderr, ", libname = %s", XSTR (libname, 0));
+    }
+
+  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
+
+  for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
+       param; param = next_param)
+    {
+      tree type;
+
+      next_param = TREE_CHAIN (param);
+
+      type = TREE_VALUE (param);
+      if (type && type != void_type_node)
+       {
+         enum machine_mode mode;
+
+         /* If the last arg doesn't have void type then we have
+            variable arguments.  */
+         if (!next_param)
+           cum->var = 1;
+
+         if ((mode = TYPE_MODE (type)))
+           {
+             if (!MUST_PASS_IN_STACK (mode, type))
+               {
+                 /* Look for float, double, or long double argument.  */
+                 if (mode == QFmode || mode == HFmode)
+                   cum->floats++;
+                 /* Look for integer, enumeral, boolean, char, or pointer
+                    argument.  */
+                 else if (mode == QImode || mode == Pmode)
+                   cum->ints++;
+               }
+           }
+         cum->args++;
+       }
+    }
+
+  if (TARGET_DEBUG)
+    fprintf (stderr, "%s%s, args = %d)\n",
+            cum->prototype ? ", prototype" : "",
+            cum->var ? ", variable args" : "",
+            cum->args);
+}
+
+
+/* Update the data in CUM to advance over an argument
+   of mode MODE and data type TYPE.
+   (TYPE is null for libcalls where that information may not be available.)  */
+
+void
+c4x_function_arg_advance (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;     /* current arg information */
+     enum machine_mode mode;   /* current arg mode */
+     tree type;                        /* type of the argument or 0 if lib support */
+     int named;                        /* whether or not the argument was named */
+{
+  if (TARGET_DEBUG)
+    fprintf (stderr, "c4x_function_adv(mode=%s, named=%d)\n\n",
+            GET_MODE_NAME (mode), named);
+  if (!TARGET_MEMPARM 
+      && named
+      && type
+      && !MUST_PASS_IN_STACK (mode, type))
+    {
+      /* Look for float, double, or long double argument.  */
+      if (mode == QFmode || mode == HFmode)
+       cum->floats++;
+      /* Look for integer, enumeral, boolean, char, or pointer argument.  */
+      else if (mode == QImode || mode == Pmode)
+       cum->ints++;
+    }
+  else if (!TARGET_MEMPARM && !type)
+    {
+      /* Handle libcall arguments.  */
+      if (mode == QFmode || mode == HFmode)
+       cum->floats++;
+      else if (mode == QImode || mode == Pmode)
+       cum->ints++;
+    }
+  return;
+}
+
+
+/* Define where to put the arguments to a function.  Value is zero to
+   push the argument on the stack, or a hard register in which to
+   store the argument.
+
+   MODE is the argument's machine mode.
+   TYPE is the data type of the argument (as a tree).
+   This is null for libcalls where that information may
+   not be available.
+   CUM is a variable of type CUMULATIVE_ARGS which gives info about
+   the preceding args and about the function being called.
+   NAMED is nonzero if this argument is a named parameter
+   (otherwise it is an extra parameter matching an ellipsis).  */
+
+struct rtx_def *
+c4x_function_arg (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;     /* current arg information */
+     enum machine_mode mode;   /* current arg mode */
+     tree type;                        /* type of the argument or 0 if lib support */
+     int named;                        /* != 0 for normal args, == 0 for ... args */
+{
+  int reg = 0;                 /* default to passing argument on stack */
+
+  if (!cum->init)
+    {
+      /* We can handle at most 2 floats in R2, R3 */
+      cum->maxfloats = (cum->floats > 2) ? 2 : cum->floats;
+
+      /* We can handle at most 6 integers minus number of floats passed 
+        in registers.  */
+      cum->maxints = (cum->ints > 6 - cum->maxfloats) ? 
+       6 - cum->maxfloats : cum->ints;
+
+      /* If there is no prototype, assume all the arguments are integers. */
+      if (!cum->prototype)
+       cum->maxints = 6;
+
+      cum->ints = cum->floats = 0;
+      cum->init = 1;
+    }
+
+  if (!TARGET_MEMPARM 
+      && named 
+      && type
+      && !MUST_PASS_IN_STACK (mode, type))
+    {
+      /* Look for float, double, or long double argument.  */
+      if (mode == QFmode || mode == HFmode)
+       {
+         if (cum->floats < cum->maxfloats)
+           reg = c4x_fp_reglist[cum->floats];
+       }
+      /* Look for integer, enumeral, boolean, char, or pointer argument.  */
+      else if (mode == QImode || mode == Pmode)
+       {
+         if (cum->ints < cum->maxints)
+           reg = c4x_int_reglist[cum->maxfloats][cum->ints];
+       }
+    }
+  else if (!TARGET_MEMPARM && !type)
+    {
+      /* We could use a different argument calling model for libcalls,
+         since we're only calling functions in libgcc.  Thus we could
+         pass arguments for long longs in registers rather than on the
+         stack.  In the meantime, use the odd TI format.  We make the
+         assumption that we won't have more than two floating point
+         args, six integer args, and that all the arguments are of the
+         same mode.  */
+      if (mode == QFmode || mode == HFmode)
+       reg = c4x_fp_reglist[cum->floats];
+      else if (mode == QImode || mode == Pmode)
+       reg = c4x_int_reglist[0][cum->ints];
+    }
+
+  if (TARGET_DEBUG)
+    {
+      fprintf (stderr, "c4x_function_arg(mode=%s, named=%d",
+              GET_MODE_NAME (mode), named);
+      if (reg)
+       fprintf (stderr, ", reg=%s", reg_names[reg]);
+      else
+       fprintf (stderr, ", stack");
+      fprintf (stderr, ")\n");
+    }
+  if (reg)
+    return gen_rtx (REG, mode, reg);
+  else
+    return NULL_RTX;
+}
+
+
+static int
+c4x_isr_reg_used_p (regno)
+     int regno;
+{
+  /* Don't save/restore FP or ST, we handle them separately.  */
+  if (regno == FRAME_POINTER_REGNUM
+      || IS_ST_REG (regno))
+    return 0;
+
+  /* We could be a little smarter abut saving/restoring DP.
+     We'll only save if for the big memory model or if
+     we're paranoid. ;-)  */
+  if (IS_DP_REG (regno))
+    return !TARGET_SMALL || TARGET_PARANOID;
+
+  /* Only save/restore regs in leaf function that are used.  */
+  if (c4x_leaf_function)
+    return regs_ever_live[regno] && fixed_regs[regno] == 0;
+
+  /* Only save/restore regs that are used by the ISR and regs
+     that are likely to be used by functions the ISR calls
+     if they are not fixed.  */
+  return IS_EXT_REG (regno)
+    || ((regs_ever_live[regno] || call_used_regs[regno]) 
+       && fixed_regs[regno] == 0);
+}
+
+
+static int
+c4x_leaf_function_p ()
+{
+  /* A leaf function makes no calls, so we only need
+     to save/restore the registers we actually use.
+     For the global variable leaf_function to be set, we need
+     to define LEAF_REGISTERS and all that it entails.
+     Let's check ourselves...   */
+
+  if (lookup_attribute ("leaf_pretend",
+                       TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
+    return 1;
+
+  /* Use the leaf_pretend attribute at your own risk.  This is a hack
+     to speed up ISRs that call a function infrequently where the
+     overhead of saving and restoring the additional registers is not
+     warranted.  You must save and restore the additional registers
+     required by the called function.  Caveat emptor.  Here's enough
+     rope...  */
+
+  if (leaf_function_p ())
+    return 1;
+
+  return 0;
+}
+
+
+static int
+c4x_assembler_function_p ()
+{
+  tree type;
+
+  type = TREE_TYPE (current_function_decl);
+  return lookup_attribute ("assembler", TYPE_ATTRIBUTES (type)) != NULL;
+}
+
+
+static int
+c4x_interrupt_function_p ()
+{
+  if (lookup_attribute ("interrupt",
+                       TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
+    return 1;
+
+  /* Look for TI style c_intnn  */
+  return current_function_name[0] == 'c'
+    && current_function_name[1] == '_'
+    && current_function_name[2] == 'i'
+    && current_function_name[3] == 'n' 
+    && current_function_name[4] == 't'
+    && isdigit (current_function_name[5])
+    && isdigit (current_function_name[6]);
+}
+
+
+/* Write function prologue.  */
+
+void
+c4x_function_prologue (file, size)
+     FILE *file;
+     int size;
+{
+  int regno;
+
+/* In functions where ar3 is not used but frame pointers are still
+   specified, frame pointers are not adjusted (if >= -O2) and this is
+   used so it won't be needlessly push the frame pointer.  */
+  int dont_push_ar3;
+
+  /* For __assembler__ function don't build a prologue.  */
+  if (c4x_assembler_function_p ())
+    {
+      fprintf (file, "; *** Assembler Function ***\n");
+      return;
+    }
+
+  /* For __interrupt__ function build specific prologue.  */
+  if (c4x_interrupt_function_p ())
+    {
+      c4x_leaf_function = c4x_leaf_function_p ();
+      fprintf (file, "; *** Interrupt Entry %s ***\n",
+              c4x_leaf_function ? "(leaf)" : "");
+
+      fprintf (file, "\tpush\tst\n");
+      if (size)
+       {
+         fprintf (file, "\tpush\tar3\n\tldi\tsp,ar3\n");
+         /* FIXME: Assume ISR doesn't require more than 32767 words
+            of local variables.  */
+         if (size > 32767)
+           error ("ISR %s requires %d words of local variables, "
+                  "maximum is 32767.", current_function_name, size);
+         fprintf (file, "\taddi\t%d,sp\n", size);
+       }
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       {
+         if (c4x_isr_reg_used_p (regno))
+           {
+             fprintf (file, "\tpush\t%s\n", reg_names[regno]);
+             if (IS_EXT_REG (regno))   /* save 32MSB of R0--R11 */
+               fprintf (file, "\tpushf\t%s\n", float_reg_names[regno]);
+           }
+       }
+      /* We need to clear the repeat mode flag if the ISR is
+         going to use a RPTB instruction or uses the RC, RS, or RE
+         registers.  */
+      if (regs_ever_live[RC_REGNO] 
+         || regs_ever_live[RS_REGNO] 
+         || regs_ever_live[RE_REGNO])
+       fprintf (file, "\tandn\t0100h,st\n");
+
+      /* Reload DP reg if we are paranoid about some turkey
+         violating small memory model rules.  */
+      if (TARGET_SMALL && TARGET_PARANOID)
+       fprintf (file, TARGET_C3X ?
+                "\tldp\t@data_sec\n" :
+                "\tldpk\t@data_sec\n");
+    }
+  else
+    {
+      if (frame_pointer_needed)
+       {
+         if ((size != 0)
+             || (current_function_args_size != 0)
+             || (optimize < 2))
+           {
+             fprintf (file, "\tpush\tar3\n");
+             fprintf (file, "\tldi\tsp,ar3\n");
+             dont_push_ar3 = 1;
+           }
+         else
+           {
+             /* Since ar3 is not used, we don't need to push it.  */
+             dont_push_ar3 = 1;
+           }
+       }
+      else
+       {
+         /* If we use ar3, we need to push it.   */
+         dont_push_ar3 = 0;
+         if ((size != 0) || (current_function_args_size != 0))
+           {
+             /* If we are omitting the frame pointer, we still have
+                to make space for it so the offsets are correct
+                unless we don't use anything on the stack at all.  */
+             size += 1;
+           }
+       }
+
+      if (size > 32767)
+       {
+         /* Local vars are too big, it will take multiple operations
+            to increment SP.  */
+         if (TARGET_C3X)
+           {
+             fprintf (file, "\tldi\t%d,r1\n", size >> 16);
+             fprintf (file, "\tlsh\t16,r1\n");
+           }
+         else
+           fprintf (file, "\tldhi\t%d,r1\n", size >> 16);
+         fprintf (file, "\tor\t%d,r1\n", size & 0xffff);
+         fprintf (file, "\taddi\tr1,sp\n");
+       }
+      else if (size != 0)
+       {
+         /* Local vars take up less than 32767 words, so we can directly
+            add the number.  */
+         fprintf (file, "\taddi\t%d,sp\n", size);
+       }
+
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       {
+         if (regs_ever_live[regno] && !call_used_regs[regno])
+           {
+             if ((regno == R6_REGNO) || (regno == R7_REGNO))
+               {
+                 /* R6 and R7 are saved as floating point */
+                 if (TARGET_PRESERVE_FLOAT)
+                   fprintf (file, "\tpush\t%s\n", reg_names[regno]);
+                 fprintf (file, "\tpushf\t%s\n", float_reg_names[regno]);
+               }
+             else if ((!dont_push_ar3) || (regno != AR3_REGNO))
+               {
+                 fprintf (file, "\tpush\t%s\n", reg_names[regno]);
+               }
+           }
+       }
+    }
+}
+
+
+/* Write function epilogue.  */
+
+void
+c4x_function_epilogue (file, size)
+     FILE *file;
+     int size;
+{
+  int regno;
+  int restore_count = 0;
+  int delayed_jump = 0;
+  int dont_pop_ar3;
+  rtx insn;
+
+  insn = get_last_insn ();
+  if (insn && GET_CODE (insn) == NOTE)
+    insn = prev_nonnote_insn (insn);
+
+  if (insn && GET_CODE (insn) == BARRIER)
+    return;
+
+  /* For __assembler__ function build no epilogue.  */
+  if (c4x_assembler_function_p ())
+    {
+      fprintf (file, "\trets\n");      /* Play it safe */
+      return;
+    }
+
+#ifdef FUNCTION_BLOCK_PROFILER_EXIT
+  if (profile_block_flag == 2)
+    {
+      FUNCTION_BLOCK_PROFILER_EXIT (file);
+    }
+#endif
+
+  /* For __interrupt__ function build specific epilogue.  */
+  if (c4x_interrupt_function_p ())
+    {
+      for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; --regno)
+       {
+         if (!c4x_isr_reg_used_p (regno))
+           continue;
+         if (IS_EXT_REG (regno))
+           fprintf (file, "\tpopf\t%s\n", float_reg_names[regno]);
+         fprintf (file, "\tpop\t%s\n", reg_names[regno]);
+       }
+      if (size)
+       {
+         fprintf (file, "\tsubi\t%d,sp\n", size);
+         fprintf (file, "\tpop\tar3\n");
+       }
+      fprintf (file, "\tpop\tst\n");
+      fprintf (file, "\treti\n");
+    }
+  else
+    {
+      if (frame_pointer_needed)
+       {
+         if ((size != 0) 
+             || (current_function_args_size != 0) 
+             || (optimize < 2))
+           {
+             /* R2 holds the return value.  */
+             fprintf (file, "\tldi\t*-ar3(1),r2\n");
+
+             /* We already have the return value and the fp,
+                so we need to add those to the stack.  */
+             size += 2;
+             delayed_jump = 1;
+             restore_count = 1;
+             dont_pop_ar3 = 1;
+           }
+         else
+           {
+             /* Since ar3 is not used for anything, we don't need to
+                pop it.  */
+             dont_pop_ar3 = 1;
+           }
+       }
+      else
+       {
+         dont_pop_ar3 = 0;     /* If we use ar3, we need to pop it */
+         if (size || current_function_args_size)
+           {
+             /* If we are ommitting the frame pointer, we still have
+                to make space for it so the offsets are correct
+                unless we don't use anything on the stack at all.  */
+             size += 1;
+           }
+       }
+
+      /* Now get the number of instructions required to restore the
+         registers.  */
+      for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
+       {
+         if ((regs_ever_live[regno] && !call_used_regs[regno])
+             && ((!dont_pop_ar3) || (regno != AR3_REGNO)))
+           {
+             restore_count++;
+             if (TARGET_PRESERVE_FLOAT
+                 && ((regno == R6_REGNO) || (regno == R7_REGNO)))
+               restore_count++;
+           }
+       }
+
+      /* Get the number of instructions required to restore the stack.  */
+      if (size > 32767)
+       restore_count += (TARGET_C3X ? 4 : 3);
+      else if (size != 0)
+       restore_count += 1;
+
+      if (delayed_jump && (restore_count < 3))
+       {
+         /* We don't have enough instructions to account for the delayed
+            branch, so put some nops in.  */
+
+         fprintf (file, "\tbud\tr2\n");
+         while (restore_count < 3)
+           {
+             fprintf (file, "\tnop\n");
+             restore_count++;
+           }
+         restore_count = 0;
+       }
+
+      /* Now restore the saved registers, putting in the delayed branch
+         where required.  */
+      for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
+       {
+         if (regs_ever_live[regno] && !call_used_regs[regno])
+           {
+             if (regno == AR3_REGNO && dont_pop_ar3)
+               continue;
+
+             if (delayed_jump && (restore_count == 3))
+               fprintf (file, "\tbud\tr2\n");
+
+             /* R6 and R7 are saved as floating point.  */
+             if ((regno == R6_REGNO) || (regno == R7_REGNO))
+               {
+                 fprintf (file, "\tpopf\t%s\n", float_reg_names[regno]);
+                 if (TARGET_PRESERVE_FLOAT)
+                   {
+                     restore_count--;
+                     if (delayed_jump && (restore_count == 3))
+                       fprintf (file, "\tbud\tr2\n");
+                     fprintf (file, "\tpop\t%s\n", reg_names[regno]);
+                   }
+               }
+             else
+               fprintf (file, "\tpop\t%s\n", reg_names[regno]);
+             restore_count--;
+           }
+       }
+
+      if (delayed_jump && (restore_count == 3))
+       fprintf (file, "\tbud\tr2\n");
+
+      if (frame_pointer_needed)
+       {
+         if ((size != 0)
+             || (current_function_args_size != 0)
+             || (optimize < 2))
+           {
+             /* Restore the old FP.  */
+             fprintf (file, "\tldi\t*ar3,ar3\n");
+             restore_count--;
+
+             if (delayed_jump && (restore_count == 3))
+               fprintf (file, "\tbud\tr2\n");
+           }
+       }
+
+      if (size > 32767)
+       {
+         /* Local vars are too big, it will take multiple operations
+            to decrement SP.  */
+         if (TARGET_C3X)
+           {
+             fprintf (file, "\tldi\t%d,r3\n", size >> 16);
+             if (delayed_jump)
+               fprintf (file, "\tbud\tr2\n");
+             fprintf (file, "\tlsh\t16,r3\n");
+           }
+         else
+           fprintf (file, "\tldhi\t%d,r3\n", size >> 16);
+         fprintf (file, "\tor\t%d,r3\n", size & 0xffff);
+         fprintf (file, "\tsubi\tr3,sp\n");
+       }
+      else if (size != 0)
+       {
+         /* Local vars take up less than 32768 words, so we can directly
+            subtract the number.  */
+         fprintf (file, "\tsubi\t%d,sp\n", size);
+       }
+
+      if (!delayed_jump)
+       fprintf (file, "\trets\n");
+    }
+}
+
+int
+c4x_null_epilogue_p ()
+{
+  int regno;
+
+  if (reload_completed
+      && !c4x_assembler_function_p ()
+      && !c4x_interrupt_function_p ()
+      && !current_function_calls_alloca
+      && !current_function_args_size
+      && !(profile_block_flag == 2)
+      && !(optimize < 2)
+      && !get_frame_size ())
+    {
+      for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
+       if (regs_ever_live[regno] && !call_used_regs[regno]
+           && (regno != AR3_REGNO))
+         return 0;
+      return 1;
+    }
+  return 0;
+}
+
+
+void
+c4x_emit_libcall (name, code, dmode, smode, noperands, operands)
+     const char *name;
+     enum rtx_code code;
+     enum machine_mode dmode;
+     enum machine_mode smode;
+     int noperands;
+     rtx *operands;
+{
+  rtx ret;
+  rtx insns;
+  rtx libcall;
+  rtx equiv;
+
+  start_sequence ();
+  libcall = gen_rtx (SYMBOL_REF, Pmode, name);
+  switch (noperands)
+    {
+    case 2:
+      ret = emit_library_call_value (libcall, NULL_RTX, 1, dmode, 1,
+                                    operands[1], smode);
+      equiv = gen_rtx (code, dmode, operands[1]);
+      break;
+
+    case 3:
+      ret = emit_library_call_value (libcall, NULL_RTX, 1, dmode, 2,
+                                    operands[1], smode, operands[2], smode);
+      equiv = gen_rtx (code, dmode, operands[1], operands[2]);
+      break;
+
+    default:
+      fatal ("c4x_emit_libcall: Bad number of operands");
+    }
+
+  insns = get_insns ();
+  end_sequence ();
+  emit_libcall_block (insns, operands[0], ret, equiv);
+}
+
+
+void
+c4x_emit_libcall3 (name, code, mode, operands)
+     const char *name;
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx *operands;
+{
+  return c4x_emit_libcall (name, code, mode, mode, 3, operands);
+}
+
+void
+c4x_emit_libcall_mulhi (name, code, mode, operands)
+     const char *name;
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx *operands;
+{
+  rtx ret;
+  rtx insns;
+  rtx libcall;
+  rtx equiv;
+
+  start_sequence ();
+  libcall = gen_rtx (SYMBOL_REF, Pmode, name);
+  ret = emit_library_call_value (libcall, NULL_RTX, 1, mode, 2,
+                                 operands[1], mode, operands[2], mode);
+  equiv = gen_rtx (TRUNCATE, mode,
+                   gen_rtx (LSHIFTRT, HImode,
+                            gen_rtx (MULT, HImode,
+                                     gen_rtx (code, HImode, operands[1]),
+                                     gen_rtx (code, HImode, operands[2])),
+                            gen_rtx (CONST_INT, VOIDmode, 32)));
+  insns = get_insns ();
+  end_sequence ();
+  emit_libcall_block (insns, operands[0], ret, equiv);
+}
+
+
+enum reg_class
+c4x_preferred_reload_class (x, class)
+     rtx x;
+     enum reg_class class;
+{
+  if (GET_CODE (x) == MEM && class > ADDR_REGS && class != INDEX_REGS)
+    {
+      x = XEXP (x, 0);
+      if (GET_CODE (x) == PLUS)
+        {
+          rtx op0 = XEXP (x, 0);
+          rtx op1 = XEXP (x, 1);
+
+          if (REG_P (op0) 
+             && IS_ADDR_REGNO (op0)
+             && GET_CODE (op1) == CONST_INT
+             && !IS_DISP8_CONST (INTVAL (op1)))
+           class = ADDR_REGS;
+        }
+    }
+  return class;
+}
+
+
+enum reg_class
+c4x_limit_reload_class (mode, class)
+     enum machine_mode mode;
+     enum reg_class class;
+{
+  return class;
+}
+
+
+enum reg_class
+c4x_secondary_memory_needed (class1, class2, mode)
+     enum reg_class class1;
+     enum reg_class class2;
+     enum machine_mode mode;
+{
+  return 0;
+}
+
+
+int
+c4x_check_legit_addr (mode, addr, strict)
+     enum machine_mode mode;
+     rtx addr;
+     int strict;
+{
+  rtx base = NULL_RTX;         /* Base register (AR0-AR7) */
+  rtx indx = NULL_RTX;         /* Index register (IR0,IR1) */
+  rtx disp = NULL_RTX;         /* Displacement */
+  enum rtx_code code;
+
+  code = GET_CODE (addr);
+  switch (code)
+    {
+      /* Register indirect with auto increment/decrement.  We don't
+        allow SP here---push_operand should recognise an operand
+        being pushed on the stack.  */
+
+    case PRE_DEC:
+    case POST_DEC:
+      if (mode != QImode && mode != QFmode)
+       return 0;
+    case PRE_INC:
+    case POST_INC:
+      base = XEXP (addr, 0);
+      if (!REG_P (base))
+       return 0;
+      break;
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+       rtx op0 = XEXP (addr, 0);
+       rtx op1 = XEXP (addr, 1);
+
+       if (mode != QImode && mode != QFmode)
+         return 0;
+
+       if (!REG_P (op0) 
+           || (GET_CODE (op1) != PLUS && GET_CODE (op1) != MINUS))
+         return 0;
+       base = XEXP (op1, 0);
+       if (base != op0)
+         return 0;
+       if (REG_P (XEXP (op1, 1)))
+         indx = XEXP (op1, 1);
+       else
+         disp = XEXP (op1, 1);
+      }
+      break;
+       
+      /* Register indirect.  */
+    case REG:
+      base = addr;
+      break;
+
+      /* Register indirect with displacement or index.  */
+    case PLUS:
+      {
+       rtx op0 = XEXP (addr, 0);
+       rtx op1 = XEXP (addr, 1);
+       enum rtx_code code0 = GET_CODE (op0);
+
+       switch (code0)
+         {
+         case USE:
+           /* The uses are put in to avoid problems
+              with referenced things disappearing.  */
+           return c4x_check_legit_addr (mode, op1, strict);
+
+         case PLUS:
+           /* This is another reference to keep things
+              from disappearing, but it contains a plus
+              of a use and DP.  */
+           if (GET_CODE (XEXP (op0, 0)) == USE)
+             return c4x_check_legit_addr (mode, op1, strict);
+           return 0;
+
+         case REG:
+           if (REG_P (op1))
+             {
+               base = op0;     /* base + index */
+               indx = op1;
+               if (IS_INDEX_REGNO (base) || IS_ADDR_REGNO (indx))
+                 {
+                   base = op1;
+                   indx = op0;
+                 }
+             }
+           else
+             {
+               base = op0;     /* base + displacement */
+               disp = op1;
+             }
+           break;
+
+         default:
+           return 0;
+         }
+      }
+      break;
+
+      /* Direct addressing with some work for the assembler...  */
+    case CONST:
+      if (GET_CODE (XEXP (addr, 0)) == PLUS
+         && (GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF
+             || GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF)
+         && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
+       return 1;
+
+      /* Direct addressing.  */
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 1;
+
+      /* Do not allow direct memory access to absolute addresses.
+         This is more pain than its worth, especially for the
+         small memory model where we can't guarantee that
+         this address is within the data page---we don't want
+         to modify the DP register in the small memory model,
+         even temporarily, since an interrupt can sneak in....  */
+    case CONST_INT:
+      return 0;
+
+      /* Indirect indirect addressing.  */
+    case MEM:
+      return 0;
+
+    case CONST_DOUBLE:
+      fatal_insn ("Using CONST_DOUBLE for address", addr);
+
+    default:
+      return 0;
+    }
+
+  /* Validate the base register.  */
+  if (base)
+    {
+      /* Check that the address is offsettable for HImode and HFmode.  */
+      if (indx && (mode == HImode || mode == HFmode))
+       return 0;
+
+      /* Handle DP based stuff.  */
+      if (REGNO (base) == DP_REGNO)
+       return 1;
+      if (strict && !REGNO_OK_FOR_BASE_P (REGNO (base)))
+       return 0;
+      else if (!strict && !IS_ADDR_OR_PSEUDO_REGNO (base))
+       return 0;
+    }
+
+  /* Now validate the index register.  */
+  if (indx)
+    {
+      if (GET_CODE (indx) != REG)
+       return 0;
+      if (strict && !REGNO_OK_FOR_INDEX_P (REGNO (indx)))
+       return 0;
+      else if (!strict && !IS_INDEX_OR_PSEUDO_REGNO (indx))
+       return 0;
+    }
+
+  /* Validate displacement.  */
+  if (disp)
+    {
+      if (GET_CODE (disp) != CONST_INT)
+       return 0;
+      if (mode == HImode || mode == HFmode)
+       {
+         /* The offset displacement must be legitimate.  */
+         if (!IS_DISP8_OFF_CONST (INTVAL (disp)))
+           return 0;
+       }
+      else
+       {
+         if (!IS_DISP8_CONST (INTVAL (disp)))
+           return 0;
+       }
+      /* Can't add an index with a disp.  */
+      if (indx)
+       return 0;               
+    }
+  return 1;
+}
+
+
+rtx
+c4x_legitimize_address (orig, mode)
+     rtx orig;
+     enum machine_mode mode;
+{
+  return NULL_RTX;
+}
+
+
+/* Provide the costs of an addressing mode that contains ADDR.
+   If ADDR is not a valid address, its cost is irrelevant.  
+   This is used in cse and loop optimisation to determine
+   if it is worthwhile storing a common address into a register. 
+   Unfortunately, the C4x address cost depends on other operands.  */
+
+int 
+c4x_address_cost (addr)
+rtx addr;
+{
+  switch (GET_CODE (addr))
+    {
+    case REG:
+      return 1;
+
+    case CONST:
+      {
+       rtx offset = const0_rtx;
+       addr = eliminate_constant_term (addr, &offset);
+       
+       if (GET_CODE (addr) == LABEL_REF)
+         return 3;
+       
+       if (GET_CODE (addr) != SYMBOL_REF)
+         return 4;
+
+       if (INTVAL (offset) == 0)
+         return 3;
+      }
+      
+      /* fall through */
+      
+    case POST_INC:
+    case POST_DEC:
+    case PRE_INC:
+    case PRE_DEC:
+      return 1;
+      
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return TARGET_SMALL ? 3 : 4;
+      
+    case PLUS:
+      {
+       register rtx op0 = XEXP (addr, 0);
+       register rtx op1 = XEXP (addr, 1);
+       
+       if (GET_CODE (op0) != REG)
+         break;
+       
+       switch (GET_CODE (op1))
+         {
+         default:
+           break;
+
+         case REG:
+           return 2;
+
+         case CONST_INT:
+           if (IS_DISP1_CONST (INTVAL (op1)))
+             return 1;
+
+           if (!TARGET_C3X && IS_UINT5_CONST (INTVAL (op1)))
+             return 2;
+
+           return 3;
+         }
+      }
+    default:
+    }
+  
+  return 4;
+}
+
+
+rtx
+c4x_gen_compare_reg (code, x, y)
+     enum rtx_code code;
+     rtx x, y;
+{
+  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
+  rtx cc_reg;
+
+  if (mode == CC_NOOVmode
+      && (code == LE || code == GE || code == LT || code == GT))
+    return NULL_RTX;
+
+  cc_reg = gen_rtx (REG, mode, ST_REGNO);
+  emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
+                     gen_rtx (COMPARE, mode, x, y)));
+  return cc_reg;
+}
+
+char *
+c4x_output_cbranch (reversed, insn)
+     int reversed;
+     rtx insn;
+{
+  int delayed = 0;
+  int annultrue = 0;
+  int annulfalse = 0;
+  rtx delay;
+  char *cp;
+  static char str[20];
+  
+  if (final_sequence)
+    {
+      delay = XVECEXP (final_sequence, 0, 1);
+      delayed = !INSN_ANNULLED_BRANCH_P (insn);
+      annultrue = INSN_ANNULLED_BRANCH_P (insn) && !INSN_FROM_TARGET_P (delay);
+      annulfalse = INSN_ANNULLED_BRANCH_P (insn) && INSN_FROM_TARGET_P (delay);
+    }
+  cp = str;
+  *cp++ = 'b';
+  *cp++ = '%';
+  if (reversed)
+    *cp++ = 'I';
+  *cp++ = '0';
+  if (delayed)
+    {
+      *cp++ = '%';
+      *cp++ = '#';
+    }
+  if (annultrue)
+    {
+      *cp++ = 'a';
+      *cp++ = 't';
+    }
+  if (annulfalse)
+    {
+      *cp++ = 'a'; 
+      *cp++ = 'f';
+    }
+  *cp++ = '\t';
+  *cp++ = '%'; 
+  *cp++ = 'l';
+  *cp++ = '1';
+  *cp = 0;
+  return str;
+}
+
+
+void
+c4x_print_operand (file, op, letter)
+     FILE *file;               /* file to write to */
+     rtx op;                   /* operand to print */
+     int letter;               /* %<letter> or 0 */
+{
+  rtx op1;
+  enum rtx_code code;
+
+  switch (letter)
+    {
+    case '#':                  /* delayed */
+      if (final_sequence)
+       asm_fprintf (file, "d");
+      return;
+    }
+
+  code = GET_CODE (op);
+  switch (letter)
+    {
+    case 'A':                  /* direct address */
+      if (code == CONST_INT || code == SYMBOL_REF)
+       asm_fprintf (file, "@");
+      break;
+
+    case 'C':                  /* call */
+      if (code != MEM)
+       fatal_insn ("c4x_print_operand: %%C inconsistency", op);
+      op1 = XEXP (op, 0);
+      SYMBOL_REF_FLAG (op1) = 1;
+      output_addr_const (file, op1);
+      return;
+
+    case 'H':                  /* sethi */
+      if (code == SYMBOL_REF)
+       SYMBOL_REF_FLAG (op) = 1;
+      break;
+
+    case 'I':                  /* reversed condition */
+      code = reverse_condition (code);
+      break;
+
+    case 'L':                  /* log 2 of constant */
+      if (code != CONST_INT)
+       fatal_insn ("c4x_print_operand: %%L inconsistency", op);
+      fprintf (file, "%d", exact_log2 (INTVAL (op)));
+      return;
+
+    case 'N':                  /* ones complement of small constant */
+      if (code != CONST_INT)
+       fatal_insn ("c4x_print_operand: %%N inconsistency", op);
+      fprintf (file, "%d", ~INTVAL (op));
+      return;
+
+    case 'K':                  /* generate ldp(k) if direct address */
+      if (!TARGET_SMALL
+         && code == MEM
+         && GET_CODE (XEXP (op, 0)) == PLUS
+         && GET_CODE(XEXP (XEXP (op, 0), 0)) == REG
+         && REGNO(XEXP (XEXP (op, 0), 0)) == DP_REGNO)
+       {
+         op1 = XEXP (XEXP (op, 0), 1);
+          if (GET_CODE(op1) == CONST_INT || GET_CODE(op1) == SYMBOL_REF)
+           {
+             asm_fprintf (file, "\t%s\t", TARGET_C3X ? "ldp" : "ldpk");
+             output_address (XEXP (adj_offsettable_operand (op, 1), 0));
+             asm_fprintf (file, "\n");
+           }
+       }
+      return;
+
+    case 'M':                  /* generate ldp(k) if direct address */
+      if (!TARGET_SMALL                /* only used in asm statements */
+         && code == MEM
+         && (GET_CODE (XEXP (op, 0)) == CONST
+             || GET_CODE (XEXP (op, 0)) == SYMBOL_REF))
+       {
+         asm_fprintf (file, "%s\t", TARGET_C3X ? "ldp" : "ldpk");
+          output_address (XEXP (op, 0));
+         asm_fprintf (file, "\n\t");
+       }
+      return;
+
+    case 'O':                  /* offset address */
+      if (code == MEM && c4x_autoinc_operand (op, Pmode))
+       break;
+      else if (code == MEM)
+       output_address (XEXP (adj_offsettable_operand (op, 1), 0));
+      else if (code == REG)
+       fprintf (file, "%s", reg_names[REGNO (op) + 1]);
+      else
+       fatal_insn ("c4x_print_operand: %%O inconsistency", op);
+      return;
+
+    case 'R':                  /* call register */
+      op1 = XEXP (op, 0);
+      if (code != MEM || GET_CODE (op1) != REG)
+       fatal_insn ("c4x_print_operand: %%R inconsistency", op);
+      else
+       fprintf (file, "%s", reg_names[REGNO (op1)]);
+      return;
+
+    default:
+      break;
+    }
+  
+  switch (code)
+    {
+    case REG:
+      if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
+       fprintf (file, "%s", float_reg_names[REGNO (op)]);
+      else
+       fprintf (file, "%s", reg_names[REGNO (op)]);
+      break;
+      
+    case MEM:
+      output_address (XEXP (op, 0));
+      break;
+      
+    case CONST_DOUBLE:
+      {
+       char str[30];
+       REAL_VALUE_TYPE r;
+       
+       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+       REAL_VALUE_TO_DECIMAL (r, "%20f", str);
+       fprintf (file, "%s", str);
+      }
+      break;
+      
+    case CONST_INT:
+      fprintf (file, "%d", INTVAL (op));
+      break;
+      
+    case NE:
+      asm_fprintf (file, "ne");
+      break;
+      
+    case EQ:
+      asm_fprintf (file, "eq");
+      break;
+      
+    case GE:
+      asm_fprintf (file, "ge");
+      break;
+
+    case GT:
+      asm_fprintf (file, "gt");
+      break;
+
+    case LE:
+      asm_fprintf (file, "le");
+      break;
+
+    case LT:
+      asm_fprintf (file, "lt");
+      break;
+
+    case GEU:
+      asm_fprintf (file, "hs");
+      break;
+
+    case GTU:
+      asm_fprintf (file, "hi");
+      break;
+
+    case LEU:
+      asm_fprintf (file, "ls");
+      break;
+
+    case LTU:
+      asm_fprintf (file, "lo");
+      break;
+
+    case SYMBOL_REF:
+      output_addr_const (file, op);
+      break;
+
+    case CONST:
+      output_addr_const (file, XEXP (op, 0));
+      break;
+
+    case CODE_LABEL:
+      break;
+
+    default:
+      fatal_insn ("c4x_print_operand: Bad operand case", op);
+      break;
+    }
+}
+
+
+void
+c4x_print_operand_address (file, addr)
+     FILE *file;
+     rtx addr;
+{
+  switch (GET_CODE (addr))
+    {
+    case REG:
+      fprintf (file, "*%s", reg_names[REGNO (addr)]);
+      break;
+
+    case PRE_DEC:
+      fprintf (file, "*--%s", reg_names[REGNO (XEXP (addr, 0))]);
+      break;
+
+    case POST_INC:
+      fprintf (file, "*%s++", reg_names[REGNO (XEXP (addr, 0))]);
+      break;
+
+    case POST_MODIFY:
+      {
+       rtx op0 = XEXP (XEXP (addr, 1), 0);
+       rtx op1 = XEXP (XEXP (addr, 1), 1);
+       
+       if (GET_CODE (XEXP (addr, 1)) == PLUS && REG_P (op1))
+         fprintf (file, "*%s++(%s)", reg_names[REGNO (op0)],
+                  reg_names[REGNO (op1)]);
+       else if (GET_CODE (XEXP (addr, 1)) == PLUS && INTVAL (op1) > 0)
+         fprintf (file, "*%s++(%d)", reg_names[REGNO (op0)],
+                  INTVAL (op1));
+       else if (GET_CODE (XEXP (addr, 1)) == PLUS && INTVAL (op1) < 0)
+         fprintf (file, "*%s--(%d)", reg_names[REGNO (op0)],
+                  -INTVAL (op1));
+       else if (GET_CODE (XEXP (addr, 1)) == MINUS && REG_P (op1))
+         fprintf (file, "*%s--(%s)", reg_names[REGNO (op0)],
+                  reg_names[REGNO (op1)]);
+       else
+         fatal_insn ("c4x_print_operand_address: Bad post_modify", addr);
+      }
+      break;
+      
+    case PRE_MODIFY:
+      {
+       rtx op0 = XEXP (XEXP (addr, 1), 0);
+       rtx op1 = XEXP (XEXP (addr, 1), 1);
+       
+       if (GET_CODE (XEXP (addr, 1)) == PLUS && REG_P (op1))
+         fprintf (file, "*++%s(%s)", reg_names[REGNO (op0)],
+                  reg_names[REGNO (op1)]);
+       else if (GET_CODE (XEXP (addr, 1)) == PLUS && INTVAL (op1) > 0)
+         fprintf (file, "*++%s(%d)", reg_names[REGNO (op0)],
+                  INTVAL (op1));
+       else if (GET_CODE (XEXP (addr, 1)) == PLUS && INTVAL (op1) < 0)
+         fprintf (file, "*--%s(%d)", reg_names[REGNO (op0)],
+                  -INTVAL (op1));
+       else if (GET_CODE (XEXP (addr, 1)) == MINUS && REG_P (op1))
+         fprintf (file, "*--%s(%s)", reg_names[REGNO (op0)],
+                  reg_names[REGNO (op1)]);
+       else
+         fatal_insn ("c4x_print_operand_address: Bad pre_modify", addr);
+      }
+      break;
+      
+    case PRE_INC:
+      fprintf (file, "*++%s", reg_names[REGNO (XEXP (addr, 0))]);
+      break;
+
+    case POST_DEC:
+      fprintf (file, "*%s--", reg_names[REGNO (XEXP (addr, 0))]);
+      break;
+
+    case PLUS:                 /* Indirect with displacement.  */
+      {
+       rtx op0 = XEXP (addr, 0);
+       rtx op1 = XEXP (addr, 1);
+       enum rtx_code code0 = GET_CODE (op0);
+
+       if (code0 == USE || code0 == PLUS)
+         {
+           asm_fprintf (file, "@");
+           output_addr_const (file, op1);
+         }
+       else if (REG_P (op0))
+         {
+           if (REGNO (op0) == DP_REGNO)
+             {
+               c4x_print_operand_address (file, op1);
+             }
+           else if (REG_P (op1))
+             {
+               if (IS_INDEX_REGNO (op0))
+                 {
+                   fprintf (file, "*+%s(%s)",
+                            reg_names[REGNO (op1)],
+                            reg_names[REGNO (op0)]);   /* index + base */
+                 }
+               else
+                 {
+                   fprintf (file, "*+%s(%s)",
+                            reg_names[REGNO (op0)],
+                            reg_names[REGNO (op1)]);   /* base + index */
+                 }
+             }
+           else if (INTVAL (op1) < 0)
+             {
+               fprintf (file, "*-%s(%d)",
+                        reg_names[REGNO (op0)],
+                        -INTVAL (op1));        /* base - displacement */
+             }
+           else
+             {
+               fprintf (file, "*+%s(%d)",
+                        reg_names[REGNO (op0)],
+                        INTVAL (op1));         /* base + displacement */
+             }
+         }
+      }
+      break;
+
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      if (!SYMBOL_REF_FLAG (addr))
+       fprintf (file, "@");
+      output_addr_const (file, addr);
+      SYMBOL_REF_FLAG (addr) = 0;
+      break;
+
+      /* We shouldn't access CONST_INT addresses.  */
+    case CONST_INT:
+
+    default:
+      fatal_insn ("c4x_print_operand_address: Bad operand case", addr);
+      break;
+    }
+}
+
+
+static int
+c4x_immed_float_p (operand)
+     rtx operand;
+{
+  long convval[2];
+  int exponent;
+  REAL_VALUE_TYPE r;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
+  if (GET_MODE (operand) == HFmode)
+    REAL_VALUE_TO_TARGET_DOUBLE (r, convval);
+  else
+    {
+      REAL_VALUE_TO_TARGET_SINGLE (r, convval[0]);
+      convval[1] = 0;
+    }
+
+  /* sign extend exponent */
+  exponent = (((convval[0] >> 24) & 0xff) ^ 0x80) - 0x80;
+  if (exponent == -128)
+    return 1;                  /* 0.0 */
+  if ((convval[0] & 0x00000fff) != 0 || convval[1] != 0)
+    return 0;                  /* Precision doesn't fit */
+  return (exponent <= 7)       /* Positive exp */
+    && (exponent >= -7);       /* Negative exp */
+}
+
+
+/* This function checks for an insn operand that requires direct
+   addressing and inserts a load of the DP register prior to the
+   insn if the big memory model is being compiled for.  Immediate
+   operands that do not fit within the opcode field get changed
+   into memory references using direct addressing.  At this point
+   all pseudos have been converted to hard registers.  */
+
+int
+c4x_scan_for_ldp (newop, insn, operand0)
+     rtx *newop;
+     rtx insn;
+     rtx operand0;
+{
+  int i;
+  char *format_ptr;
+  rtx op0, op1, op2, addr;
+  rtx operand = *newop;
+
+  switch (GET_CODE (operand))
+    {
+    case MEM:
+      op0 = XEXP (operand, 0);
+
+      /* We have something we need to emit a load dp insn for.
+         The first operand should hold the rtx for the instruction
+         required.  */
+
+      switch (GET_CODE (op0))
+       {
+       case CONST_INT:
+         fatal_insn ("c4x_scan_for_ldp: Direct memory access to const_int",
+                    op0);
+         break;
+
+       case CONST:
+       case SYMBOL_REF:
+         if (!TARGET_C3X && !TARGET_SMALL
+             && recog_memoized (insn) == CODE_FOR_movqi_noclobber
+             && ((addr = find_reg_note (insn, REG_EQUAL, NULL_RTX))
+                 || (addr = find_reg_note (insn, REG_EQUIV, NULL_RTX)))
+             && (IS_STD_OR_PSEUDO_REGNO (operand0)))
+           {
+             addr = XEXP (addr, 0);
+             if (GET_CODE (addr) == CONST_INT)
+               {
+                 op1 = gen_rtx (CONST_INT, VOIDmode, INTVAL (addr) & ~0xffff);
+                 emit_insn_before (gen_movqi (operand0, op1), insn);
+                 op1 = gen_rtx (CONST_INT, VOIDmode, INTVAL (addr) & 0xffff);
+                 emit_insn_before (gen_iorqi3_noclobber (operand0,
+                                                     operand0, op1), insn);
+                 delete_insn (insn);
+                 return 1;
+               }
+             else if (GET_CODE (addr) == SYMBOL_REF)
+               {
+                 emit_insn_before (gen_set_high_use (operand0, addr, addr),
+                                   insn);
+                 emit_insn_before (gen_set_ior_lo_use (operand0, addr, addr),
+                                   insn);
+                 delete_insn (insn);
+                 return 1;
+               }
+             else if (GET_CODE (addr) == CONST
+                      && GET_CODE (op1 = XEXP (addr, 0)) == PLUS
+                      && GET_CODE (op2 = XEXP (op1, 0)) == SYMBOL_REF
+                      && GET_CODE (XEXP (op1, 1)) == CONST_INT)
+               {
+                 emit_insn_before (gen_set_high_use (operand0, addr, op2),
+                                   insn);
+                 emit_insn_before (gen_set_ior_lo_use (operand0, addr, op2),
+                                   insn);
+                 delete_insn (insn);
+                 return 1;
+               }
+           }
+         if (!TARGET_SMALL)
+           emit_insn_before (gen_set_ldp (gen_rtx (REG, Pmode, DP_REGNO),
+                                          operand), insn);
+
+         /* Replace old memory reference with direct reference.  */
+         *newop = gen_rtx (MEM, GET_MODE (operand),
+                           gen_rtx (PLUS, Pmode,
+                                    gen_rtx (REG, Pmode, DP_REGNO), op0));
+
+         /* Use change_address?  */
+         MEM_VOLATILE_P (*newop) = MEM_VOLATILE_P (operand);
+         RTX_UNCHANGING_P (*newop) = RTX_UNCHANGING_P (operand);
+         MEM_IN_STRUCT_P (*newop) = MEM_IN_STRUCT_P (operand);
+         break;
+
+       default:
+         break;
+       }
+
+      return 0;
+
+    case CONST_INT:
+      if (SMALL_CONST (INTVAL (operand), insn))
+       break;
+      fatal_insn ("Immediate integer too large", insn);
+
+    case CONST_DOUBLE:
+      if (c4x_immed_float_p (operand))
+       break;
+
+      /* We'll come here if a CONST_DOUBLE integer has slipped
+         though the net...  */
+      fatal_insn ("Immediate CONST_DOUBLE integer too large", insn);
+
+    case CONST:
+      fatal_insn ("Immediate integer not known", insn);
+
+      /* Symbol and label immediate addresses cannot be stored
+         within a C[34]x instruction, so we store them in memory
+         and use direct addressing instead.  */
+    case LABEL_REF:
+    case SYMBOL_REF:
+      if (GET_CODE (operand0) != REG)
+       break;
+
+      op0 = XEXP (force_const_mem (Pmode, operand), 0);
+      *newop = gen_rtx (MEM, GET_MODE (operand),
+                       gen_rtx (PLUS, Pmode,
+                                gen_rtx (PLUS, Pmode,
+                                         gen_rtx (USE, VOIDmode, operand),
+                                         gen_rtx (REG, Pmode, DP_REGNO)),
+                                op0));
+
+      if (!TARGET_SMALL)
+       emit_insn_before (gen_set_ldp_use (gen_rtx (REG, Pmode, DP_REGNO),
+                                          *newop, operand), insn);
+      return 0;
+
+    default:
+      break;
+    }
+
+  format_ptr = GET_RTX_FORMAT (GET_CODE (operand));
+
+  /* Recursively hunt for required loads of DP.  */
+  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
+    {
+      if (*format_ptr++ == 'e')        /* rtx expression */
+       if (c4x_scan_for_ldp (&XEXP (operand, i), insn, operand0))
+         break;
+    }
+  return 0;
+}
+
+
+/* The last instruction in a repeat block cannot be a Bcond, DBcound,
+   CALL, CALLCond, TRAPcond, RETIcond, RETScond, IDLE, RPTB or RPTS.
+
+   None of the last four instructions from the bottom of the block can
+   be a BcondD, BRD, DBcondD, RPTBD, LAJ, LAJcond, LATcond, BcondAF,
+   BcondAT or RETIcondD.
+
+   This routine scans the four previous insns for a jump insn, and if
+   one is found, returns 1 so that we bung in a nop instruction.
+   This simple minded strategy will add a nop, when it may not
+   be required.  Say when there is a JUMP_INSN near the end of the
+   block that doesn't get converted into a delayed branch.
+
+   Note that we cannot have a call insn, since we don't generate
+   repeat loops with calls in them (although I suppose we could, but
+   there's no benefit.)  */
+
+int
+c4x_rptb_nop_p (insn)
+     rtx insn;
+{
+  int i;
+
+  /* If there is a label at the end of the loop we must insert
+     a NOP.  */
+  insn = prev_nonnote_insn (insn);
+  if (GET_CODE (insn) == CODE_LABEL)
+    return 1;
+
+  for (i = 0; i < 4; i++)
+    {
+      /* Search back for prev non-note and non-label insn.  */
+      while (GET_CODE (insn) == NOTE || GET_CODE (insn) == CODE_LABEL
+            || GET_CODE (insn) == USE || GET_CODE (insn) == CLOBBER)
+       insn = PREV_INSN (insn);
+
+      /* I we have a jump instruction we should insert a NOP. If we
+        hit repeat block top we should only insert a NOP if the loop
+        is empty. */
+      if (GET_CODE (insn) == JUMP_INSN)
+       return 1;
+      else if (recog_memoized (insn) == CODE_FOR_rptb_top)
+       return i == 0;
+      insn = PREV_INSN (insn);
+    }
+  return 0;
+}
+
+
+/* This function is a C4x special. It scans through all the insn
+   operands looking for places where the DP register needs to be
+   reloaded and for large immediate operands that need to be converted
+   to memory references.  The latter should be avoidable with proper
+   definition of patterns in machine description.  We come here right
+   near the end of things, immediately before delayed branch
+   scheduling.  */
+
+void
+c4x_process_after_reload (first)
+     rtx first;
+{
+  rtx operand0;
+  rtx insn;
+  int i;
+
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    {
+      /* Look for insn.  */
+      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+       {
+         int noperands;
+         int insn_code_number;
+
+         insn_code_number = recog_memoized (insn);
+
+         if (insn_code_number < 0)
+           continue;
+
+         /* We split all insns here if they have a # for the output
+            template if we are using the big memory model since there
+            is a chance that we might be accessing memory across a
+            page boundary.  */
+
+         if (!TARGET_SMALL)
+           {
+             char *template;
+
+             template = insn_template[insn_code_number];
+             if (template && template[0] == '#' && template[1] == '\0')
+               {
+                 rtx new = try_split (PATTERN(insn), insn, 0);
+                 
+                 /* If we didn't split the insn, go away.  */
+                 if (new == insn && PATTERN (new) == PATTERN(insn))
+                   fatal_insn ("Couldn't split pattern", insn);
+
+                 PUT_CODE (insn, NOTE);
+                 NOTE_SOURCE_FILE (insn) = 0;
+                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+
+                 /* Do we have to update the basic block info here? 
+                    Maybe reorg wants it sorted out... */
+
+                 /* Continue with the first of the new insns gnerated
+                     by the split. */
+                 insn = new;
+
+                 insn_code_number = recog_memoized (insn);
+                 
+                 if (insn_code_number < 0)
+                   continue;
+               }
+           }
+
+         /* Ignore jumps and calls.  */
+         if (GET_CODE (insn) == CALL_INSN
+             || GET_CODE (insn) == JUMP_INSN)
+           {
+             continue;         /* Hopefully we are not hosed here.  */
+           }
+
+         noperands = insn_n_operands[insn_code_number];
+
+         insn_extract (insn);
+
+         operand0 = recog_operand[0];
+
+         for (i = 0; i < noperands; i++)
+           if (c4x_scan_for_ldp (recog_operand_loc[i], insn, operand0))
+             break;
+       }
+    }
+}
+
+
+static int
+c4x_a_register (op)
+     rtx op;
+{
+  return REG_P (op) && IS_ADDR_OR_PSEUDO_REGNO (op);
+}
+
+
+static int
+c4x_x_register (op)
+     rtx op;
+{
+  return REG_P (op) && IS_INDEX_OR_PSEUDO_REGNO (op);
+}
+
+
+static int
+c4x_int_constant (op)
+     rtx op;
+{
+  if (GET_CODE (op) != CONST_INT)
+    return 0;
+  return GET_MODE (op) == VOIDmode
+    || GET_MODE_CLASS (op) == MODE_INT
+    || GET_MODE_CLASS (op) == MODE_PARTIAL_INT;
+}
+
+
+static int
+c4x_float_constant (op)
+     rtx op;
+{
+  if (GET_CODE (op) != CONST_DOUBLE)
+    return 0;
+  return GET_MODE (op) == QFmode || GET_MODE (op) == HFmode;
+}
+
+
+int
+c4x_H_constant (op)
+     rtx op;
+{
+  return c4x_float_constant (op) && c4x_immed_float_p (op);
+}
+
+
+int
+c4x_I_constant (op)
+     rtx op;
+{
+  return c4x_int_constant (op) && IS_INT16_CONST (INTVAL (op));
+}
+
+
+int
+c4x_J_constant (op)
+     rtx op;
+{
+  if (TARGET_C3X)
+    return 0;
+  return c4x_int_constant (op) && IS_INT8_CONST (INTVAL (op));
+}
+
+
+static int
+c4x_K_constant (op)
+     rtx op;
+{
+  if (TARGET_C3X)
+    return 0;
+  return c4x_int_constant (op) && IS_INT5_CONST (INTVAL (op));
+}
+
+
+int
+c4x_L_constant (op)
+     rtx op;
+{
+  return c4x_int_constant (op) && IS_UINT16_CONST (INTVAL (op));
+}
+
+
+static int
+c4x_N_constant (op)
+     rtx op;
+{
+  return c4x_int_constant (op) && IS_NOT_UINT16_CONST (INTVAL (op));
+}
+
+
+static int
+c4x_O_constant (op)
+     rtx op;
+{
+  return c4x_int_constant (op) && IS_HIGH_CONST (INTVAL (op));
+}
+
+
+/* The constraints do not have to check the register class,
+   except when needed to discriminate between the constraints.
+   The operand has been checked by the predicates to be valid.  */
+
+/* ARx + 9-bit signed const or IRn
+   *ARx, *+ARx(n), *-ARx(n), *+ARx(IRn), *-Arx(IRn) for -256 < n < 256
+   We don't include the pre/post inc/dec forms here since
+   they are handled by the <> constraints.  */
+
+int
+c4x_Q_constraint (op)
+     rtx op;
+{
+  enum machine_mode mode = GET_MODE (op);
+
+  if (GET_CODE (op) != MEM)
+    return 0;
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case REG:
+      return 1;
+
+    case PLUS:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+
+       if (!REG_P (op0))
+         return 0;
+
+       if (REG_P (op1))
+         return 1;
+
+       if (GET_CODE (op1) != CONST_INT)
+         return 0;
+
+       /* HImode and HFmode must be offsettable.  */
+       if (mode == HImode || mode == HFmode)
+         return IS_DISP8_OFF_CONST (INTVAL (op1));
+       
+       return IS_DISP8_CONST (INTVAL (op1));
+      }
+      break;
+    default:
+      break;
+    }
+  return 0;
+}
+
+
+/* ARx + 5-bit unsigned const
+   *ARx, *+ARx(n) for n < 32 */
+
+int
+c4x_R_constraint (op)
+     rtx op;
+{
+  enum machine_mode mode = GET_MODE (op);
+
+  if (TARGET_C3X)
+    return 0;
+  if (GET_CODE (op) != MEM)
+    return 0;
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case REG:
+      return 1;
+
+    case PLUS:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+
+       if (!REG_P (op0))
+         return 0;
+
+       if (GET_CODE (op1) != CONST_INT)
+         return 0;
+
+       /* HImode and HFmode must be offsettable.  */
+       if (mode == HImode || mode == HFmode)
+         return IS_UINT5_CONST (INTVAL (op1) + 1);
+       
+       return IS_UINT5_CONST (INTVAL (op1));
+      }
+      break;
+    default:
+      break;
+    }
+  return 0;
+}
+
+
+static int
+c4x_R_indirect (op)
+     rtx op;
+{
+  enum machine_mode mode = GET_MODE (op);
+
+  if (TARGET_C3X || GET_CODE (op) != MEM)
+    return 0;
+
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case REG:
+      return IS_ADDR_OR_PSEUDO_REGNO (op);
+
+    case PLUS:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+
+       /* HImode and HFmode must be offsettable.  */
+       if (mode == HImode || mode == HFmode)
+         return IS_ADDR_OR_PSEUDO_REGNO (op0)
+           && GET_CODE (op1) == CONST_INT 
+           && IS_UINT5_CONST (INTVAL (op1) + 1);
+
+       return REG_P (op0)
+         && IS_ADDR_OR_PSEUDO_REGNO (op0)
+         && GET_CODE (op1) == CONST_INT
+         && IS_UINT5_CONST (INTVAL (op1));
+      }
+      break;
+
+    default:
+      break;
+    }
+  return 0;
+}
+
+
+/* ARx + 1-bit unsigned const or IRn
+   *ARx, *+ARx(1), *-ARx(1), *+ARx(IRn), *-Arx(IRn)
+   We don't include the pre/post inc/dec forms here since
+   they are handled by the <> constraints.  */
+
+int
+c4x_S_constraint (op)
+     rtx op;
+{
+  enum machine_mode mode = GET_MODE (op);
+  if (GET_CODE (op) != MEM)
+    return 0;
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case REG:
+      return 1;
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+       
+       if ((GET_CODE (op1) != PLUS && GET_CODE (op1) != MINUS)
+           || (op0 != XEXP (op1, 0)))
+         return 0;
+       
+       op0 = XEXP (op1, 0);
+       op1 = XEXP (op1, 1);
+       return REG_P (op0) && REG_P (op1);
+       /* pre or post_modify with a displacement of 0 or 1 
+          should not be generated.  */
+      }
+      break;
+
+    case PLUS:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+
+       if (!REG_P (op0))
+         return 0;
+
+       if (REG_P (op1))
+         return 1;
+
+       if (GET_CODE (op1) != CONST_INT)
+         return 0;
+       
+       /* HImode and HFmode must be offsettable.  */
+       if (mode == HImode || mode == HFmode)
+         return IS_DISP1_OFF_CONST (INTVAL (op1));
+       
+       return IS_DISP1_CONST (INTVAL (op1));
+      }
+      break;
+    default:
+      break;
+    }
+  return 0;
+}
+
+
+static int
+c4x_S_indirect (op)
+     rtx op;
+{
+  enum machine_mode mode = GET_MODE (op);
+  if (GET_CODE (op) != MEM)
+    return 0;
+
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case PRE_DEC:
+    case POST_DEC:
+      if (mode != QImode && mode != QFmode)
+       return 0;
+    case PRE_INC:
+    case POST_INC:
+      op = XEXP (op, 0);
+
+    case REG:
+      return IS_ADDR_OR_PSEUDO_REGNO (op);
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+       
+       if (mode != QImode && mode != QFmode)
+         return 0;
+
+       if ((GET_CODE (op1) != PLUS && GET_CODE (op1) != MINUS)
+           || (op0 != XEXP (op1, 0)))
+         return 0;
+       
+       op0 = XEXP (op1, 0);
+       op1 = XEXP (op1, 1);
+       return REG_P (op0) && IS_ADDR_OR_PSEUDO_REGNO (op0)
+         && REG_P (op1) && IS_INDEX_OR_PSEUDO_REGNO (op1);
+       /* pre or post_modify with a displacement of 0 or 1 
+          should not be generated.  */
+      }
+
+    case PLUS:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+
+       if (REG_P (op0))
+         {
+           /* HImode and HFmode must be offsettable.  */
+           if (mode == HImode || mode == HFmode)
+             return IS_ADDR_OR_PSEUDO_REGNO (op0)
+               && GET_CODE (op1) == CONST_INT 
+               && IS_DISP1_OFF_CONST (INTVAL (op1));
+
+           if (REG_P (op1))
+             return (IS_INDEX_OR_PSEUDO_REGNO (op1)
+                     && IS_ADDR_OR_PSEUDO_REGNO (op0))
+               || (IS_ADDR_OR_PSEUDO_REGNO (op1)
+                   && IS_INDEX_OR_PSEUDO_REGNO (op0));
+           
+           return IS_ADDR_OR_PSEUDO_REGNO (op0)
+             && GET_CODE (op1) == CONST_INT 
+             && IS_DISP1_CONST (INTVAL (op1));
+         }
+      }
+      break;
+
+    default:
+      break;
+    }
+  return 0;
+}
+
+
+/* Symbol ref.  */
+
+int
+c4x_T_constraint (op)
+     rtx op;
+{
+  if (GET_CODE (op) != MEM)
+    return 0;
+  op = XEXP (op, 0);
+
+  if ((GET_CODE (op) == PLUS)
+      && (GET_CODE (XEXP (op, 0)) == REG)
+      && (REGNO (XEXP (op, 0)) == DP_REGNO))
+    {
+      op = XEXP (op, 1);
+    }
+  else if ((GET_CODE (op) == PLUS)
+          && (GET_CODE (XEXP (op, 0)) == PLUS)
+          && (GET_CODE (XEXP (XEXP (op, 0), 0)) == USE))
+    {
+      op = XEXP (op, 1);
+    }
+  else if ((GET_CODE (op) == PLUS) && (GET_CODE (XEXP (op, 0)) == USE))
+    {
+      op = XEXP (op, 1);
+    }
+
+  /* Don't allow direct addressing to an arbitrary constant.  */
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
+      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+    return 1;
+
+  return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
+}
+
+
+int
+c4x_autoinc_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) == MEM)
+    {
+      enum rtx_code code = GET_CODE (XEXP (op, 0));
+      
+      if (code == PRE_INC
+         || code == PRE_DEC
+         || code == POST_INC
+         || code == POST_DEC
+         || code == PRE_MODIFY
+         || code == POST_MODIFY
+         )
+       return 1;
+    }
+  return 0;
+}
+
+
+/* Match any operand.  */
+
+int
+any_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  return 1;
+}
+
+
+/* Nonzero if OP is a floating point value with value 0.0.  */
+
+int
+fp_zero_operand (op)
+     rtx op;
+{
+  REAL_VALUE_TYPE r;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+  return REAL_VALUES_EQUAL (r, dconst0);
+}
+
+
+int
+const_operand (op, mode)
+     register rtx op;
+     register enum machine_mode mode;
+{
+  switch (mode)
+    {
+    case QFmode:
+    case HFmode:
+      if (GET_CODE (op) != CONST_DOUBLE
+         || GET_MODE (op) != mode
+         || GET_MODE_CLASS (mode) != MODE_FLOAT)
+       return 0;
+
+      return c4x_immed_float_p (op);
+
+#if Pmode != QImode
+    case Pmode:
+#endif
+    case QImode:
+      if (GET_CODE (op) != CONST_INT
+         || (GET_MODE (op) != VOIDmode && GET_MODE (op) != mode)
+         || GET_MODE_CLASS (mode) != MODE_INT)
+       return 0;
+
+      return IS_HIGH_CONST (INTVAL (op)) || IS_INT16_CONST (INTVAL (op));
+
+    case HImode:
+      return 0;
+
+    default:
+      return 0;
+    }
+}
+
+
+int
+stik_const_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_K_constant (op);
+}
+
+
+int
+not_const_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_N_constant (op);
+}
+
+
+int
+reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return register_operand (op, mode);
+}
+
+int
+reg_imm_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (REG_P (op) || CONSTANT_P (op))
+    return 1;
+  return 0;
+}
+
+int
+not_modify_reg (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (REG_P (op) || CONSTANT_P (op))
+    return 1;
+  if (GET_CODE (op) != MEM)
+    return 0;
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case REG:
+      return 1;
+
+    case PLUS:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+
+       if (!REG_P (op0))
+         return 0;
+       
+       if (REG_P (op1) || GET_CODE (op1) == CONST_INT)
+         return 1;
+      }
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 1;
+    default:
+      break;
+    }
+  return 0;
+}
+
+int
+not_rc_reg (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (REG_P (op) && REGNO (op) == RC_REGNO)
+    return 0;
+  return 1;
+}
+
+/* Extended precision register R0-R1.  */
+
+int
+r0r1_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (!register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return REG_P (op) && IS_R0R1_OR_PSEUDO_REGNO (op);
+}
+
+
+/* Extended precision register R2-R3.  */
+
+int
+r2r3_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (!register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return REG_P (op) && IS_R2R3_OR_PSEUDO_REGNO (op);
+}
+
+
+/* Low extended precision register R0-R7.  */
+
+int
+ext_low_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (!register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return REG_P (op) && IS_EXT_LOW_OR_PSEUDO_REGNO (op);
+}
+
+
+/* Extended precision register.  */
+
+int
+ext_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (!register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (!REG_P (op))
+    return 0;
+  return IS_EXT_OR_PSEUDO_REGNO (op);
+}
+
+
+/* Standard precision register.  */
+
+int
+std_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (!register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return REG_P (op) && IS_STD_OR_PSEUDO_REGNO (op);
+}
+
+
+/* Address register.  */
+
+int
+addr_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (!register_operand (op, mode))
+    return 0;
+  return c4x_a_register (op);
+}
+
+
+/* Index register.  */
+
+int
+index_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (!register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return c4x_x_register (op);
+}
+
+
+/* DP register.  */
+
+int
+dp_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return REG_P (op) && IS_DP_OR_PSEUDO_REGNO (op);
+}
+
+
+/* SP register.  */
+
+int
+sp_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return REG_P (op) && IS_SP_OR_PSEUDO_REGNO (op);
+}
+
+
+/* ST register.  */
+
+int
+st_reg_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  return REG_P (op) && IS_ST_OR_PSEUDO_REGNO (op);
+}
+
+
+int
+call_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) != MEM)
+    return 0;
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case SYMBOL_REF:
+    case REG:
+      return 1;
+    default:
+    }
+  return 0;
+}
+
+
+/* Check src operand of two operand arithmetic instructions.  */
+
+int
+src_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (REG_P (op))
+    return reg_operand (op, mode);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (op);
+
+  /* We could allow certain CONST_INT values for HImode...  */
+  if (GET_CODE (op) == CONST_INT)
+    return (mode == QImode || mode == Pmode) && c4x_I_constant (op);
+
+  /* We don't like CONST_DOUBLE integers.  */
+  if (GET_CODE (op) == CONST_DOUBLE)
+    return c4x_H_constant (op);
+
+  return general_operand (op, mode);
+}
+
+
+int
+src_hi_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (c4x_O_constant (op))
+    return 1;
+  return src_operand (op, mode);
+}
+
+
+/* Check src operand of two operand logical instructions.  */
+
+int
+lsrc_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode == VOIDmode)
+    mode = GET_MODE (op);
+
+  if (mode != QImode && mode != Pmode)
+    fatal_insn ("Mode not QImode", op);
+
+  if (REG_P (op))
+    return reg_operand (op, mode);
+
+  if (GET_CODE (op) == CONST_INT)
+    return c4x_L_constant (op) || c4x_J_constant (op);
+
+  return general_operand (op, mode);
+}
+
+
+/* Check src operand of two operand tricky instructions.  */
+
+int
+tsrc_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode == VOIDmode)
+    mode = GET_MODE (op);
+
+  if (mode != QImode && mode != Pmode)
+    fatal_insn ("Mode not QImode", op);
+
+  if (REG_P (op))
+    return reg_operand (op, mode);
+
+  if (GET_CODE (op) == CONST_INT)
+    return c4x_L_constant (op) || c4x_N_constant (op) || c4x_J_constant (op);
+
+  return general_operand (op, mode);
+}
+
+
+int
+reg_or_const_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return reg_operand (op, mode) || const_operand (op, mode);
+}
+
+
+/* Check for indirect operands allowable in parallel instruction.  */
+
+int
+par_ind_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  return c4x_S_indirect (op);
+}
+
+
+/* Check for operands allowable in parallel instruction.  */
+
+int
+parallel_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return ext_low_reg_operand (op, mode) || par_ind_operand (op, mode);
+}
+
+
+static void 
+c4x_S_address_parse (op, base, incdec, index, disp)
+     rtx op;
+     int *base;
+     int *incdec;
+     int *index;
+     int *disp;
+{
+  *base = 0;
+  *incdec = 0;
+  *index = 0;
+  *disp = 0;
+       
+  if (GET_CODE (op) != MEM)
+    fatal_insn ("Invalid indirect memory address", op);
+  
+  op = XEXP (op, 0);
+  switch (GET_CODE (op))
+    {
+    case PRE_DEC:
+      *base = REGNO (XEXP (op, 0));
+      *incdec = 1;
+      *disp = -1;
+      return;
+
+    case POST_DEC:
+      *base = REGNO (XEXP (op, 0));
+      *incdec = 1;
+      *disp = 0;
+      return;
+
+    case PRE_INC:
+      *base = REGNO (XEXP (op, 0));
+      *incdec = 1;
+      *disp = 1;
+      return;
+
+    case POST_INC:
+      *base = REGNO (XEXP (op, 0));
+      *incdec = 1;
+      *disp = 0;
+      return;
+
+    case POST_MODIFY:
+      *base = REGNO (XEXP (op, 0));
+      if (REG_P (XEXP (XEXP (op, 1), 1)))
+       {
+         *index = REGNO (XEXP (XEXP (op, 1), 1));
+         *disp = 0;            /* ??? */
+       }
+      else
+         *disp = INTVAL (XEXP (XEXP (op, 1), 1));
+      *incdec = 1;
+      return;
+
+    case PRE_MODIFY:
+      *base = REGNO (XEXP (op, 0));
+      if (REG_P (XEXP (XEXP (op, 1), 1)))
+       {
+         *index = REGNO (XEXP (XEXP (op, 1), 1));
+         *disp = 1;            /* ??? */
+       }
+      else
+         *disp = INTVAL (XEXP (XEXP (op, 1), 1));
+      *incdec = 1;
+
+      return;
+
+    case REG:
+      *base = REGNO (op);
+      return;
+
+    case PLUS:
+      {
+       rtx op0 = XEXP (op, 0);
+       rtx op1 = XEXP (op, 1);
+
+       if (c4x_a_register (op0))
+         {
+           if (c4x_x_register (op1))
+             {
+               *base = REGNO (op0);
+               *index = REGNO (op1);
+               return;
+             }
+           else if ((GET_CODE (op1) == CONST_INT 
+                     && IS_DISP1_CONST (INTVAL (op1))))
+             {
+               *base = REGNO (op0);
+               *disp = INTVAL (op1);
+               return;
+             }
+         }
+       else if (c4x_x_register (op0) && c4x_a_register (op1))
+         {
+           *base = REGNO (op1);
+           *index = REGNO (op0);
+           return;
+         }
+      }
+      /* Fallthrough  */
+
+    default:
+      fatal_insn ("Invalid indirect (S) memory address", op);
+    }
+}
+
+
+int
+c4x_address_conflict (op0, op1, store0, store1)
+     rtx op0;
+     rtx op1;
+     int store0;
+     int store1;
+{
+  int base0;
+  int base1;
+  int incdec0;
+  int incdec1;
+  int index0;
+  int index1;
+  int disp0;
+  int disp1;
+  
+  c4x_S_address_parse (op0, &base0, &incdec0, &index0, &disp0);
+  c4x_S_address_parse (op1, &base1, &incdec1, &index1, &disp1);
+
+  if (store0 && store1)
+    {
+      /* If we have two stores in parallel to the same address, then
+        the C4x only executes one of the stores.  This is unlikely to
+        cause problems except when writing to a hardware device such
+        as a FIFO since the second write will be lost.  The user
+        should flag the hardware location as being volatile so that
+        we don't do this optimisation.  While it is unlikely that we
+        have an aliased address if both locations are not marked
+        volatile, it is probably safer to flag a potential conflict
+        if either location is volatile.  */
+      if (!TARGET_ALIASES)
+       {
+         if (MEM_VOLATILE_P (op0) && MEM_VOLATILE_P (op1))
+           return 1;
+       }
+      else
+       {
+         if (MEM_VOLATILE_P (op0) || MEM_VOLATILE_P (op1))
+           return 1;
+       }
+    }
+
+  /* If have a parallel load and a store to the same address, the load
+     is performed first, so there is no conflict.  Similarly, there is
+     no conflict if have parallel loads from the same address.  */
+
+  /* Cannot use auto increment or auto decrement twice for same
+     base register.  */
+  if (base0 == base1 && incdec0 && incdec0)
+    return 1;
+
+  /* It might be too confusing for GCC if we have use a base register
+     with a side effect and a memory reference using the same register
+     in parallel.  */
+  if (!TARGET_DEVEL && base0 == base1 && (incdec0 || incdec1))
+    return 1;
+
+  /* It is not worthwhile having parallel loads from the same address
+     unless we could be sure that both locations were in internal
+     memory.  We allow this for peepholes (after reload has completed
+     since we are going to be executing two insns to the same address
+     anyhow) but steer the combiner away from doing this since it seems
+     to get the wrong idea.  */
+  if (!store0 && !store1 && base0 == base1 && disp0 == disp1
+      && !reload_completed)
+    return 1;
+
+  /* No conflict.  */
+  return 0;
+}
+
+
+/* Check for while loop inside a decrement and branch loop.  */
+
+int
+c4x_label_conflict (insn, jump, db)
+     rtx insn;
+     rtx jump;
+     rtx db;
+{
+  while (insn)
+    {
+      if (GET_CODE (insn) == CODE_LABEL)
+       {
+          if (CODE_LABEL_NUMBER (jump) == CODE_LABEL_NUMBER (insn))
+           return 1;
+          if (CODE_LABEL_NUMBER (db) == CODE_LABEL_NUMBER (insn))
+           return 0;
+       }
+      insn = PREV_INSN (insn);
+    }
+  return 1;
+}
+
+
+/* Validate combination of operands for parallel load/store instructions.  */
+
+int
+valid_parallel_operands_4 (operands, mode)
+     rtx *operands;
+     enum machine_mode mode;
+{
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+  rtx op2 = operands[2];
+  rtx op3 = operands[3];
+
+  if (GET_CODE (op0) == SUBREG)
+    op0 = SUBREG_REG (op0);
+  if (GET_CODE (op1) == SUBREG)
+    op1 = SUBREG_REG (op1);
+  if (GET_CODE (op2) == SUBREG)
+    op2 = SUBREG_REG (op2);
+  if (GET_CODE (op3) == SUBREG)
+    op3 = SUBREG_REG (op3);
+
+  /* The patterns should only allow ext_low_reg_operand() or
+     par_ind_operand() operands.  Thus of the 4 operands, only 2
+     should be REGs and the other 2 should be MEMs.  */
+
+  /* LDI||LDI  */
+  if (GET_CODE (op0) == REG && GET_CODE (op2) == REG)
+    return (REGNO (op0) != REGNO (op2))
+      && GET_CODE (op1) == MEM && GET_CODE (op3) == MEM
+      && !c4x_address_conflict (op1, op3, 0, 0);
+
+  /* STI||STI  */
+  if (GET_CODE (op1) == REG && GET_CODE (op3) == REG)
+    return GET_CODE (op0) == MEM && GET_CODE (op2) == MEM
+      && !c4x_address_conflict (op0, op2, 1, 1);
+
+  /* LDI||STI  */
+  if (GET_CODE (op0) == REG && GET_CODE (op3) == REG)
+    return GET_CODE (op1) == MEM && GET_CODE (op2) == MEM
+      && !c4x_address_conflict (op1, op2, 0, 1);
+
+  /* STI||LDI  */
+  if (GET_CODE (op1) == REG && GET_CODE (op2) == REG)
+    return GET_CODE (op0) == MEM && GET_CODE (op3) == MEM
+      && !c4x_address_conflict (op0, op3, 1, 0);
+
+  return 0;
+}
+
+/* We only use this to check operands 1 and 2 since these may be
+   commutative.  It will need extending for the C32 opcodes.  */
+int
+valid_parallel_operands_5 (operands, mode)
+     rtx *operands;
+     enum machine_mode mode;
+{
+  int regs = 0;
+  rtx op0 = operands[1];
+  rtx op1 = operands[2];
+
+  if (GET_CODE (op0) == SUBREG)
+    op0 = SUBREG_REG (op0);
+  if (GET_CODE (op1) == SUBREG)
+    op1 = SUBREG_REG (op1);
+
+  /* The patterns should only allow ext_low_reg_operand() or
+     par_ind_operand() operands. */
+
+  if (GET_CODE (op0) == REG)
+    regs++;
+  if (GET_CODE (op1) == REG)
+    regs++;
+
+  return regs == 1;
+}
+
+
+int
+valid_parallel_operands_6 (operands, mode)
+     rtx *operands;
+     enum machine_mode mode;
+{
+  int regs = 0;
+  rtx op0 = operands[1];
+  rtx op1 = operands[2];
+  rtx op2 = operands[4];
+  rtx op3 = operands[5];
+
+  if (GET_CODE (op0) == SUBREG)
+    op0 = SUBREG_REG (op0);
+  if (GET_CODE (op1) == SUBREG)
+    op1 = SUBREG_REG (op1);
+  if (GET_CODE (op2) == SUBREG)
+    op2 = SUBREG_REG (op2);
+  if (GET_CODE (op3) == SUBREG)
+    op3 = SUBREG_REG (op3);
+
+  /* The patterns should only allow ext_low_reg_operand() or
+     par_ind_operand() operands.  Thus of the 4 input operands, only 2
+     should be REGs and the other 2 should be MEMs.  */
+
+  if (GET_CODE (op0) == REG)
+    regs++;
+  if (GET_CODE (op1) == REG)
+    regs++;
+  if (GET_CODE (op2) == REG)
+    regs++;
+  if (GET_CODE (op3) == REG)
+    regs++;
+
+  /* The new C30/C40 silicon dies allow 3 regs of the 4 input operands. 
+     Perhaps we should count the MEMs as well?  */
+  return regs == 2;
+}
+
+
+int
+legitimize_parallel_operands_6 (operands, mode)
+     rtx *operands;
+     enum machine_mode mode;
+{
+  /* It's gonna be hard to legitimize operands for a parallel
+     instruction... TODO...  */
+  return valid_parallel_operands_6 (operands, mode);
+}
+
+
+/* Validate combination of src operands.  Note that the operands have
+   been screened by the src_operand predicate.  We just have to check
+   that the combination of operands is valid.  If FORCE is set, ensure
+   that the destination regno is valid if we have a 2 operand insn.  */
+
+static int
+c4x_valid_operands (code, operands, mode, force)
+     enum rtx_code code;
+     rtx *operands;
+     enum machine_mode mode;
+     int force;
+{
+  rtx op1;
+  rtx op2;
+  enum rtx_code code1;
+  enum rtx_code code2;
+
+  if (code == COMPARE)
+    {
+      op1 = operands[0];
+      op2 = operands[1];
+    }
+  else
+    {
+      op1 = operands[1];
+      op2 = operands[2];
+    }
+
+  if (GET_CODE (op1) == SUBREG)
+    op1 = SUBREG_REG (op1);
+  if (GET_CODE (op2) == SUBREG)
+    op2 = SUBREG_REG (op2);
+
+  code1 = GET_CODE (op1);
+  code2 = GET_CODE (op2);
+
+  if (code1 == REG && code2 == REG)
+    return 1;
+
+  if (code1 == MEM && code2 == MEM)
+    {
+      if (c4x_S_indirect (op1, mode) && c4x_S_indirect (op2, mode))
+       return 1;
+      return c4x_R_indirect (op1, mode) && c4x_R_indirect (op2, mode);
+    }
+
+  if (code1 == code2)
+    return 0;
+
+  if (code1 == REG)
+    {
+      switch (code2)
+       {
+       case CONST_INT:
+         if (c4x_J_constant (op2) && c4x_R_indirect (op1))
+           return 1;
+         break;
+         
+       case CONST_DOUBLE:
+         if (!c4x_H_constant (op2))
+           return 0;
+         break;
+
+         /* Any valid memory operand screened by src_operand is OK.  */
+       case MEM:
+         
+         /* After CSE, any remaining (ADDRESSOF:P reg) gets converted
+            into a stack slot memory address comprising a PLUS and a
+            constant.  */
+       case ADDRESSOF:
+         break;
+         
+       default:
+         fatal ("c4x_valid_operands: Internal error");
+         break;
+       }
+      
+      /* Check that we have a valid destination register for a two operand
+        instruction.  */
+      return !force || code == COMPARE || REGNO (op1) == REGNO (operands[0]);
+    }
+
+  /* We assume MINUS is commutative since the subtract patterns
+     also support the reverse subtract instructions.  Since op1
+     is not a register, and op2 is a register, op1 can only
+     be a restricted memory operand for a shift instruction.  */
+  if (code == ASHIFTRT || code == LSHIFTRT
+      || code == ASHIFT || code == COMPARE)
+    return code2 == REG
+      && (c4x_S_indirect (op1) || c4x_R_indirect (op1));
+  
+  switch (code1)
+    {
+    case CONST_INT:
+      if (c4x_J_constant (op1) && c4x_R_indirect (op2))
+       return 1;
+      break;
+      
+    case CONST_DOUBLE:
+      if (!c4x_H_constant (op1))
+       return 0;
+      break;
+
+      /* Any valid memory operand screened by src_operand is OK. */      
+    case MEM:
+
+      /* After CSE, any remaining (ADDRESSOF:P reg) gets converted
+        into a stack slot memory address comprising a PLUS and a
+        constant.  */
+    case ADDRESSOF:
+      break;
+      
+    default:
+      fatal ("c4x_valid_operands: Internal error");
+      break;
+    }
+      
+  /* Check that we have a valid destination register for a two operand
+     instruction.  */
+  return !force || REGNO (op1) == REGNO (operands[0]);
+}
+
+
+int valid_operands (code, operands, mode)
+     enum rtx_code code;
+     rtx *operands;
+     enum machine_mode mode;
+{
+
+  /* If we are not optimizing then we have to let anything go and let
+     reload fix things up.  instantiate_decl in function.c can produce
+     invalid insns by changing the offset of a memory operand from a
+     valid one into an invalid one, when the second operand is also a
+     memory operand.  The alternative is not to allow two memory
+     operands for an insn when not optimizing.  The problem only rarely
+     occurs, for example with the C-torture program DFcmp.c  */
+
+  return !optimize || c4x_valid_operands (code, operands, mode, 0);
+}
+
+
+int
+legitimize_operands (code, operands, mode)
+     enum rtx_code code;
+     rtx *operands;
+     enum machine_mode mode;
+{
+  /* Compare only has 2 operands.  */
+  if (code == COMPARE)
+    {
+      /* During RTL generation, force constants into pseudos so that
+        they can get hoisted out of loops.  This will tie up an extra
+        register but can save an extra cycle.  Only do this if loop
+        optimisation enabled.  (We cannot pull this trick for add and
+        sub instructions since the flow pass won't find
+        autoincrements etc.)  This allows us to generate compare
+        instructions like CMPI R0, *AR0++ where R0 = 42, say, instead
+        of LDI *AR0++, R0; CMPI 42, R0. 
+
+        Note that expand_binops will try to load an expensive constant
+        into a register if it is used within a loop.  Unfortunately,
+        the cost mechanism doesn't allow us to look at the other
+        operand to decide whether the constant is expensive.  */
+      
+      if (!reload_in_progress
+         && TARGET_HOIST
+         && optimize > 0
+         && ((GET_CODE (operands[1]) == CONST_INT 
+              && !c4x_J_constant (operands[1])
+              && INTVAL (operands[1]) != 0)
+             || GET_CODE (operands[1]) == CONST_DOUBLE))
+       operands[1] = force_reg (mode, operands[1]);
+      
+      if (!reload_in_progress
+          && !c4x_valid_operands (code, operands, mode, 0))
+       operands[0] = force_reg (mode, operands[0]);
+      return 1;
+    }
+  
+  /* We cannot do this for ADDI/SUBI insns since we will
+     defeat the flow pass from finding autoincrement addressing
+     opportunities.  */
+  if (!reload_in_progress
+      && !((code == PLUS || code == MINUS) && mode == Pmode)
+      && (TARGET_HOIST && optimize > 1
+       && ((GET_CODE (operands[2]) == CONST_INT 
+           && !c4x_J_constant (operands[2])
+           && INTVAL (operands[2]) != 0)
+          || GET_CODE (operands[2]) == CONST_DOUBLE)))
+    operands[2] = force_reg (mode, operands[2]);
+
+  /* We can get better code on a C30 if we force constant shift counts
+     into a register.  This way they can get hoisted out of loops,
+     tying up a register, but saving an instruction.  The downside is
+     that they may get allocated to an address or index register, and
+     thus we will get a pipeline conflict if there is a nearby
+     indirect address using an address register. 
+
+     Note that expand_binops will not try to load an expensive constant
+     into a register if it is used within a loop for a shift insn.  */
+  
+  if (!reload_in_progress
+      && !c4x_valid_operands (code, operands, mode, TARGET_FORCE))
+    {
+      /* If the operand combination is invalid, we force operand1 into a
+         register, preventing reload from having doing to do this at a
+         later stage.  */
+      operands[1] = force_reg (mode, operands[1]);
+      if (TARGET_FORCE)
+       {
+         emit_move_insn (operands[0], operands[1]);
+         operands[1] = copy_rtx (operands[0]);
+       }
+      else
+       {
+         /* Just in case...  */
+         if (!c4x_valid_operands (code, operands, mode, 0))
+           operands[2] = force_reg (mode, operands[2]);
+       }
+    }
+
+  /* Right shifts require a negative shift count, but GCC expects
+     a positive count, so we emit a NEG.  */
+  if ((code == ASHIFTRT || code == LSHIFTRT)
+      && (GET_CODE (operands[2]) != CONST_INT))
+    operands[2] = gen_rtx (NEG, mode, negate_rtx (mode, operands[2]));
+  
+  return 1;
+}
+
+
+/* The following predicates are used for instruction scheduling.  */
+
+int
+group1_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return REG_P (op) && IS_GROUP1_REG (REGNO (op));
+}
+
+
+int
+group1_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (GET_CODE (op) == MEM)
+    {
+      op = XEXP (op, 0);
+      if (GET_CODE (op) == PLUS)
+       {
+         rtx op0 = XEXP (op, 0);
+         rtx op1 = XEXP (op, 1);
+
+         if (((GET_CODE (op0) == REG) && IS_GROUP1_REGNO (op0))
+             || ((GET_CODE (op1) == REG) && IS_GROUP1_REGNO (op1)))
+           return 1;
+       }
+      else if ((REG_P (op)) && IS_GROUP1_REGNO (op))
+       return 1;
+    }
+
+  return 0;
+}
+
+
+/* Return true if any one of the address registers.  */
+
+int
+arx_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return REG_P (op) && IS_ADDR_REGNO (op);
+}
+
+
+static int
+c4x_arn_reg_operand (op, mode, regno)
+     rtx op;
+     enum machine_mode mode;
+     int regno;
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  return REG_P (op) && (REGNO (op) == regno);
+}
+
+
+static int
+c4x_arn_mem_operand (op, mode, regno)
+     rtx op;
+     enum machine_mode mode;
+     int regno;
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (GET_CODE (op) == MEM)
+    {
+      op = XEXP (op, 0);
+      switch (GET_CODE (op))
+       {
+       case PRE_DEC:
+       case POST_DEC:
+       case PRE_INC:
+       case POST_INC:
+         op = XEXP (op, 0);
+
+       case REG:
+          if (REG_P (op) && (REGNO (op) == regno))
+           return 1;
+         break;
+
+       case PRE_MODIFY:
+       case POST_MODIFY:
+          if (REG_P (XEXP (op, 0)) && (REGNO (XEXP (op, 0)) == regno))
+           return 1;
+          if (REG_P (XEXP (XEXP (op, 1), 1))
+             && (REGNO (XEXP (XEXP (op, 1), 1)) == regno))
+           return 1;
+         break;
+
+       case PLUS:
+         {
+           rtx op0 = XEXP (op, 0);
+           rtx op1 = XEXP (op, 1);
+
+           if (((GET_CODE (op0) == REG) && (REGNO (op0) == regno)) 
+               || ((GET_CODE (op1) == REG) && (REGNO (op1) == regno)))
+             return 1;
+         }
+         break;
+       default:
+         break;
+       }
+    }
+  return 0;
+}
+
+
+int
+ar0_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR0_REGNO);
+}
+
+
+int
+ar0_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR0_REGNO);
+}
+
+
+int
+ar1_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR1_REGNO);
+}
+
+
+int
+ar1_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR1_REGNO);
+}
+
+
+int
+ar2_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR2_REGNO);
+}
+
+
+int
+ar2_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR2_REGNO);
+}
+
+
+int
+ar3_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR3_REGNO);
+}
+
+
+int
+ar3_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR3_REGNO);
+}
+
+
+int
+ar4_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR4_REGNO);
+}
+
+
+int
+ar4_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR4_REGNO);
+}
+
+
+int
+ar5_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR5_REGNO);
+}
+
+
+int
+ar5_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR5_REGNO);
+}
+
+
+int
+ar6_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR6_REGNO);
+}
+
+
+int
+ar6_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR6_REGNO);
+}
+
+
+int
+ar7_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, AR7_REGNO);
+}
+
+
+int
+ar7_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, AR7_REGNO);
+}
+
+
+int
+ir0_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, IR0_REGNO);
+}
+
+
+int
+ir0_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, IR0_REGNO);
+}
+
+
+int
+ir1_reg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_reg_operand (op, mode, IR1_REGNO);
+}
+
+
+int
+ir1_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return c4x_arn_mem_operand (op, mode, IR1_REGNO);
+}
+
+
+/* We allow autoincrement addressing.  */
+
+rtx
+c4x_operand_subword (op, i, validate_address, mode)
+     rtx op;
+     int i;
+     int validate_address;
+     enum machine_mode mode;
+{
+  if (mode != HImode && mode != HFmode)
+    fatal_insn ("c4x_operand_subword: invalid mode", op);
+
+  if (mode == HFmode && REG_P (op))
+    fatal_insn ("c4x_operand_subword: invalid operand", op);
+
+  if (GET_CODE (op) == MEM)
+    {
+      enum rtx_code code = GET_CODE (XEXP (op, 0));
+      enum machine_mode mode = GET_MODE (XEXP (op, 0));
+
+      switch (code)
+       {
+       case POST_INC:
+       case PRE_INC:
+         if (mode == HImode)
+           mode = QImode;
+         else if (mode == HFmode)
+           mode = QFmode;
+         return gen_rtx (MEM, mode, XEXP (op, 0));
+         
+       case POST_DEC:
+       case PRE_DEC:
+       case PRE_MODIFY:
+       case POST_MODIFY:
+         /* We could handle these with some difficulty.
+            e.g., *p-- => *(p-=2); *(p+1).  */
+         fatal_insn ("c4x_operand_subword: invalid autoincrement", op);
+
+       default:
+         break;
+       }
+    }
+  
+  return operand_subword (op, i, validate_address, mode);
+}
+
+/* Handle machine specific pragmas for compatibility with existing
+   compilers for the C3x/C4x.
+
+   pragma                                 attribute
+   ----------------------------------------------------------
+   CODE_SECTION(symbol,"section")          section("section")
+   DATA_SECTION(symbol,"section")          section("section")
+   FUNC_CANNOT_INLINE(function)            
+   FUNC_EXT_CALLED(function)               
+   FUNC_IS_PURE(function)                  const
+   FUNC_IS_SYSTEM(function)                
+   FUNC_NEVER_RETURNS(function)            noreturn
+   FUNC_NO_GLOBAL_ASG(function)            
+   FUNC_NO_IND_ASG(function)               
+   INTERRUPT(function)                     interrupt
+
+   */
+
+int
+c4x_handle_pragma (p_getc, p_ungetc, pname)
+     int (*  p_getc) PROTO ((void));
+     void (* p_ungetc) PROTO ((int));
+     char *pname;
+{
+  int i;
+  int c;
+  int namesize;
+  char *name;
+  tree func;
+  tree sect = NULL_TREE;
+  tree new;
+
+  c = p_getc ();
+  while (c == ' ' || c == '\t') c = p_getc ();
+  if (c != '(')
+    return 0;
+
+  c = p_getc ();
+  while (c == ' ' || c == '\t') c = p_getc ();
+  if (!(isalpha(c) || c == '_' || c == '$' || c == '@'))
+    return 0;
+
+  i = 0;
+  namesize = 16;
+  name = xmalloc (namesize);
+  while (isalnum (c) || c == '_' || c == '$' || c == '@')
+    {
+      if (i >= namesize-1)
+       {
+         namesize += 16;
+         name = xrealloc (name, namesize);
+       }
+      name[i++] = c;
+      c = p_getc ();
+    }
+  name[i] = 0;
+  func = get_identifier (name);
+  free (name);
+  
+  if (strcmp (pname, "CODE_SECTION") == 0
+      || strcmp (pname, "DATA_SECTION") == 0)
+    {
+      while (c == ' ' || c == '\t') c = p_getc ();
+      if (c != ',')
+        return 0;
+
+      c = p_getc ();
+      while (c == ' ' || c == '\t') c = p_getc ();
+      if (c != '"')
+        return 0;
+
+      i = 0;
+      namesize = 16;
+      name = xmalloc (namesize);
+      c = p_getc ();
+      while (c != '"' && c != '\n' && c != '\r' && c != EOF)
+        {
+          if (i >= namesize-1)
+           {
+             namesize += 16;
+             name = xrealloc (name, namesize);
+           }
+          name[i++] = c;
+          c = p_getc ();
+        }
+      name[i] = 0;
+      sect = build_string (i, name);
+      TREE_TYPE (sect) = char_array_type_node;
+      free (name);
+      sect = build_tree_list (NULL_TREE, sect);
+      
+      if (c != '"')
+        return 0;
+      c = p_getc ();
+    }
+  while (c == ' ' || c == '\t') c = p_getc ();
+  if (c != ')')
+    return 0;
+  
+  new = build_tree_list (func, sect);
+  if (strcmp (pname, "CODE_SECTION") == 0)
+    code_tree = chainon (code_tree, new);
+  
+  else if (strcmp (pname, "DATA_SECTION") == 0)
+    data_tree = chainon (data_tree, new);
+  
+  else if (strcmp (pname, "FUNC_CANNOT_INLINE") == 0)
+      ; /* ignore */
+  
+  else if (strcmp (pname, "FUNC_EXT_CALLED") == 0)
+      ; /* ignore */
+  
+  else if (strcmp (pname, "FUNC_IS_PURE") == 0)
+     pure_tree = chainon (pure_tree, new);
+  
+  else if (strcmp (pname, "FUNC_IS_SYSTEM") == 0)
+      ; /* ignore */
+  
+  else if (strcmp (pname, "FUNC_NEVER_RETURNS") == 0)
+    noreturn_tree = chainon (noreturn_tree, new);
+  
+  else if (strcmp (pname, "FUNC_NO_GLOBAL_ASG") == 0)
+      ; /* ignore */
+  
+  else if (strcmp (pname, "FUNC_NO_IND_ASG") == 0)
+      ; /* ignore */
+  
+  else if (strcmp (pname, "INTERRUPT") == 0)
+    interrupt_tree = chainon (interrupt_tree, new);
+  
+  else
+    return 0;
+  
+  return 1;
+}
+
+
+static void
+c4x_check_attribute(attrib, list, decl, attributes)
+     char *attrib;
+     tree list, decl, *attributes;
+{
+  while (list != NULL_TREE
+         && IDENTIFIER_POINTER (TREE_PURPOSE (list)) !=
+        IDENTIFIER_POINTER (DECL_NAME (decl)))
+    list = TREE_CHAIN(list);
+  if (list)
+    *attributes = chainon (*attributes,
+                          build_tree_list (get_identifier (attrib),
+                                           TREE_VALUE(list)));
+}
+
+
+void
+c4x_set_default_attributes(decl, attributes)
+     tree decl, *attributes;
+{
+  switch (TREE_CODE (decl))
+    {
+    case FUNCTION_DECL:
+      c4x_check_attribute ("section", code_tree, decl, attributes);
+      c4x_check_attribute ("const", pure_tree, decl, attributes);
+      c4x_check_attribute ("noreturn", noreturn_tree, decl, attributes);
+      c4x_check_attribute ("interrupt", interrupt_tree, decl, attributes);
+      break;
+
+    case VAR_DECL:
+      c4x_check_attribute ("section", data_tree, decl, attributes);
+      break;
+
+    default:
+      break;
+    }
+}
+
+
+/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine
+   specific attribute for TYPE.  The attributes in ATTRIBUTES have
+   previously been assigned to TYPE.  */
+
+int
+c4x_valid_type_attribute_p (type, attributes, identifier, args)
+     tree type;
+     tree attributes;
+     tree identifier;
+     tree args;
+{
+  if (TREE_CODE (type) != FUNCTION_TYPE)
+    return 0;
+  
+  if (is_attribute_p ("interrupt", identifier))
+    return 1;
+  
+  if (is_attribute_p ("assembler", identifier))
+    return 1;
+  
+  if (is_attribute_p ("leaf_pretend", identifier))
+    return 1;
+  
+  return 0;
+}
+
+
+/* This is a modified version of modified_between_p that doesn't give
+   up if a changing MEM is found.  It checks all insns between START
+   and END to see if any registers mentioned in X are set. */
+static int
+c4x_modified_between_p (x, start, end)
+     rtx x;
+     rtx start, end;
+{
+  enum rtx_code code = GET_CODE (x);
+  char *fmt;
+  int i, j;
+
+  switch (code)
+    {
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 0;
+
+    case PC:
+    case CC0:
+      return 1;
+
+    case MEM:
+      break;
+
+    case REG:
+      return reg_set_between_p (x, start, end);
+      
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e' && c4x_modified_between_p (XEXP (x, i), start, end))
+       return 1;
+
+      if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         if (c4x_modified_between_p (XVECEXP (x, i, j), start, end))
+           return 1;
+    }
+
+  return 0;
+}
+
+/* Return 1 if rtx X references memory that is changing.  */
+static int
+c4x_mem_ref_p (x)
+     rtx x;
+{
+  enum rtx_code code = GET_CODE (x);
+  char *fmt;
+  int i, j;
+
+  if (code == MEM && !RTX_UNCHANGING_P (x))
+    return 1;
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e' && c4x_mem_ref_p (XEXP (x, i)))
+       return 1;
+
+      if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         if (c4x_mem_ref_p (XVECEXP (x, i, j)))
+           return 1;
+    }
+
+  return 0;
+}
+
+/* Return 1 if rtx X sets or clobbers memory.  */
+static int
+c4x_mem_set_p (x)
+     rtx x;
+{
+  enum rtx_code code = GET_CODE (x);
+  char *fmt;
+  int i, j;
+
+  if ((code == SET || code == CLOBBER)
+      && (GET_CODE (SET_DEST (x)) == MEM))
+    return 1;
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e' && c4x_mem_set_p (XEXP (x, i)))
+       return 1;
+
+      if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         if (c4x_mem_set_p (XVECEXP (x, i, j)))
+           return 1;
+    }
+
+  return 0;
+}
+
+
+/* Return 1 if any insns between START and END (exclusive) sets
+   or clobbers memory.  */
+static int
+c4x_mem_modified_between_p (start, end)
+     rtx start, end;
+{
+  rtx insn;
+
+  if (start == end)
+    return 0;
+
+  for (insn = NEXT_INSN (start); insn != end; insn = NEXT_INSN (insn))
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+       && c4x_mem_set_p (PATTERN (insn)))
+      return 1;
+  return 0;
+}
+
+
+/* Returns 1 if INSN can be moved past all the insns between START and
+   END exclusive.  If TARGET_ALIASES is not set and a memory store is
+   detected, then 0 is returned.  */
+static int
+c4x_insn_moveable_p (insn, start, end)
+     rtx insn;
+     rtx start, end;
+{
+  if (start == end)
+    return 1;
+
+  /* We can't use modified_between_p since this will
+     return 1 if set1 contains a MEM.  */
+  if (c4x_modified_between_p (insn, start, end))
+    return 0;
+
+  return 1;
+}
+
+
+/* See if the insns INSN1 and INSN2 can be packed into a PARALLEL.
+   Return 0 if the insns cannot be packed or the rtx of the packed
+   insn (with clobbers added as necessary).  If DEPEND is non zero,
+   then the destination register of INSN1 must be used by INSN2.  */
+static rtx
+c4x_parallel_pack (insn1, insn2, depend)
+     rtx insn1;
+     rtx insn2;
+     int depend;
+{
+  rtx set1;
+  rtx set2;
+  rtx pack;
+  enum machine_mode mode1;
+  enum machine_mode mode2;
+  int num_clobbers;
+  int insn_code_number;
+
+  /* We could generalise things to not just rely on single sets.  */
+  if (!(set1 = single_set (insn1))
+      || !(set2 = single_set (insn2)))
+    return 0;
+
+  mode1 = GET_MODE (SET_DEST (set1));
+  mode2 = GET_MODE (SET_DEST (set2));
+  if (mode1 != mode2)
+    return 0;
+
+  if (depend)
+    {
+      rtx dst1;
+
+      /* Require insn2 to be dependent upon the result of insn1.  */
+      dst1 = SET_DEST (set1);
+      
+      if (!REG_P (dst1))
+       return 0;
+
+      if (!reg_mentioned_p (dst1, set2))
+       return 0;
+
+      /* The dependent register must die in insn2 since a parallel
+        insn will generate a new value.  */
+      if (!find_regno_note (insn2, REG_DEAD, REGNO (dst1)))
+       return 0;
+    }
+
+  pack = gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, set1, set2));
+  num_clobbers = 0;
+  if ((insn_code_number = recog (pack, pack, &num_clobbers)) < 0)
+    return 0;
+
+  if (num_clobbers != 0)
+    {
+      rtx newpack;
+      int i;
+
+      newpack = gen_rtx (PARALLEL, VOIDmode,
+                        gen_rtvec (GET_CODE (pack) == PARALLEL
+                                   ? XVECLEN (pack, 0) + num_clobbers
+                                   : num_clobbers + 1));
+
+      if (GET_CODE (pack) == PARALLEL)
+       for (i = 0; i < XVECLEN (pack, 0); i++)
+         XVECEXP (newpack, 0, i) = XVECEXP (pack, 0, i);
+      else
+       XVECEXP (newpack, 0, 0) = pack;
+
+      add_clobbers (newpack, insn_code_number);
+      pack = newpack;
+    }
+
+  return pack;
+}
+
+
+static rtx
+c4x_parallel_find (insn1, loop_end, depend, insn2)
+     rtx insn1;
+     rtx loop_end;
+     int depend;
+     rtx *insn2;
+{
+  rtx insn;
+  rtx pack;
+
+  /* We could use the logical links if depend is non zero?  */
+
+  for (insn = NEXT_INSN (insn1); insn != loop_end; insn = NEXT_INSN(insn))
+    {
+      switch (GET_CODE (insn))
+       {
+       default:
+       case JUMP_INSN:
+       case CALL_INSN:
+       case NOTE:
+         break;
+
+       case INSN:
+         if (!(pack = c4x_parallel_pack (insn1, insn, depend)))
+           break;
+
+         /* What if insn1 or insn2 sets cc and is required by another
+            insn?  */
+
+#if 0
+         /* Check that nothing between insn1 and insn will spoil the
+            show.  */
+         if (NEXT_INSN (insn1) != insn 
+             && c4x_modified_between_p (insn, NEXT_INSN (insn1), insn))
+           return 0;
+#else
+         /* This will do in the interim.  If the insns between
+            insn1 and insn are harmless, we can move things around
+            if we're careful.  */
+         if (next_nonnote_insn (insn1) != insn)
+           return 0;
+#endif
+         
+         /* Do some checks here... */
+         *insn2 = insn;
+         return pack;
+       }
+    }
+  return 0;
+}
+
+
+/* Update the register info for reg REG found in the basic block BB,
+   where SET is 1 if the register is being set.  */
+static void
+c4x_update_info_reg (reg, set, bb)
+     rtx reg;
+     int set;
+     int bb;
+{
+  int regno;
+
+  if (!REG_P (reg))
+    fatal_insn ("Expecting register rtx", reg);
+
+  regno = REGNO (reg);
+
+  /* REGNO_FIRST_UID and REGNO_LAST_UID don't need setting.  */
+
+  SET_REGNO_REG_SET (basic_block_live_at_start[bb], regno);
+  REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
+  if (set)
+    REG_N_SETS (regno)++;  
+  else
+    REG_N_REFS (regno)++;  
+}
+
+
+/* Update the register info for all the regs in X found in the basic
+   block BB.  */
+static void
+c4x_update_info_regs(x, bb)
+     rtx x;
+     int bb;
+{
+  enum rtx_code code;
+  char *fmt;
+  int i, j;
+
+  if (!x)
+    return;
+
+  code = GET_CODE (x);
+  switch (code)
+    {
+    case CLOBBER:
+#if 0
+      if (REG_P (SET_DEST (x)))
+       return;
+      break;
+#endif
+
+    case SET:
+      if (REG_P (SET_DEST (x)))
+       c4x_update_info_reg (SET_DEST (x), 1, bb);
+      else
+       c4x_update_info_regs (SET_DEST (x), bb);
+
+      if (code == SET)
+       c4x_update_info_regs (SET_SRC (x), bb);
+      return;
+
+    case REG:
+      c4x_update_info_reg (x, 0, bb);
+      return;
+
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       c4x_update_info_regs (XEXP (x, i), bb);
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         c4x_update_info_regs (XVECEXP (x, i, j), bb);
+    }
+}
+
+
+static void
+c4x_copy_insn_after(insn, prev, bb)
+     rtx insn;
+     rtx prev;
+     int bb;
+{
+  rtx note;
+  rtx new;
+
+  emit_insn_after (copy_rtx (PATTERN (insn)), prev);
+
+  new = NEXT_INSN (prev);
+
+  /* Copy the REG_NOTES from insn to the new insn.  */
+  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+    REG_NOTES (new) = gen_rtx (GET_CODE (note), 
+                                REG_NOTE_KIND (note),
+                                XEXP (note, 0),
+                                REG_NOTES (new));
+
+  /* Handle all the registers within insn and update the reg info.  */
+  c4x_update_info_regs (PATTERN (insn), bb);
+}
+
+
+static void
+c4x_copy_insns_after(start, end, pprev, bb)
+     rtx start;
+     rtx end;
+     rtx *pprev;
+     int bb;
+{
+  rtx insn;
+
+  for (insn = start; insn != NEXT_INSN (end); insn = NEXT_INSN(insn))
+    {
+      switch (GET_CODE (insn))
+       {
+       case CALL_INSN:
+         /* We could allow a libcall with no side effects??? */
+         fatal_insn("Repeat block loop contains a call", insn);
+         break;
+         
+       case INSN:
+         c4x_copy_insn_after(insn, *pprev, bb - 1);
+         *pprev = NEXT_INSN (*pprev);
+         break;
+
+       default:
+         break;
+       }
+    }
+}
+
+
+/* Merge the notes of insn2 with the notes of insn.  */
+static void
+c4x_merge_notes(insn, insn2)
+     rtx insn;
+     rtx insn2;
+{
+  rtx note;
+          
+  for (note = REG_NOTES (insn2); note; note = XEXP (note, 1))
+    {
+      rtx link;
+      
+      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+       if (REG_NOTE_KIND (note) == REG_NOTE_KIND (link)
+           && XEXP (note, 0) == XEXP (link, 0))
+         remove_note (insn, note);
+    }
+  for (note = REG_NOTES (insn2); note; note = XEXP (note, 1))
+    REG_NOTES (insn) = gen_rtx (GET_CODE (note), 
+                               REG_NOTE_KIND (note),
+                               XEXP (note, 0),
+                               REG_NOTES (insn));
+}
+
+
+/* This pass must update information that subsequent passes expect to be
+   correct.  Namely: reg_n_refs, reg_n_sets, reg_n_deaths,
+   reg_n_calls_crossed, and reg_live_length.  Also, basic_block_head,
+   basic_block_end.   */
+
+static int
+c4x_parallel_process (loop_start, loop_end)
+     rtx loop_start;
+     rtx loop_end;
+{
+  rtx insn;
+  rtx insn2;
+  rtx pack;
+  rtx hoist;
+  rtx sink;
+  rtx loop_count;
+  rtx loop_count_set;
+  rtx end_label;
+  int num_packs;
+  int bb;
+
+  /* The loop must have a calculable number of iterations
+     since we need to reduce the loop count by one.  
+
+     For now, only process repeat block loops, since we can tell that
+     these have a calculable number of iterations. 
+
+     The loop count must be at least 2?  */
+
+  loop_count = NEXT_INSN (loop_start);
+
+  /* Skip past CLOBBER and USE and deleted insn. This is from flow. */
+  for (;;)
+    {
+      if (GET_CODE (loop_count) == INSN)
+       {
+          rtx x = PATTERN (loop_count);
+          if (GET_CODE (x) != USE && GET_CODE (x) != CLOBBER)
+           break;
+       }
+      else if (GET_CODE (loop_count) == NOTE)
+       {
+         if (! INSN_DELETED_P (loop_count))
+           break;
+       }
+      else
+       break;
+      loop_count = NEXT_INSN (loop_count);
+    }
+  
+  if (!(loop_count_set = single_set (loop_count)))
+    return 0;
+  
+  if (!REG_P (SET_DEST (loop_count_set)) 
+      || REGNO (SET_DEST (loop_count_set)) != RC_REGNO)
+    return 0;
+
+  /* Determine places to hoist and sink insns out of the loop.  We
+     won't have to update basic_block_head if we move things after
+     loop_count. */
+  
+  hoist = loop_count;
+  end_label = PREV_INSN (loop_end);
+
+  /* Skip past filler insn if present.  */
+  if (GET_CODE (end_label) != CODE_LABEL)
+    end_label = PREV_INSN (end_label);
+
+  /* Skip past CLOBBER, USE, and deleted insns inserted by the flow pass. */
+  for (;;)
+    {
+      if (GET_CODE (end_label) == INSN)
+       {
+          rtx x = PATTERN (end_label);
+          if (GET_CODE (x) != USE && GET_CODE (x) != CLOBBER)
+           break;
+       }
+      else if (GET_CODE (end_label) == NOTE)
+       {
+         if (! INSN_DELETED_P (end_label))
+           break;
+       }
+      else
+       break;
+      end_label = PREV_INSN (end_label);
+    }
+
+  if (GET_CODE (end_label) != CODE_LABEL)
+    return 0;
+
+  sink = end_label;
+
+  /* There must be an easier way to work out which basic block we are
+     in.  */
+  for (bb = 0; bb < n_basic_blocks; bb++)
+    if (basic_block_head[bb] == sink)
+      break;
+
+  if (bb >= n_basic_blocks)
+    fatal_insn("Cannot find basic block for insn", sink);
+
+  /* Skip to label at top of loop.  */
+  for (; GET_CODE (loop_start) != CODE_LABEL;
+       loop_start = NEXT_INSN(loop_start));
+  
+  num_packs = 0;
+  for (insn = loop_start; insn != loop_end; insn = NEXT_INSN(insn))
+    {
+      switch (GET_CODE (insn))
+       {
+       default:
+       case JUMP_INSN:
+       case CALL_INSN:
+       case NOTE:
+         break;
+
+       case INSN:
+
+         /* Look for potential insns to combine where the second one
+            is dependent upon the first.  We could have another pass
+            that tries combining independent insns but that is not so
+            important.  We could do this afterwards as a more generic
+            peepholer.  */
+            
+         if ((pack = c4x_parallel_find(insn, loop_end, 1, &insn2)))
+           {
+             rtx set1;
+             rtx set2;
+             rtx note;
+             rtx seq_start;
+
+             set1 = single_set (insn);
+             set2 = single_set (insn2);
+
+             /* We need to hoist a copy of insn1 out of the loop and
+                to sink a copy insn2 out of the loop.  We can avoid
+                the latter if the destination of insn2 is used
+                by a following insn within the loop.
+                
+                We cannot hoist insn1 out of the loop if any of the
+                preceeding insns within the loop modifies the destination
+                of insn1 or modifies any of the operands of insn1.  */
+
+             /* If the user has flagged that there are potential aliases,
+                then we can't move the insn if it references memory
+                past any insns that modify memory.  */
+             if (TARGET_ALIASES 
+                 && c4x_mem_ref_p (PATTERN (insn))
+                 && c4x_mem_modified_between_p (loop_start, loop_end))
+               break;
+
+             /* None of the registers used in insn can be modified by
+                any of the insns from the start of the loop until insn.  */
+             if (!c4x_insn_moveable_p (set1, loop_start, insn))
+               break;
+
+             /* None of the registers used in insn can be modified by
+                any of the insns after insn2 until the end of the
+                loop, especially the result which needs to be saved
+                for the next iteration. */
+             if (!c4x_insn_moveable_p (set1, insn2, loop_end))
+               break;
+
+             /* We need to hoist all the insns from the loop top
+                to and including insn.  */
+             c4x_copy_insns_after(NEXT_INSN (loop_start), insn, &hoist, bb);
+
+             /* We need to sink all the insns after insn to 
+                loop_end.  */
+             c4x_copy_insns_after (NEXT_INSN (insn), PREV_INSN(end_label),
+                                   &sink, bb + 1);
+
+             /* Change insn to the new parallel insn, retaining the notes
+                of the old insn.  */
+             if (!validate_change (insn, &PATTERN (insn), pack, 0))
+               fatal_insn("Cannot replace insn with parallel insn", pack);
+
+             /* Copy the REG_NOTES from insn2 to the new insn
+                avoiding duplicates.  */
+             c4x_merge_notes (insn, insn2);
+
+             delete_insn (insn2);
+             
+             /* The destination register of insn1 no longer dies in
+             this composite insn.  Don't use remove_death since that
+             alters REG_N_DEATHS.  The REG_DEAD note has just been
+             moved.  */
+             note = find_regno_note (insn, REG_DEAD, REGNO (SET_DEST (set1)));
+             if (note)
+               remove_note (insn, note);
+
+             /* Do we have to modify the LOG_LINKS?  */
+
+             /* We need to decrement the loop count.  We probably
+                should test if RC is negative and branch to end label
+                if so.  */
+             if (GET_CODE (SET_SRC (loop_count_set)) == CONST_INT)
+               {
+                 /* The loop count must be more than 1 surely?  */
+                 SET_SRC (loop_count_set) 
+                   = gen_rtx (CONST_INT, VOIDmode,
+                              INTVAL (SET_SRC (loop_count_set)) -1);
+               }
+             else if (GET_CODE (SET_SRC (loop_count_set)) == PLUS
+                      && GET_CODE (XEXP (SET_SRC (loop_count_set), 1))
+                      == CONST_INT)
+               {
+                 XEXP (SET_SRC (loop_count_set), 1)
+                   = gen_rtx (CONST_INT, VOIDmode,
+                              INTVAL (XEXP (SET_SRC (loop_count_set), 1))
+                              - 1);
+               }
+             else
+               {
+                 start_sequence ();
+                 expand_binop (QImode, sub_optab,
+                               gen_rtx (REG, QImode, RC_REGNO),
+                               gen_rtx (CONST_INT, VOIDmode, 1),
+                               gen_rtx (REG, QImode, RC_REGNO),
+                               1, OPTAB_DIRECT);
+                 seq_start = get_insns ();
+                 end_sequence ();
+                 emit_insns_after (seq_start, loop_count);
+
+                 /* Check this.  What if we emit more than one insn?
+                    Can we emit more than one insn? */
+                 REG_NOTES (seq_start)
+                   = gen_rtx (EXPR_LIST, REG_UNUSED,
+                              gen_rtx (REG, QImode, RC_REGNO),
+                              REG_NOTES (seq_start));
+               }
+
+             start_sequence ();
+             emit_cmp_insn (gen_rtx (REG, QImode, RC_REGNO),
+                            const0_rtx, LT, NULL_RTX, QImode, 0, 0);
+             emit_jump_insn (gen_blt (end_label));
+             seq_start = get_insns ();
+             end_sequence ();
+             emit_insns_after (seq_start, hoist);
+             
+             /* This is a bit of a hack... */
+             REG_NOTES (NEXT_INSN (seq_start))
+               = gen_rtx (EXPR_LIST, REG_DEAD,
+                          gen_rtx (REG, QImode, RC_REGNO),
+                          REG_NOTES (NEXT_INSN (seq_start)));
+
+             if (TARGET_DEVEL)
+               debug_rtx(insn);
+
+             num_packs ++;
+             
+#if 1
+             /* If we want to pack more than one parallel insn
+                we will have to tag which insns have been
+                hoisted/sunk/paired.  We might need a recursive approach. */
+             
+             return num_packs;
+#endif
+           }
+         break;
+       }
+    }
+  return num_packs;
+}
+
+
+static void
+c4x_combine_parallel_independent (insns)
+     rtx insns;
+{
+  /* Combine independent insns like
+     (set (mem (reg 0)) (reg 1))
+     (set (reg 2) (mem (reg 3)))
+     where (reg 1) != (reg 2) unless there is a REG_DEAD note
+     on the first insn. */
+
+}
+
+static void
+c4x_combine_parallel_dependent (insns)
+     rtx insns;
+{
+  rtx insn;
+  rtx loop_start;
+  rtx loop_end;
+  int num_jumps;
+  int num_insns;
+
+   /* Find the innermost loop and check that it is unjumped.  */
+  loop_start = NULL_RTX;
+  num_jumps = 0;
+  for (insn = insns; insn; insn = NEXT_INSN(insn))
+    {
+      switch (GET_CODE (insn))
+       {
+       case INSN:
+         num_insns++;
+         break;
+
+       case CALL_INSN:
+         /* We could allow a libcall with no side effects??? */
+       case JUMP_INSN:
+         num_jumps++;
+         break;
+
+       case NOTE:
+         switch (NOTE_LINE_NUMBER (insn))
+           {
+           case NOTE_INSN_LOOP_BEG:
+             loop_start = insn;
+             num_jumps = 0;
+             num_insns = 0;
+             break;
+
+           case NOTE_INSN_LOOP_CONT:
+             if (!loop_start)
+               break;
+             /* We can't handle a loop with jumps or calls.
+                If there are too many insns, we are unlikely
+                to be able to find a suitable case for optimisation.
+                The maximum number of insns may require tweaking.  */
+             if (!num_jumps && num_insns < 20)
+               {
+                 /* Skip to end of loop.  */
+                 loop_end = NULL_RTX;
+                 for (; insn; insn = NEXT_INSN(insn))
+                   if (GET_CODE (insn) == NOTE
+                       && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+                     break;
+                 loop_end = insn;
+                 if (!loop_end)
+                   fatal_insn("Could not find note at end of loop", 
+                              loop_start);
+                 c4x_parallel_process(loop_start, loop_end);
+               }
+             loop_start = NULL_RTX;
+             break;
+
+           default:
+             break;
+           }
+       default:
+         break;
+       }
+    }
+}
+
+
+void
+c4x_combine_parallel (insns)
+     rtx insns;
+{
+ /* Only let people who know how to shoot themselves in the foot do so!  */
+  if (!TARGET_PARALLEL_PACK)
+    return;
+  
+  c4x_combine_parallel_dependent (insns);
+
+  c4x_combine_parallel_independent (insns);
+}
+
+
+/* True if INSN is between START and END.  If END precedes START
+   something has gone awry.  */
+
+static int
+c4x_rptb_in_range (insn, start, end)
+     rtx insn, start, end;
+{
+  rtx this;
+  
+  for (this = start; ; this = NEXT_INSN (this))
+    {
+      if (this == insn)
+       return 1;
+      if (this == end)
+       return 0;
+      if (this == NULL_RTX)
+       fatal_insn ("c4x_rptb_in_range: Repeat block error", start);
+    }
+}
+
+
+/* Returns true if there are no jumps crossing the loop boundary and
+   no calls anywhere.  */  
+
+int
+c4x_rptb_unjumped_loop_p (loop_start, loop_end)
+     rtx loop_start, loop_end;
+{
+  rtx insn;
+  rtx continue_label = NULL_RTX;
+  rtx continue_note = NULL_RTX;        /* Loop continue note if there is one.  */
+
+  /* Scan loop backwards.  */
+  for (insn = PREV_INSN (loop_end); insn && insn != loop_start;
+       insn = PREV_INSN (insn))
+    {
+      switch (GET_CODE (insn))
+       {
+       case JUMP_INSN:
+         {
+           rtx jump_label = JUMP_LABEL (insn);
+
+           /* We don't like jumps out of the loop.  We also look
+              for jumps to the end of loop, say from a continue
+              statement.  */
+           if (continue_note
+               && jump_label == next_nonnote_insn (continue_note))
+             continue_label = jump_label;
+           else if (!c4x_rptb_in_range (jump_label, loop_start, 
+                                        continue_note ? continue_note :
+                                        loop_end))
+             return 0;
+         }
+         /* Fall through  */
+         
+       case INSN:
+         if (0 && volatile_refs_p (PATTERN (insn)))
+           {
+             c4x_dump (loop_dump_stream, 
+                       "Repeat block: Volatile memory ref within loop\n");
+             return 0;
+           }
+
+         /* The C4x movstrqi_large pattern clobbers RC, RE, RS.
+            This should be generalised to check for insns that use
+            these registers within the loop.  */
+         if (recog_memoized (insn) == CODE_FOR_movstrqi_large)
+           {
+             c4x_dump (loop_dump_stream, 
+                       "Repeat block: Memory copy within loop\n");
+             return 0;
+           }
+         break;
+         
+         /* It is not worthwhile preserving the zero overhead loop
+            context across calls.  */
+       case CALL_INSN:
+         /* We could allow a libcall with no side effects??? */
+         c4x_dump (loop_dump_stream, "Repeat block: Call within loop\n");
+         return 0;
+         
+       case NOTE:
+         switch (NOTE_LINE_NUMBER (insn))
+           {
+           case NOTE_INSN_LOOP_CONT:
+             if (continue_note == NULL_RTX)
+               continue_note = insn;
+
+             /* Check for empty loop which would throw c4x_rptb_nop_p.
+                GCC doesn't optimise empty loops away since user
+                may be trying to implement a simple but crude delay.  */
+             if (GET_CODE (PREV_INSN (insn)) == NOTE 
+                 && NOTE_LINE_NUMBER (PREV_INSN (insn)) == NOTE_INSN_LOOP_BEG)
+               {
+                 c4x_dump (loop_dump_stream, "Repeat block: Empty loop\n");
+                 return 0;
+               }
+             break;
+
+             /* If we find a LOOP_END note, then we are not in the
+                innermost loop.  */
+           case NOTE_INSN_LOOP_END:
+             return 0;
+
+           default:
+             continue;
+           }
+       default:
+         continue;
+       }
+    }
+  if (insn == NULL_RTX)
+    fatal("Repeat block: Inconsistent loop");
+
+  c4x_dump (loop_dump_stream, "Repeat block: Unjumped loop\n");
+  if (continue_label)
+    c4x_dump (loop_dump_stream, "Repeat block: Continue_label %d\n",
+             INSN_UID (continue_label));
+  return 1;
+}
+
+
+/* Find and record in PCOMP and PJUMP the final comparison and jump
+   insns of the loop specified by LOOP_END.  Return 1 if both have been
+   found, otherwise return 0.  */
+
+static int
+c4x_rptb_find_comp_and_jump (loop_end, pcomp, pjump)
+     rtx loop_end;
+     rtx *pcomp, *pjump;
+{
+  rtx final_comp, comp_pat;
+  rtx final_jump = prev_nonnote_insn (loop_end);
+
+  if (!final_jump)
+    return 0;
+
+  final_comp = PREV_INSN (final_jump);
+  if (!final_comp)
+    return 0;
+
+  if ((GET_CODE (final_comp) != INSN))
+    return 0;
+
+  comp_pat = PATTERN (final_comp);
+
+  if ((GET_CODE (comp_pat) != SET)
+      || GET_CODE (XEXP (comp_pat, 0)) != REG
+      || REGNO (XEXP (comp_pat, 0)) != ST_REGNO)
+    return 0;
+
+  *pcomp = final_comp;
+  *pjump = final_jump;
+  return 1;
+}
+
+
+/* Determine if the loop count is computable for a repeat loop.  */
+
+static int
+c4x_rptb_loop_info_get (loop_start, loop_end, loop_info)
+     rtx loop_start, loop_end;
+     c4x_rptb_info_t *loop_info;
+{
+  rtx iteration_var, initial_value, increment, comparison;
+  enum rtx_code cc;            /* Comparison code */
+  rtx comparison_value;
+
+  loop_info->loop_start = loop_start;
+  loop_info->loop_count = loop_iterations (loop_start, loop_end);
+
+  /* If the number of loop cycles does not need calculating at
+     run-time then things are easy... Note that the repeat count
+     value must be a positive integer for the RPTB instruction.  If
+     loop_count is zero then we don't have a constant count.  */
+  if (loop_info->loop_count > 0)
+    return 1;
+  if (loop_info->loop_count < 0)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Negative loop count %d\n",
+               loop_info->loop_count);
+      return 0;
+    }
+
+  comparison = get_condition_for_loop (prev_nonnote_insn (loop_end));
+  if (comparison == NULL_RTX)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Cannot find comparison\n");
+      return 0;
+    }
+  cc = GET_CODE (comparison);
+
+  /* Only allow a register as the iteration value.  */
+  iteration_var = XEXP (comparison, 0);
+  if (GET_CODE (iteration_var) != REG)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Non reg. iteration value\n");
+      return 0;
+    }
+
+  c4x_dump (loop_dump_stream, "Repeat block: Iteration value regno = %d\n",
+           REGNO (iteration_var));
+
+  /* The comparison value must not change on the fly.  */
+  comparison_value = XEXP (comparison, 1);
+  if (!invariant_p (comparison_value))
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Comparison value variant\n");
+      return 0;
+    }
+
+  /* This routine in unroll.c does the hard work of finding the
+     initial value and increment for us.  Currently it won't find the
+     intitial value or increment for do {} while; or while() {} do;
+     loops.  This is because the iteration_var we find in the
+     comparison insn is a GIV rather than a BIV and iteration_info does
+     not like GIVs.  We could scan all the BIVs like check_dbra_loop()
+     does...  */
+
+  iteration_info (iteration_var, &initial_value, &increment,
+                 loop_start, loop_end);
+  if (initial_value == NULL_RTX || increment == NULL_RTX)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Cannot determine initial"
+               " value or increment\n");
+      return 0;
+    }
+
+  /* Only allow constant integer increment, not a variable.  */
+  if (GET_CODE (increment) != CONST_INT)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Increment not constant\n");
+      return 0;
+    }
+
+  loop_info->incr = INTVAL (increment);
+
+  /* If the increment is not a power of 2, (i.e, 1, 2, 4, etc.) then
+     we will need to emit a divide instruction rather than a right
+     shift to calculate the loop count.  */
+  if ((loop_info->shift = exact_log2 (abs (loop_info->incr))) < 0)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Increment not power of 2\n");
+      return 0;
+    }
+
+  /* The front end changes GT to NE for unsigned numbers, so we
+     "undo" this here for clarity.  */
+  loop_info->unsigned_p = 0;
+  if (GET_CODE (increment) == CONST_INT
+      && INTVAL (increment) == -1 && cc == NE)
+    {
+      loop_info->unsigned_p = 1;
+      cc = GT;
+    }
+
+  if (!(cc == LT || cc == LE || cc == LTU || cc == LEU
+       || cc == GT || cc == GE || cc == GTU || cc == GEU))
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Invalid comparison\n");
+      return 0;
+    }
+
+  loop_info->swap_p = (cc == GT || cc == GE || cc == GTU || cc == GEU);
+  if (loop_info->swap_p)
+    {
+      loop_info->start_value = comparison_value;
+      loop_info->end_value = initial_value;
+      loop_info->incr = -loop_info->incr;
+    }
+  else
+    {
+      loop_info->start_value = initial_value;
+      loop_info->end_value = comparison_value;
+    }
+
+  /* Check if loop won't terminate?  */
+  if (loop_info->incr <= 0)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Increment negative\n");
+      return 0;
+    }
+
+  loop_info->off_by_one = (cc == LT || cc == LTU || cc == GT || cc == GTU);
+  loop_info->unsigned_p |= (cc == LTU || cc == LEU || cc == GTU || cc == GEU);
+
+  /* We have a switch to allow an unsigned loop counter.
+     We'll normally disallow this case since the the repeat
+     count for the RPTB instruction must be less than 0x80000000.  */
+  if (loop_info->unsigned_p && !TARGET_LOOP_UNSIGNED)
+    {
+      c4x_dump (loop_dump_stream, "Repeat block: Unsigned comparison\n");
+      return 0;
+    }
+
+  return 1;
+}
+
+
+/* Emit insn(s) to compute loop iteration count.  */
+
+static rtx
+c4x_rptb_emit_init (loop_info)
+     c4x_rptb_info_t *loop_info;
+{
+  rtx result;
+  int adjust;
+  rtx seq_start;
+
+  /* If have a known constant loop count, things are easy...  */
+  if (loop_info->loop_count > 0)
+    return gen_rtx (CONST_INT, VOIDmode, loop_info->loop_count - 1);
+
+  if (loop_info->shift < 0)
+    abort ();
+
+  start_sequence ();
+
+  result = loop_info->end_value;
+  if (loop_info->start_value != const0_rtx)
+    {
+      /* end_value - start_value */
+      result = expand_binop (QImode, sub_optab,
+                            result, loop_info->start_value,
+                            0, loop_info->unsigned_p, OPTAB_DIRECT);
+    }
+
+  adjust = loop_info->incr - loop_info->off_by_one;
+  if (adjust > 0)
+    {
+      /* end_value - start_value + adjust */
+      result = expand_binop (QImode, add_optab,
+                            result, GEN_INT (adjust),
+                            0, loop_info->unsigned_p, OPTAB_DIRECT);
+    }
+
+  if (loop_info->shift > 0)
+    {
+      /* (end_value - start_value + adjust) >> shift */
+      result = expand_binop (QImode, loop_info->unsigned_p ?
+                            lshr_optab : ashr_optab, result,
+                            gen_rtx (CONST_INT, VOIDmode,
+                                     loop_info->shift),
+                            0, loop_info->unsigned_p, OPTAB_DIRECT);
+    }
+
+  /* ((end_value - start_value + adjust) >> shift) - 1 */
+  result = expand_binop (QImode, sub_optab,
+                        result, gen_rtx (CONST_INT, VOIDmode, 1),
+                        0, loop_info->unsigned_p, OPTAB_DIRECT);
+
+  seq_start = get_insns ();
+  end_sequence ();
+
+  emit_insns_before (seq_start, loop_info->loop_start);
+  return result;
+}
+
+
+/* This routine checks for suitable loops that can use zero overhead
+   looping and emits insns marking the start and end of the loop
+   as well as an insn for initialising the loop counter.  */
+
+void
+c4x_rptb_process (loop_start, loop_end)
+     rtx loop_start, loop_end;
+{
+  rtx iteration_count;
+  rtx start_label;
+  rtx end_label;
+  rtx comp_insn;
+  rtx jump_insn;
+  c4x_rptb_info_t info;
+
+  if (!TARGET_RPTB)
+    return;
+
+  /* Check that there are no jumps crossing loop boundary or calls.  */
+  if (!c4x_rptb_unjumped_loop_p (loop_start, loop_end))
+    return;
+
+  start_label = next_nonnote_insn (loop_start);
+  if (GET_CODE (start_label) != CODE_LABEL)
+    return;
+
+  /* Find comparison and jump insns.  */
+  if (!c4x_rptb_find_comp_and_jump (loop_end, &comp_insn, &jump_insn))
+    return;
+
+  /* If we don't jump back to start label, then the loop is no good.  */
+  if (start_label != JUMP_LABEL (jump_insn))
+    return;
+
+  /* Check that number of loops is computable.  */
+  if (!c4x_rptb_loop_info_get (loop_start, loop_end, &info))
+    return;
+
+  c4x_dump (loop_dump_stream, "Repeat block: Loop start at %d, end at %d\n",
+           INSN_UID (loop_start), INSN_UID (loop_end));
+
+  if (info.loop_count > 0)
+    c4x_dump (loop_dump_stream, "Repeat block: Loop count = %d\n",
+             info.loop_count);
+  else
+    c4x_dump (loop_dump_stream,
+             "Repeat block: incr %d, shift %d, swap_p %d,"
+             " off_by_one %d, unsigned_p %d\n",
+             info.incr, info.shift, info.swap_p,
+             info.off_by_one, info.unsigned_p);
+
+  /* Emit insns to compute loop iteration count.  */
+  iteration_count = c4x_rptb_emit_init (&info);
+  if (iteration_count == NULL_RTX)
+    abort ();
+
+  /* Add label at end of loop, immediately after jump insn.  */
+  end_label = gen_label_rtx ();
+  emit_label_after (end_label, jump_insn);
+
+  /* Add label to forced label list to prevent jump optimisation
+     coalescing end_label with bypass_label since we need these destinct if
+     we are to sink insns out of the loop. */
+  if (GET_CODE (NEXT_INSN (loop_end)) == CODE_LABEL)
+    {
+      rtx bypass_label;
+
+      bypass_label = NEXT_INSN (loop_end);
+#if 0
+      forced_labels = gen_rtx (EXPR_LIST, VOIDmode,
+                              end_label, forced_labels);
+      forced_labels = gen_rtx (EXPR_LIST, VOIDmode,
+                              bypass_label, forced_labels);
+#endif
+      emit_insn_after (gen_repeat_block_filler (), end_label);
+      
+      c4x_dump (loop_dump_stream,
+               "Repeat block: Start label at %d, end label at %d,"
+               " bypass label at %d\n",
+               INSN_UID (start_label), INSN_UID (end_label),
+               INSN_UID (bypass_label));
+    }
+  else
+    {
+      emit_insn_after (gen_repeat_block_filler (), end_label);
+      c4x_dump (loop_dump_stream,
+               "Repeat block: Start label at %d, end label at %d\n",
+               INSN_UID (start_label), INSN_UID (end_label));
+    }
+  
+  /* Create pattern for repeat_block_top and insert at top of loop.  */
+  emit_insn_before (gen_repeat_block_top (const0_rtx, iteration_count,
+                                         start_label, end_label),
+                   start_label);
+  
+  /* Replace the jump instruction with repeat_block_end insn.  */
+  PATTERN (jump_insn) = gen_repeat_block_end (const0_rtx, start_label);
+
+  /* The insn is unrecognizable after the surgery.  */
+  INSN_CODE (jump_insn) = -1;
+  
+  /* Delete the comparison insn.  */
+  delete_insn (comp_insn);
+}
+
+
+int
+c4x_rptb_rpts_p (insn, op)
+     rtx insn, op;
+{
+  /* The next insn should be our label marking where the
+     repeat block starts.  */
+  insn = NEXT_INSN (insn);
+  if (GET_CODE (insn) != CODE_LABEL)
+    {
+      /* Some insns may have been shifted between the RPTB insn
+         and the top label... They were probably destined to
+         be moved out of the loop.  For now, let's leave them
+         where they are and print a warning.  We should
+         probably move these insns before the repeat block insn.  */
+      if (TARGET_DEBUG)
+       fatal_insn("c4x_rptb_rpts_p: Repeat block top label moved\n",
+                  insn);
+      return 0;
+    }
+
+  /* Skip any notes.  */
+  insn = next_nonnote_insn (insn);
+
+  /* This should be our first insn in the loop.  */
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+    return 0;
+
+  /* Skip any notes.  */
+  insn = next_nonnote_insn (insn);
+
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+    return 0;
+
+  if (recog_memoized (insn) != CODE_FOR_repeat_block_end)
+    return 0;
+
+  if (TARGET_RPTS)
+    return 1;
+
+  return (GET_CODE (op) == CONST_INT) && TARGET_RPTS_CYCLES (INTVAL (op));
+}
+
+/*
+   Loop structure of `for' loops:
+
+   Check if iterations required
+   If not, jump to BYPASS_LABEL
+
+   NOTE_INSN_LOOP_BEG
+   <<<Repeat block top goes here>>
+   START_LABEL:
+   {NOTE_BLOCK_BEGIN}
+
+   Body of loop
+
+   {NOTE_BLOCK_END}
+   {NOTE_INSN_LOOP_CONT}
+
+   Increment loop counters here
+
+   {NOTE_INSN_LOOP_VTOP}
+   <<<Repeat block nop goes here if nec.>>>
+   Exit test here                       <<<This gets deleted>>>
+   If not exiting jump to START_LABEL   <<<Repeat block end goes here>>>
+   <<<END_LABEL goes here>>
+
+   NOTE_INSN_LOOP_END
+
+   BYPASS_LABEL:
+
+   Note that NOTE_INSN_LOOP_VTOP is only required for loops such as
+   for loops, where it necessary to duplicate the exit test.  This
+   position becomes another virtual start of the loop when considering
+   invariants.
+
+   Note that if there is nothing in the loop body we get:
+
+   NOTE_INSN_LOOP_BEG
+   NOTE_INSN_LOOP_CONT
+   START_LABEL:
+   NOTE_INSN_LOOP_VTOP
+   ...
+ */
+
+
+/* Adjust the cost of a scheduling dependency.  Return the new cost of
+   a dependency LINK or INSN on DEP_INSN.  COST is the current cost. 
+   A set of an address register followed by a use occurs a 2 cycle
+   stall (reduced to a single cycle on the c40 using LDA), while
+   a read of an address register followed by a use occurs a single cycle.  */
+#define        SET_USE_COST    3
+#define        SETLDA_USE_COST 2
+#define        READ_USE_COST   2
+
+int
+c4x_adjust_cost (insn, link, dep_insn, cost)
+     rtx insn;
+     rtx link;
+     rtx dep_insn;
+     int cost;
+{
+  /* Don't worry about this until we know what registers have been
+     assigned.  */
+  if (!reload_completed)
+    return 0;
+
+  /* How do we handle dependencies where a read followed by another
+     read causes a pipeline stall?  For example, a read of ar0 followed
+     by the use of ar0 for a memory reference.  It looks like we
+     need to extend the scheduler to handle this case.  */
+
+  /* Reload sometimes generates a CLOBBER of a stack slot, e.g.,
+     (clobber (mem:QI (plus:QI (reg:QI 11 ar3) (const_int 261)))),
+     so only deal with insns we know about.  */
+  if (recog_memoized (dep_insn) < 0)
+    return 0;
+
+  if (REG_NOTE_KIND (link) == 0)
+    {
+      int max = 0;
+
+      /* Data dependency; DEP_INSN writes a register that INSN reads some
+        cycles later.  */
+
+      if (TARGET_C3X)
+       {
+         if (get_attr_setgroup1 (dep_insn) && get_attr_usegroup1 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_readarx (dep_insn) && get_attr_usegroup1 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+       }
+      else
+       {
+         /* This could be significantly optimized. We should look
+            to see if dep_insn sets ar0-ar7 or ir0-ir1 and if
+            insn uses ar0-ar7.  We then test if the same register
+            is used.  The tricky bit is that some operands will
+            use several registers...  */
+
+         if (get_attr_setar0 (dep_insn) && get_attr_usear0 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar0 (dep_insn) && get_attr_usear0 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar0 (dep_insn) && get_attr_usear0 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setar1 (dep_insn) && get_attr_usear1 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar1 (dep_insn) && get_attr_usear1 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar1 (dep_insn) && get_attr_usear1 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setar2 (dep_insn) && get_attr_usear2 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar2 (dep_insn) && get_attr_usear2 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar2 (dep_insn) && get_attr_usear2 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setar3 (dep_insn) && get_attr_usear3 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar3 (dep_insn) && get_attr_usear3 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar3 (dep_insn) && get_attr_usear3 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setar4 (dep_insn) && get_attr_usear4 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar4 (dep_insn) && get_attr_usear4 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar4 (dep_insn) && get_attr_usear4 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setar5 (dep_insn) && get_attr_usear5 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar5 (dep_insn) && get_attr_usear5 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar5 (dep_insn) && get_attr_usear5 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setar6 (dep_insn) && get_attr_usear6 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar6 (dep_insn) && get_attr_usear6 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar6 (dep_insn) && get_attr_usear6 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setar7 (dep_insn) && get_attr_usear7 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ar7 (dep_insn) && get_attr_usear7 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+         if (get_attr_readar7 (dep_insn) && get_attr_usear7 (insn))
+           max = READ_USE_COST > max ? READ_USE_COST : max;
+
+         if (get_attr_setir0 (dep_insn) && get_attr_useir0 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ir0 (dep_insn) && get_attr_useir0 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+
+         if (get_attr_setir1 (dep_insn) && get_attr_useir1 (insn))
+           max = SET_USE_COST > max ? SET_USE_COST : max;
+         if (get_attr_setlda_ir1 (dep_insn) && get_attr_useir1 (insn))
+           max = SETLDA_USE_COST > max ? SETLDA_USE_COST : max;
+       }
+
+      if (max)
+       cost = max;
+
+      /* For other data dependencies, the default cost specified in the
+        md is correct.  */
+      return cost;
+    }
+  else if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
+    {
+      /* Anti dependency; DEP_INSN reads a register that INSN writes some
+        cycles later.  */
+
+      /* For c4x anti dependencies, the cost is 0.  */
+      return 0;
+    }
+  else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
+    {
+      /* Output dependency; DEP_INSN writes a register that INSN writes some
+        cycles later.  */
+
+      /* For c4x output dependencies, the cost is 0.  */
+      return 0;
+    }
+  else
+    abort ();
+}
diff --git a/gcc/config/c4x/c4x.h b/gcc/config/c4x/c4x.h
new file mode 100644 (file)
index 0000000..cc92b2a
--- /dev/null
@@ -0,0 +1,2608 @@
+/* Definitions of target machine for GNU compiler.  TMS320C[34]x
+   Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+
+   Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz)
+              and Herman Ten Brugge (Haj.Ten.Brugge@net.HCC.nl).
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Set the following so that some of the macros expand to function
+   calls to simplify debugging.  */
+#define C4X_DEBUG 1
+
+/* RUN-TIME TARGET SPECIFICATION */
+
+#define C4x   1
+
+/* Name of the c4x assembler */
+
+#define ASM_PROG "c4x-as"
+
+/* Name of the c4x linker */
+
+#define LD_PROG "c4x-ld"
+
+/* Define assembler options */
+
+#define ASM_SPEC "\
+%{!mcpu=30:%{!mcpu=31:%{!mcpu=32:%{!mcpu=40:%{!mcpu=44:\
+%{!m30:%{!m40:-m40}}}}}}} \
+%{mcpu=30:-m30} \
+%{mcpu=31:-m31} \
+%{mcpu=32:-m32} \
+%{mcpu=40:-m40} \
+%{mcpu=44:-m44} \
+%{m30:-m30} \
+%{m31:-m31} \
+%{m32:-m32} \
+%{m40:-m40} \
+%{m44:-m44} \
+%{mmemparm:-p} %{mregparm:-r} \
+%{!mmemparm:%{!mregparm:-r}} \
+%{mbig:-b} %{msmall:-s} \
+%{!msmall:%{!mbig:-b}}"
+
+/* Define linker options */
+
+#define LINK_SPEC "\
+%{m30:--architecture c3x} \
+%{m31:--architecture c3x} \
+%{m32:--architecture c3x} \
+%{mcpu=30:--architecture c3x} \
+%{mcpu=31:--architecture c3x} \
+%{mcpu=32:--architecture c3x}"
+
+/* Define C preprocessor options. */
+
+#define CPP_SPEC "\
+%{!m30:%{!m31:%{!m32:%{!mcpu=30:%{!mcpu=31:%{!mcpu=32:%{!mcpu=40:%{!mcpu=44:\
+  %{!m40:%{!m44:-D_TMS320C4x -D_C4x -D_TMS320C40 -D_C40 }}}}}}}}}} \
+%{mcpu=30:-D_TMS320C3x -D_C3x -D_TMS320C30 -D_C30 } \
+%{m30:-D_TMS320C3x -D_C3x -D_TMS320C30 -D_C30 } \
+%{mcpu=31:-D_TMS320C3x -D_C3x -D_TMS320C31 -D_C31 } \
+%{m31:-D_TMS320C3x -D_C3x -D_TMS320C31 -D_C31 } \
+%{mcpu=32:-D_TMS320C3x -D_C3x -D_TMS320C32 -D_C32 } \
+%{m32:-D_TMS320C3x -D_C3x -D_TMS320C32 -D_C32 } \
+%{mcpu=40:-D_TMS320C4x -D_C4x -D_TMS320C40 -D_C40 } \
+%{m40:-D_TMS320C4x -D_C4x -D_TMS320C40 -D_C40 } \
+%{mcpu=44:-D_TMS320C4x -D_C4x -D_TMS320C44 -D_C44 } \
+%{m44:-D_TMS320C4x -D_C4x -D_TMS320C44 -D_C44 } \
+%{mmemparm:-U_REGPARM }%{mregparm:-D_REGPARM } \
+%{!mmemparm:%{!mregparm:-D_REGPARM }} \
+%{msmall:-U_BIGMODEL } %{mbig:-D_BIGMODEL } \
+%{!msmall:%{!mbig:-D_BIGMODEL }} \
+%{finline-functions:-D_INLINE }"
+
+/* Specify the startup file to link with. */
+
+#define STARTFILE_SPEC "\
+%{!mmemparm:%{m30:%{msmall:crt0_3sr%O%s} %{!msmall:crt0_3br%O%s}}} \
+%{mmemparm:%{m30:%{msmall:crt0_3sm%O%s} %{!msmall:crt0_3bm%O%s}}} \
+%{!mmemparm:%{m31:%{msmall:crt0_3sr%O%s} %{!msmall:crt0_3br%O%s}}} \
+%{mmemparm:%{m31:%{msmall:crt0_3sm%O%s} %{!msmall:crt0_3bm%O%s}}} \
+%{!mmemparm:%{m32:%{msmall:crt0_3sr%O%s} %{!msmall:crt0_3br%O%s}}} \
+%{mmemparm:%{m32:%{msmall:crt0_3sm%O%s} %{!msmall:crt0_3bm%O%s}}} \
+%{!mmemparm:%{mcpu=30:%{msmall:crt0_3sr%O%s} %{!msmall:crt0_3br%O%s}}} \
+%{mmemparm:%{mcpu=30:%{msmall:crt0_3sm%O%s} %{!msmall:crt0_3bm%O%s}}} \
+%{!mmemparm:%{mcpu=31:%{msmall:crt0_3sr%O%s} %{!msmall:crt0_3br%O%s}}} \
+%{mmemparm:%{mcpu=31:%{msmall:crt0_3sm%O%s} %{!msmall:crt0_3bm%O%s}}} \
+%{!mmemparm:%{mcpu=32:%{msmall:crt0_3sr%O%s} %{!msmall:crt0_3br%O%s}}} \
+%{mmemparm:%{mcpu=32:%{msmall:crt0_3sm%O%s} %{!msmall:crt0_3bm%O%s}}} \
+%{!mmemparm:%{m40:%{msmall:crt0_4sr%O%s} %{!msmall:crt0_4br%O%s}}} \
+%{mmemparm:%{m40:%{msmall:crt0_4sm%O%s} %{!msmall:crt0_4bm%O%s}}} \
+%{!mmemparm:%{m44:%{msmall:crt0_4sr%O%s} %{!msmall:crt0_4br%O%s}}} \
+%{mmemparm:%{m44:%{msmall:crt0_4sm%O%s} %{!msmall:crt0_4bm%O%s}}} \
+%{!mmemparm:%{mcpu=40:%{msmall:crt0_4sr%O%s} %{!msmall:crt0_4br%O%s}}} \
+%{mmemparm:%{mcpu=40:%{msmall:crt0_4sm%O%s} %{!msmall:crt0_4bm%O%s}}} \
+%{!mmemparm:%{mcpu=44:%{msmall:crt0_4sr%O%s} %{!msmall:crt0_4br%O%s}}} \
+%{mmemparm:%{mcpu=44:%{msmall:crt0_4sm%O%s} %{!msmall:crt0_4bm%O%s}}} \
+%{!mmemparm:%{!m30:%{!m31:%{!m32:%{!mcpu=30:%{!mcpu=31:%{!mcpu=32: \
+  %{!mcpu=40:%{!mcpu=44:%{!m40:%{!m44:%{msmall:crt0_4sr%O%s}}}}}}}}}}}} \
+%{mmemparm:%{!m30:%{!m31:%{!m32:%{!mcpu=30:%{!mcpu=31:%{!mcpu=32: \
+  %{!mcpu=40:%{!mcpu=44:%{!m40:%{!m44:%{msmall:crt0_4sm%O%s}}}}}}}}}}}} \
+%{!mmemparm:%{!m30:%{!m31:%{!m32:%{!mcpu=30:%{!mcpu=31:%{!mcpu=32: \
+  %{!mcpu=40:%{!mcpu=44:%{!m40:%{!m44:%{!msmall:crt0_4br%O%s}}}}}}}}}}}} \
+%{mmemparm:%{!m30:%{!m31:%{!m32:%{!mcpu=30:%{!mcpu=31:%{!mcpu=32: \
+  %{!mcpu=40:%{!mcpu=44:%{!m40:%{!m44:%{!msmall:crt0_4bm%O%s}}}}}}}}}}}}"
+
+/* Specify the end file to link with */
+
+#define ENDFILE_SPEC ""
+
+/* Target compilation option flags */
+
+#define SMALL_MEMORY_FLAG   0x0000001 /* small memory model */
+#define MPYI_FLAG           0x0000002 /* use 24-bit MPYI for C3x */
+#define FAST_FIX_FLAG       0x0000004 /* fast fixing of floats */
+#define RPTS_FLAG           0x0000008 /* allow use of RPTS */
+#define C3X_FLAG            0x0000010 /* emit C3x code */
+#define TI_FLAG             0x0000020 /* be compatible with TI assembler */
+#define PARANOID_FLAG       0x0000040 /* be paranoid about DP reg. in ISRs */
+#define MEMPARM_FLAG        0x0000080 /* pass arguments on stack */
+#define DEVEL_FLAG          0x0000100 /* enable features under development */
+#define RPTB_FLAG           0x0000200 /* enable repeat block */
+#define BK_FLAG             0x0000400 /* use BK as general register */
+#define DB_FLAG             0x0000800 /* use decrement and branch for C3x */
+#define DEBUG_FLAG          0x0001000 /* enable debugging of GCC */
+#define HOIST_FLAG          0x0002000 /* force constants into registers */
+#define LOOP_UNSIGNED_FLAG  0x0004000 /* allow unsigned loop counters */
+#define FORCE_FLAG          0x0008000 /* force op0 and op1 to be same */
+#define PRESERVE_FLOAT_FLAG 0x0010000 /* save all 40 bits for floats */
+#define PARALLEL_PACK_FLAG  0x0020000 /* allow parallel insn packing */
+#define PARALLEL_MPY_FLAG   0x0040000 /* allow MPY||ADD, MPY||SUB insns */
+#define ALIASES_FLAG       0x0080000 /* assume mem refs possibly aliased */
+
+#define C30_FLAG            0x0100000 /* emit C30 code */
+#define C31_FLAG            0x0200000 /* emit C31 code */
+#define C32_FLAG            0x0400000 /* emit C32 code */
+#define C40_FLAG            0x1000000 /* emit C40 code */
+#define C44_FLAG            0x2000000 /* emit C44 code */
+
+/* Run-time compilation parameters selecting different hardware subsets.
+
+   Macro to define tables used to set the flags.
+   This is a list in braces of pairs in braces,
+   each pair being { "NAME", VALUE }
+   where VALUE is the bits to set or minus the bits to clear.
+   An empty string NAME is used to identify the default VALUE.  */
+
+#define TARGET_SWITCHES \
+{ { "small", SMALL_MEMORY_FLAG }, \
+  { "big", -SMALL_MEMORY_FLAG }, \
+  { "mpyi", MPYI_FLAG}, \
+  { "no-mpyi", -MPYI_FLAG}, \
+  { "fast-fix", FAST_FIX_FLAG}, \
+  { "no-fast-fix", -FAST_FIX_FLAG}, \
+  { "rpts", RPTS_FLAG}, \
+  { "no-rpts", -RPTS_FLAG}, \
+  { "rptb", RPTB_FLAG}, \
+  { "no-rptb", -RPTB_FLAG}, \
+  { "30", C30_FLAG}, \
+  { "31", C31_FLAG}, \
+  { "32", C32_FLAG}, \
+  { "40", C40_FLAG}, \
+  { "44", C44_FLAG}, \
+  { "ti", TI_FLAG}, \
+  { "no-ti", -TI_FLAG}, \
+  { "paranoid", PARANOID_FLAG}, \
+  { "no-paranoid", -PARANOID_FLAG}, \
+  { "isr-dp-reload", PARANOID_FLAG}, \
+  { "no-isr-dp-reload", -PARANOID_FLAG}, \
+  { "memparm", MEMPARM_FLAG}, \
+  { "regparm", -MEMPARM_FLAG}, \
+  { "devel", DEVEL_FLAG}, \
+  { "no-devel", -DEVEL_FLAG}, \
+  { "bk", BK_FLAG}, \
+  { "no-bk", -BK_FLAG}, \
+  { "db", DB_FLAG}, \
+  { "no-db", -DB_FLAG}, \
+  { "debug", DEBUG_FLAG}, \
+  { "no-debug", -DEBUG_FLAG}, \
+  { "hoist", HOIST_FLAG}, \
+  { "no-hoist", -HOIST_FLAG}, \
+  { "no-force", -FORCE_FLAG}, \
+  { "force", FORCE_FLAG}, \
+  { "loop-unsigned", LOOP_UNSIGNED_FLAG}, \
+  { "no-loop-unsigned", -LOOP_UNSIGNED_FLAG}, \
+  { "preserve-float", PRESERVE_FLOAT_FLAG}, \
+  { "no-preserve-float", -PRESERVE_FLOAT_FLAG}, \
+  { "parallel-insns", PARALLEL_PACK_FLAG}, \
+  { "no-parallel-mpy", -PARALLEL_MPY_FLAG}, \
+  { "parallel-mpy", PARALLEL_MPY_FLAG}, \
+  { "no-parallel-insns", -PARALLEL_PACK_FLAG}, \
+  { "aliases", ALIASES_FLAG}, \
+  { "no-aliases", -ALIASES_FLAG}, \
+  { "", TARGET_DEFAULT} }
+
+/* Default target switches */
+
+/* Play safe, not the fastest code.  Note that setting PARALLEL_MPY
+flag will set SMALL_REGISTER_CLASSES which can be a price to pay,
+especially when MPY||ADD instructions are only generated very
+infrequenctly. */
+#define TARGET_DEFAULT         ALIASES_FLAG | RPTB_FLAG | PARALLEL_PACK_FLAG
+
+/* Caveats:
+   Max iteration count for RPTB/RPTS is 2^31 + 1.
+   Max iteration count for DB is 2^31 + 1 for C40, but 2^23 + 1 for C30.
+   RPTS blocks interrupts.  */
+
+
+extern int target_flags;
+
+#define TARGET_INLINE          1 /* Inline MPYI */
+#define TARGET_PARALLEL                1 /* Enable parallel insns in MD */
+#define TARGET_SMALL_REG_CLASS 1 
+
+#define TARGET_SMALL           (target_flags & SMALL_MEMORY_FLAG)
+#define TARGET_MPYI            (!TARGET_C3X || (target_flags & MPYI_FLAG))
+#define TARGET_FAST_FIX                (target_flags & FAST_FIX_FLAG)
+#define TARGET_RPTS            (target_flags & RPTS_FLAG)
+#define TARGET_TI              (target_flags & TI_FLAG)
+#define TARGET_PARANOID                (target_flags & PARANOID_FLAG)
+#define TARGET_MEMPARM         (target_flags & MEMPARM_FLAG)
+#define TARGET_DEVEL           (target_flags & DEVEL_FLAG)
+#define TARGET_RPTB            (target_flags & RPTB_FLAG \
+                                && optimize >= 2)
+#define TARGET_BK              (target_flags & BK_FLAG)
+#define TARGET_DB              (!TARGET_C3X || (target_flags & DB_FLAG))
+#define TARGET_DEBUG           (target_flags & DEBUG_FLAG)
+#define TARGET_HOIST           (target_flags & HOIST_FLAG)
+#define TARGET_LOOP_UNSIGNED   (target_flags & LOOP_UNSIGNED_FLAG)
+#define TARGET_FORCE           (target_flags & FORCE_FLAG)
+#define        TARGET_PRESERVE_FLOAT   (target_flags & PRESERVE_FLOAT_FLAG)
+#define TARGET_PARALLEL_PACK   (TARGET_RPTB \
+                                && (target_flags & PARALLEL_PACK_FLAG) \
+                                && optimize >= 2)
+#define TARGET_PARALLEL_MPY    (TARGET_PARALLEL_PACK \
+                                && (target_flags & PARALLEL_MPY_FLAG))
+#define        TARGET_ALIASES          (target_flags & ALIASES_FLAG)
+
+#define TARGET_C3X             (target_flags & C3X_FLAG)
+#define TARGET_C30             (target_flags & C30_FLAG)
+#define TARGET_C31             (target_flags & C31_FLAG)
+#define TARGET_C32             (target_flags & C32_FLAG)
+#define TARGET_C40             (target_flags & C40_FLAG)
+#define TARGET_C44             (target_flags & C44_FLAG)
+
+/* -mrpts            allows the use of the RPTS instruction irregardless.
+   -mrpts=max-cycles will use RPTS if the number of cycles is constant
+   and less than max-cycles. */
+
+#define TARGET_RPTS_CYCLES(CYCLES) (TARGET_RPTS || (CYCLES) < c4x_rpts_cycles)
+
+/* -mcpu=XX    with XX = target DSP version number */
+
+/* This macro is similar to `TARGET_SWITCHES' but defines names of
+   command options that have values.  Its definition is an
+   initializer with a subgrouping for each command option.
+
+   Each subgrouping contains a string constant, that defines the
+   fixed part of the option name, and the address of a variable.
+   The variable, type `char *', is set to the variable part of the
+   given option if the fixed part matches.  The actual option name
+   is made by appending `-m' to the specified name.
+
+   Here is an example which defines `-mshort-data-NUMBER'.  If the
+   given option is `-mshort-data-512', the variable `m88k_short_data'
+   will be set to the string `"512"'.
+
+   extern char *m88k_short_data;
+   #define TARGET_OPTIONS { { "short-data-", &m88k_short_data } }  */
+
+extern char *c4x_rpts_cycles_string, *c4x_cpu_version_string;
+
+#define TARGET_OPTIONS         \
+{ {"rpts=", &c4x_rpts_cycles_string},\
+  {"cpu=", &c4x_cpu_version_string} }
+
+/* Sometimes certain combinations of command options do not make sense
+   on a particular target machine.  You can define a macro
+   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
+   defined, is executed once just after all the command options have
+   been parsed. */
+
+extern void c4x_override_options ();
+#define OVERRIDE_OPTIONS c4x_override_options ()
+
+
+/* Run Time Target Specification  */
+
+#define TARGET_VERSION fprintf (stderr, " (TMS320C[34]x, TI syntax)" );
+
+/* Storage Layout  */
+
+#define BITS_BIG_ENDIAN                0
+#define BYTES_BIG_ENDIAN       0
+#define WORDS_BIG_ENDIAN       0
+
+/* Technically, we are little endian, but we put the floats out as
+   whole longs and this makes GCC put them out in the right order. */
+
+#define FLOAT_WORDS_BIG_ENDIAN 1
+
+/* Note the ANSI C standard requires sizeof(char) = 1.  On the C[34]x
+   all integral and floating point data types are stored in memory as
+   32-bits (floating point types can be stored as 40-bits in the
+   extended precision registers), so sizeof(char) = sizeof(short) =
+   sizeof(int) = sizeof(long) = sizeof(float) = sizeof(double) = 1. */
+
+#define BITS_PER_UNIT          32
+#define BITS_PER_WORD          32
+#define UNITS_PER_WORD         1
+#define POINTER_SIZE           32
+#define PARM_BOUNDARY          32
+#define STACK_BOUNDARY         32
+#define FUNCTION_BOUNDARY      32
+#define BIGGEST_ALIGNMENT      32
+#define EMPTY_FIELD_BOUNDARY   32
+#define STRICT_ALIGNMENT       0
+#define TARGET_FLOAT_FORMAT    C4X_FLOAT_FORMAT
+#define MAX_FIXED_MODE_SIZE    64 /* HImode */
+
+/* Use the internal floating point stuff in the compiler and not the
+   host floating point stuff. */
+
+#define REAL_ARITHMETIC
+
+/* Define register numbers */
+
+/* Extended-precision registers */
+
+#define R0_REGNO   0
+#define R1_REGNO   1
+#define R2_REGNO   2
+#define R3_REGNO   3
+#define R4_REGNO   4
+#define R5_REGNO   5
+#define R6_REGNO   6
+#define R7_REGNO   7
+
+/* Auxiliary (address) registers */
+
+#define AR0_REGNO  8
+#define AR1_REGNO  9
+#define AR2_REGNO 10
+#define AR3_REGNO 11
+#define AR4_REGNO 12
+#define AR5_REGNO 13
+#define AR6_REGNO 14
+#define AR7_REGNO 15
+
+/* Data page register */
+
+#define DP_REGNO  16
+
+/* Index registers */
+
+#define IR0_REGNO 17
+#define IR1_REGNO 18
+
+/* Block size register */
+
+#define BK_REGNO  19
+
+/* Stack pointer */
+
+#define SP_REGNO  20
+
+/* Status register */
+
+#define ST_REGNO  21
+
+/* Misc. interrupt registers */
+
+#define DIE_REGNO 22           /* C4x only */
+#define IE_REGNO  22           /* C3x only */
+#define IIE_REGNO 23           /* C4x only */
+#define IF_REGNO  23           /* C3x only */
+#define IIF_REGNO 24           /* C4x only */
+#define IOF_REGNO 24           /* C3x only */
+
+/* Repeat block registers */
+
+#define RS_REGNO  25
+#define RE_REGNO  26
+#define RC_REGNO  27
+
+/* Additional extended-precision registers */
+
+#define R8_REGNO  28           /* C4x only */
+#define R9_REGNO  29           /* C4x only */
+#define R10_REGNO 30           /* C4x only */
+#define R11_REGNO 31           /* C4x only */
+
+#define FIRST_PSEUDO_REGISTER  32
+
+/* Extended precision registers (low set) */
+
+#define IS_R0R1_REG(r)             ((((r) >= R0_REGNO) && ((r) <= R1_REGNO)))
+#define IS_R2R3_REG(r)             ((((r) >= R2_REGNO) && ((r) <= R3_REGNO)))
+#define IS_EXT_LOW_REG(r)          ((((r) >= R0_REGNO) && ((r) <= R7_REGNO)))
+
+/* Extended precision registers (high set) */
+
+#define IS_EXT_HIGH_REG(r)         (!TARGET_C3X \
+                                   && ((r) >= R8_REGNO) && ((r) <= R11_REGNO))
+/* Address registers */
+
+#define IS_AUX_REG(r)    (((r) >= AR0_REGNO) && ((r) <= AR7_REGNO))
+#define IS_ADDR_REG(r)   IS_AUX_REG(r)
+#define IS_DP_REG(r)     ((r) == DP_REGNO)
+#define IS_INDEX_REG(r)  (((r) == IR0_REGNO) || ((r) == IR1_REGNO))
+#define IS_SP_REG(r)     ((r) == SP_REGNO)
+#define IS_BK_REG(r)     (TARGET_BK && (r) == BK_REGNO)
+
+/* Misc registers */
+
+#define IS_ST_REG(r)     ((r) == ST_REGNO)
+#define IS_REPEAT_REG(r) (((r) >= RS_REGNO) && ((r) <= RC_REGNO))
+
+/* Composite register sets */
+
+#define IS_ADDR_OR_INDEX_REG(r) (IS_ADDR_REG(r) || IS_INDEX_REG(r))
+#define IS_EXT_REG(r)           (IS_EXT_LOW_REG(r) || IS_EXT_HIGH_REG(r))
+#define IS_STD_REG(r)           (IS_ADDR_OR_INDEX_REG(r) || IS_REPEAT_REG(r) \
+                                 || IS_SP_REG(r) || IS_BK_REG(r))
+#define IS_INT_REG(r)           (IS_EXT_REG(r) || IS_STD_REG(r))
+#define IS_GROUP1_REG(r)        (IS_ADDR_OR_INDEX_REG(r) || IS_BK_REG(r))
+
+
+#define IS_PSEUDO_REG(r)            ((r) >= FIRST_PSEUDO_REGISTER)
+#define IS_R0R1_OR_PSEUDO_REG(r)    (IS_R0R1_REG(r) || IS_PSEUDO_REG(r))
+#define IS_R2R3_OR_PSEUDO_REG(r)    (IS_R2R3_REG(r) || IS_PSEUDO_REG(r))
+#define IS_EXT_OR_PSEUDO_REG(r)     (IS_EXT_REG(r) || IS_PSEUDO_REG(r))
+#define IS_STD_OR_PSEUDO_REG(r)     (IS_STD_REG(r) || IS_PSEUDO_REG(r))
+#define IS_INT_OR_PSEUDO_REG(r)     (IS_INT_REG(r) || IS_PSEUDO_REG(r))
+#define IS_ADDR_OR_PSEUDO_REG(r)    (IS_ADDR_REG(r) || IS_PSEUDO_REG(r))
+#define IS_INDEX_OR_PSEUDO_REG(r)   (IS_INDEX_REG(r) || IS_PSEUDO_REG(r))
+#define IS_EXT_LOW_OR_PSEUDO_REG(r) (IS_EXT_LOW_REG(r) || IS_PSEUDO_REG(r))
+#define IS_DP_OR_PSEUDO_REG(r)      (IS_DP_REG(r) || IS_PSEUDO_REG(r))
+#define IS_SP_OR_PSEUDO_REG(r)      (IS_SP_REG(r) || IS_PSEUDO_REG(r))
+#define IS_ST_OR_PSEUDO_REG(r)      (IS_ST_REG(r) || IS_PSEUDO_REG(r))
+
+#define IS_PSEUDO_REGNO(op)          (IS_PSEUDO_REG(REGNO(op)))
+#define IS_ADDR_REGNO(op)            (IS_ADDR_REG(REGNO(op)))
+#define IS_INDEX_REGNO(op)           (IS_INDEX_REG(REGNO(op)))
+#define IS_GROUP1_REGNO(r)           (IS_GROUP1_REG(REGNO(op)))
+
+#define IS_R0R1_OR_PSEUDO_REGNO(op)  (IS_R0R1_OR_PSEUDO_REG(REGNO(op)))
+#define IS_R2R3_OR_PSEUDO_REGNO(op)  (IS_R2R3_OR_PSEUDO_REG(REGNO(op)))
+#define IS_EXT_OR_PSEUDO_REGNO(op)   (IS_EXT_OR_PSEUDO_REG(REGNO(op)))
+#define IS_STD_OR_PSEUDO_REGNO(op)   (IS_STD_OR_PSEUDO_REG(REGNO(op)))
+#define IS_EXT_LOW_OR_PSEUDO_REGNO(op) (IS_EXT_LOW_OR_PSEUDO_REG(REGNO(op)))
+#define IS_INT_OR_PSEUDO_REGNO(op)   (IS_INT_OR_PSEUDO_REG(REGNO(op)))
+
+#define IS_ADDR_OR_PSEUDO_REGNO(op)  (IS_ADDR_OR_PSEUDO_REG(REGNO(op)))
+#define IS_INDEX_OR_PSEUDO_REGNO(op) (IS_INDEX_OR_PSEUDO_REG(REGNO(op)))
+#define IS_DP_OR_PSEUDO_REGNO(op)    (IS_DP_OR_PSEUDO_REG(REGNO(op)))
+#define IS_SP_OR_PSEUDO_REGNO(op)    (IS_SP_OR_PSEUDO_REG(REGNO(op)))
+#define IS_ST_OR_PSEUDO_REGNO(op)    (IS_ST_OR_PSEUDO_REG(REGNO(op)))
+
+/* 1 for registers that have pervasive standard uses
+   and are not available for the register allocator. */
+
+#define FIXED_REGISTERS \
+{                                                                      \
+/* R0  R1  R2  R3  R4  R5  R6  R7 AR0 AR1 AR2 AR3 AR4 AR5 AR6 AR7 */   \
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,     \
+/* DP IR0 IR1  BK  SP  ST DIE IIE IIF  RS  RE  RC  R8  R9 R10 R11 */   \
+    1,  0,  0,  0,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0      \
+}
+
+/* 1 for registers not available across function calls.
+   These must include the FIXED_REGISTERS and also any
+   registers that can be used without being saved.
+   The latter must include the registers where values are returned
+   and the register where structure-value addresses are passed.
+   Aside from that, you can include as many other registers as you like.  
+   
+   Note that the extended precision registers are only saved in some
+   modes.  The macro HARD_REGNO_CALL_CLOBBERED specifies which modes
+   get clobbered for a given regno.  */
+
+#define CALL_USED_REGISTERS \
+{                                                                      \
+/* R0  R1  R2  R3  R4  R5  R6  R7 AR0 AR1 AR2 AR3 AR4 AR5 AR6 AR7 */   \
+    1,  1,  1,  1,  0,  0,  0,  0,  1,  1,  1,  0,  0,  0,  0,  0,     \
+/* DP IR0 IR1  BK  SP  ST DIE IIE IIF  RS  RE  RC  R8  R9 R10 R11 */   \
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1      \
+}
+
+/* Macro to conditionally modify fixed_regs/call_used_regs. */
+
+#define CONDITIONAL_REGISTER_USAGE                     \
+  {                                                    \
+    if (!TARGET_BK)                                    \
+      {                                                        \
+       fixed_regs[BK_REGNO] = 1;                       \
+        call_used_regs[BK_REGNO] = 1;                  \
+        c4x_regclass_map[BK_REGNO] = NO_REGS;          \
+      }                                                        \
+    if (TARGET_C3X)                                    \
+      {                                                        \
+        int i;                                          \
+                                                        \
+        reg_names[DIE_REGNO] = "ie";  /* clobber die */ \
+        reg_names[IF_REGNO] = "if";   /* clobber iie */ \
+        reg_names[IOF_REGNO] = "iof"; /* clobber iif */ \
+                                                       \
+        for (i = R8_REGNO; i <= R11_REGNO; i++)        \
+        {                                              \
+            fixed_regs[i] = call_used_regs[i] = 1;     \
+            c4x_regclass_map[i] = NO_REGS;             \
+        }                                              \
+      }                                                        \
+   }
+
+/* Order of Allocation of Registers  */
+
+/* List the order in which to allocate registers.  Each register must be
+   listed once, even those in FIXED_REGISTERS.
+
+   First allocate registers that don't need preservation across calls,
+   except index and address registers.  Then allocate data registers
+   that require preservation across calls (even though this invokes an
+   extra overhead of having to save/restore these registers).  Next
+   allocate the address and index registers, since using these
+   registers for arithmetic can cause pipeline stalls.  Finally
+   allocated the fixed registers which won't be allocated anyhow.  */
+
+#define REG_ALLOC_ORDER                                        \
+{R0_REGNO, R1_REGNO, R2_REGNO, R3_REGNO,               \
+ R9_REGNO, R10_REGNO, R11_REGNO,                       \
+ RS_REGNO, RE_REGNO, RC_REGNO, BK_REGNO,               \
+ R4_REGNO, R5_REGNO, R6_REGNO, R7_REGNO, R8_REGNO,     \
+ AR0_REGNO, AR1_REGNO, AR2_REGNO, AR3_REGNO,           \
+ AR4_REGNO, AR5_REGNO, AR6_REGNO, AR7_REGNO,           \
+ IR0_REGNO, IR1_REGNO,                                 \
+ SP_REGNO, DP_REGNO, ST_REGNO, IE_REGNO, IF_REGNO, IOF_REGNO}
+
+
+/* Determine which register classes are very likely used by spill registers.
+   local-alloc.c won't allocate pseudos that have these classes as their
+   preferred class unless they are "preferred or nothing".  */
+
+#define CLASS_LIKELY_SPILLED_P(CLASS) \
+ ((CLASS) == INDEX_REGS)
+
+/* CCmode is wrongly defined in machmode.def  It should have a size
+   of UNITS_PER_WORD. */
+
+#define HARD_REGNO_NREGS(REGNO, MODE)                          \
+(((MODE) == CCmode || (MODE) == CC_NOOVmode) ? 1 : ((MODE) == HFmode) ? 1 : \
+((GET_MODE_SIZE(MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+
+/* A C expression that is nonzero if the hard register REGNO is preserved
+   across a call in mode MODE.  This does not have to include the call used
+   registers.  */
+
+#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE)                        \
+     (((REGNO) == R6_REGNO || (REGNO) == R7_REGNO)                          \
+      && (MODE) != QFmode                                                   \
+      || ((REGNO) == R4_REGNO || (REGNO) == R5_REGNO || (REGNO == R8_REGNO) \
+         && ((MODE) != QImode || (MODE) != HImode || (MODE) != Pmode)))
+
+/* Specify the modes required to caller save a given hard regno.  */
+
+#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS) (c4x_caller_save_map[REGNO])
+
+int c4x_hard_regno_mode_ok ();
+#define HARD_REGNO_MODE_OK(REGNO, MODE)  c4x_hard_regno_mode_ok(REGNO, MODE)
+
+
+/* A C expression that is nonzero if it is desirable to choose
+   register allocation so as to avoid move instructions between a
+   value of mode MODE1 and a value of mode MODE2.
+
+   Value is 1 if it is a good idea to tie two pseudo registers
+   when one has mode MODE1 and one has mode MODE2.
+   If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
+   for any hard reg, then this must be 0 for correct output.  */
+
+#define MODES_TIEABLE_P(MODE1, MODE2)          0
+
+
+/* Define the classes of registers for register constraints in the
+   machine description.  Also define ranges of constants.
+
+   One of the classes must always be named ALL_REGS and include all hard regs.
+   If there is more than one class, another class must be named NO_REGS
+   and contain no registers.
+
+   The name GENERAL_REGS must be the name of a class (or an alias for
+   another name such as ALL_REGS).  This is the class of registers
+   that is allowed by "g" or "r" in a register constraint.
+   Also, registers outside this class are allocated only when
+   instructions express preferences for them.
+
+   The classes must be numbered in nondecreasing order; that is,
+   a larger-numbered class must never be contained completely
+   in a smaller-numbered class.
+
+   For any two classes, it is very desirable that there be another
+   class that represents their union.  */
+   
+enum reg_class
+  {
+    NO_REGS,
+    R0R1_REGS,                 /* 't' */
+    R2R3_REGS,                 /* 'u' */
+    EXT_LOW_REGS,              /* 'q' */
+    EXT_REGS,                  /* 'f' */
+    ADDR_REGS,                 /* 'a' */
+    INDEX_REGS,                        /* 'x' */
+    SP_REG,                    /* 'b' */
+    BK_REG,                    /* 'k' */
+    INT_REGS,                  /* 'c' */
+    GENERAL_REGS,              /* 'r' */
+    DP_REG,                    /* 'z' */
+    ST_REG,                    /* 'y' */
+    ALL_REGS,
+    LIM_REG_CLASSES
+  };
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES \
+{                      \
+   "NO_REGS",          \
+   "R0R1_REGS",                \
+   "R2R3_REGS",                \
+   "EXT_LOW_REGS",     \
+   "EXT_REGS",         \
+   "ADDR_REGS",                \
+   "INDEX_REGS",       \
+   "SP_REG",           \
+   "BK_REG",           \
+   "INT_REGS",         \
+   "GENERAL_REGS",     \
+   "DP_REG",           \
+   "ST_REG",           \
+   "ALL_REGS"          \
+};
+
+/* Define which registers fit in which classes.
+   This is an initializer for a vector of HARD_REG_SET
+   of length N_REG_CLASSES.  */
+
+
+#define REG_CLASS_CONTENTS \
+{                                              \
+ 0x00000000, /*     No registers */            \
+ 0x00000003, /* 't' R0-R1       */             \
+ 0x0000000c, /* 'u' R2-R3       */             \
+ 0x000000ff, /* 'q' R0-R7       */             \
+ 0xf00000ff, /* 'f' R0-R11       */            \
+ 0x0000ff00, /* 'a' AR0-AR7 */                 \
+ 0x00060000, /* 'x' IR0-IR1 */                 \
+ 0x00100000, /* 'b' SP */                      \
+ 0x00080000, /* 'k' BK */                      \
+ 0x0e1eff00, /* 'c' AR0-AR7, IR0-IR1, RC, RS, RE, BK, SP */    \
+ 0xfe1effff, /* 'r' R0-R11, AR0-AR7, IR0-IR1, RC, RS, RE, BK, SP */\
+ 0x00010000, /* 'z' DP */                      \
+ 0x00200000, /* 'y' ST */                      \
+ 0xffffffff, /*     All registers */           \
+}
+
+/* The same information, inverted:
+   Return the class number of the smallest class containing
+   reg number REGNO.  This could be a conditional expression
+   or could index an array.  */
+
+#define REGNO_REG_CLASS(REGNO) (c4x_regclass_map[REGNO])
+
+/* When SMALL_REGISTER_CLASSES is defined, the compiler allows
+registers explicitly used in the rtl to be used as spill registers but
+prevents the compiler from extending the lifetime of these registers.
+Problems can occur if reload has to spill a register used explicitly
+in the RTL if it has a long lifetime.   This is only likely to be a problem
+with a function having many variables and thus lots of spilling.  
+
+We only need to define SMALL_REGISTER_CLASSES if TARGET_PARALLEL_MPY
+is defined since the MPY|ADD insns require the classes R0R1_REGS and
+R2R3_REGS which are used by the function return registers (R0,R1) and
+the register arguments (R2,R3), respectively.  I'm reluctant to define
+this macro since it stomps on many potential optimisations.  Ideally
+it should have a register class argument so that not all the register
+classes gets penalised for the sake of a naughty few...  For long
+double arithmetic we need two additional registers that we can use as
+spill registers.  */
+
+#define SMALL_REGISTER_CLASSES (TARGET_SMALL_REG_CLASS && TARGET_PARALLEL_MPY)
+
+#define BASE_REG_CLASS ADDR_REGS
+#define INDEX_REG_CLASS INDEX_REGS
+
+/*
+  Constraints for the C4x
+  a - address reg (ar0-ar7)
+  b - stack reg (sp)
+  c - other gp int-only reg
+  d - data/int reg (equiv. to f)
+  f - data/float reg
+  h - data/long double reg (equiv. to f)
+  k - block count (bk)
+  q - r0-r7
+  t - r0-r1
+  u - r2-r3
+  x - index register (ir0-ir1)
+  y - status register (st)
+  z - dp reg (dp) 
+
+  G - short float 16-bit
+  I - signed 16-bit constant (sign extended)
+  J - signed 8-bit constant (sign extended)  (C4x only)
+  K - signed 5-bit constant (sign extended)  (C4x only for stik)
+  L - unsigned 16-bit constant
+  M - unsigned 8-bit constant                (C4x only)
+  N - ones complement of unsigned 16-bit constant
+  Q - indirect arx + 9-bit signed displacement
+      (a *-arx(n) or *+arx(n) is used to account for the sign bit)
+  R - indirect arx + 5-bit unsigned displacement  (C4x only)
+  S - indirect arx + 0, 1, or irn displacement
+  T - direct symbol ref
+  > - indirect with autoincrement
+  < - indirect with autodecrement
+  } - indirect with post-modify
+  { - indirect with pre-modify
+  */
+
+#define REG_CLASS_FROM_LETTER(CC)                              \
+     ( ((CC) == 'a') ? ADDR_REGS                               \
+     : ((CC) == 'b') ? SP_REG                                  \
+     : ((CC) == 'c') ? INT_REGS                                        \
+     : ((CC) == 'd') ? EXT_REGS                                        \
+     : ((CC) == 'f') ? EXT_REGS                                        \
+     : ((CC) == 'h') ? EXT_REGS                                        \
+     : ((CC) == 'k') ? BK_REG                                  \
+     : ((CC) == 'q') ? EXT_LOW_REGS                            \
+     : ((CC) == 't') ? R0R1_REGS                               \
+     : ((CC) == 'u') ? R2R3_REGS                               \
+     : ((CC) == 'x') ? INDEX_REGS                              \
+     : ((CC) == 'y') ? ST_REG                                  \
+     : ((CC) == 'z') ? DP_REG                                  \
+     : NO_REGS )
+
+/* These assume that REGNO is a hard or pseudo reg number.
+   They give nonzero only if REGNO is a hard reg of the suitable class
+   or a pseudo reg currently allocated to a suitable hard reg.
+   Since they use reg_renumber, they are safe only once reg_renumber
+   has been allocated, which happens in local-alloc.c.  */
+
+#define REGNO_OK_FOR_BASE_P(REGNO)  \
+     (IS_ADDR_REG(REGNO) || IS_ADDR_REG((unsigned)reg_renumber[REGNO]))
+
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+     (IS_INDEX_REG(REGNO) || IS_INDEX_REG((unsigned)reg_renumber[REGNO]))
+
+extern enum reg_class c4x_preferred_reload_class ();
+#define PREFERRED_RELOAD_CLASS(X, CLASS) c4x_preferred_reload_class(X, CLASS)
+
+extern enum reg_class c4x_limit_reload_class ();
+#define LIMIT_RELOAD_CLASS(X, CLASS) c4x_limit_reload_class(X, CLASS)
+
+extern enum reg_class c4x_secondary_memory_needed ();
+#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE)  \
+c4x_secondary_memory_needed(CLASS1, CLASS2, MODE)
+
+#define CLASS_MAX_NREGS(CLASS, MODE)                   \
+(((MODE) == CCmode || (MODE) == CC_NOOVmode) ? 1 : ((MODE) == HFmode) ? 1 : \
+((GET_MODE_SIZE(MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+#define IS_INT5_CONST(VAL) (((VAL) <= 15) && ((VAL) >= -16))   /* 'K' */
+
+#define IS_UINT5_CONST(VAL) (((VAL) <= 31) && ((VAL) >= 0))    /* 'R' */
+
+#define IS_INT8_CONST(VAL) (((VAL) <= 127) && ((VAL) >= -128)) /* 'J' */
+
+#define IS_UINT8_CONST(VAL) (((VAL) <= 255) && ((VAL) >= 0))   /* 'M' */
+
+#define IS_INT16_CONST(VAL) (((VAL) <= 32767) && ((VAL) >= -32768)) /* 'I' */
+
+#define IS_UINT16_CONST(VAL) (((VAL) <= 65535) && ((VAL) >= 0))        /* 'L' */
+
+#define IS_NOT_UINT16_CONST(VAL) IS_UINT16_CONST(~(VAL))       /* 'N' */
+
+#define IS_HIGH_CONST(VAL) (!TARGET_C3X && (((VAL) & 0xffff) == 0)) /* 'O' */
+
+
+#define IS_DISP1_CONST(VAL) (((VAL) <= 1) && ((VAL) >= -1)) /* 'S' */
+
+#define IS_DISP8_CONST(VAL) (((VAL) <= 255) && ((VAL) >= -255))        /* 'Q' */
+
+#define IS_DISP1_OFF_CONST(VAL) (IS_DISP1_CONST (VAL) \
+                                && IS_DISP1_CONST (VAL + 1))
+
+#define IS_DISP8_OFF_CONST(VAL) (IS_DISP8_CONST (VAL) \
+                                && IS_DISP8_CONST (VAL + 1))
+
+#define CONST_OK_FOR_LETTER_P(VAL, C)                                  \
+        ( ((C) == 'I') ? (IS_INT16_CONST (VAL))                                \
+       : ((C) == 'J') ? (!TARGET_C3X && IS_INT8_CONST (VAL))           \
+       : ((C) == 'K') ? (!TARGET_C3X && IS_INT5_CONST (VAL))           \
+        : ((C) == 'L') ? (IS_UINT16_CONST (VAL))                       \
+       : ((C) == 'M') ? (!TARGET_C3X && IS_UINT8_CONST (VAL))          \
+       : ((C) == 'N') ? (IS_NOT_UINT16_CONST (VAL))                    \
+       : ((C) == 'O') ? (IS_HIGH_CONST (VAL))                          \
+        : 0 )  
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL, C)                           \
+        ( ((C) == 'G') ? (fp_zero_operand (VAL))                       \
+       : ((C) == 'H') ? (c4x_H_constant (VAL))                         \
+       : 0 )
+
+#define EXTRA_CONSTRAINT(VAL, C) \
+        ( ((C) == 'Q') ? (c4x_Q_constraint (VAL))                      \
+       : ((C) == 'R') ? (c4x_R_constraint (VAL))                       \
+       : ((C) == 'S') ? (c4x_S_constraint (VAL))                       \
+       : ((C) == 'T') ? (c4x_T_constraint (VAL))                       \
+       : 0 )
+
+#define SMALL_CONST(VAL, insn)                                         \
+     (  ((insn == NULL_RTX) || (get_attr_data (insn) == DATA_INT16))   \
+       ? IS_INT16_CONST (VAL)                                          \
+       : ( (get_attr_data (insn) == DATA_NOT_UINT16)                   \
+           ? IS_NOT_UINT16_CONST (VAL)                                 \
+           :  ( (get_attr_data (insn) == DATA_HIGH_16)                 \
+              ? IS_HIGH_CONST (VAL)                                    \
+              : IS_UINT16_CONST (VAL)                                  \
+           )                                                           \
+         )                                                             \
+       )
+
+/*
+   I. Routine calling with arguments in registers
+   ----------------------------------------------
+
+   The TI C3x compiler has a rather unusual register passing algorithm.
+   Data is passed in the following registers (in order):
+
+   AR2, R2, R3, RC, RS, RE
+
+   However, the first and second floating point values are always in R2
+   and R3 (and all other floats are on the stack).  Structs are always
+   passed on the stack.  If the last argument is an ellipsis, the
+   previous argument is passed on the stack so that its address can be
+   taken for the stdargs macros.
+
+   Because of this, we have to pre-scan the list of arguments to figure
+   out what goes where in the list.
+
+   II. Routine calling with arguments on stack
+   -------------------------------------------
+
+   Let the subroutine declared as "foo(arg0, arg1, arg2);" have local
+   variables loc0, loc1, and loc2.  After the function prologue has
+   been executed, the stack frame will look like:
+
+   [stack grows towards increasing addresses]
+       I-------------I
+   5   I saved reg1  I  <= SP points here
+       I-------------I
+   4   I saved reg0  I  
+       I-------------I
+   3   I       loc2  I  
+       I-------------I  
+   2   I       loc1  I  
+       I-------------I  
+   1   I       loc0  I  
+       I-------------I
+   0   I     old FP  I <= FP (AR3) points here
+       I-------------I
+   -1  I  return PC  I
+       I-------------I
+   -2  I       arg0  I  
+       I-------------I  
+   -3  I       arg1  I
+       I-------------I  
+   -4  I       arg2  I 
+       I-------------I  
+
+   All local variables (locn) are accessible by means of +FP(n+1)
+   addressing, where n is the local variable number.
+
+   All stack arguments (argn) are accessible by means of -FP(n-2).
+
+   The stack pointer (SP) points to the last register saved in the
+   prologue (regn).
+
+   Note that a push instruction performs a preincrement of the stack
+   pointer.  (STACK_PUSH_CODE == PRE_INC)
+
+   III. Registers used in function calling convention
+   --------------------------------------------------
+
+   Preserved across calls: R4...R5 (only by PUSH,  i.e. lower 32 bits)
+   R6...R7 (only by PUSHF, i.e. upper 32 bits)
+   AR3...AR7
+
+   (Because of this model, we only assign FP values in R6, R7 and
+   only assign integer values in R4, R5.)
+
+   These registers are saved at each function entry and restored at
+   the exit. Also it is expected any of these not affected by any
+   call to user-defined (not service) functions.
+
+   Not preserved across calls: R0...R3
+   R4...R5 (upper 8 bits)
+   R6...R7 (lower 8 bits)
+   AR0...AR2, IR0, IR1, BK, ST, RS, RE, RC
+
+   These registers are used arbitrary in a function without being preserved.
+   It is also expected that any of these can be clobbered by any call.
+
+   Not used by GCC (except for in user "asm" statements):
+   IE (DIE), IF (IIE), IOF (IIF)
+
+   These registers are never used by GCC for any data, but can be used
+   with "asm" statements.  */
+
+#define C4X_ARG0 -2
+#define C4X_LOC0 1
+
+/* Basic Stack Layout  */
+     
+/* The stack grows upward, stack frame grows upward, and args grow
+   downward. */
+
+#define STARTING_FRAME_OFFSET          C4X_LOC0
+#define FIRST_PARM_OFFSET(FNDECL)      (C4X_ARG0 + 1)
+#define ARGS_GROW_DOWNWARD
+#define STACK_POINTER_OFFSET 1
+
+/* Define this if pushing a word on the stack
+   makes the stack pointer a smaller address.  */
+
+/* #define STACK_GROWS_DOWNWARD */
+/* Like the dsp16xx, i370, i960, and we32k ports */
+
+/* Define this if the nominal address of the stack frame
+   is at the high-address end of the local variables;
+   that is, each additional local variable allocated
+   goes at a more negative offset in the frame.  */
+
+/* #define FRAME_GROWS_DOWNWARD */
+
+
+/* Registers That Address the Stack Frame  */
+
+#define STACK_POINTER_REGNUM   SP_REGNO        /* SP */
+#define FRAME_POINTER_REGNUM   AR3_REGNO       /* AR3 */
+#define ARG_POINTER_REGNUM     AR3_REGNO       /* AR3 */
+#define STATIC_CHAIN_REGNUM    AR0_REGNO       /* AR0 */
+
+/* Eliminating Frame Pointer and Arg Pointer  */
+
+#define FRAME_POINTER_REQUIRED 0
+
+#define INITIAL_FRAME_POINTER_OFFSET(DEPTH)                    \
+{                                                              \
+ int regno;                                                    \
+ int offset = 0;                                               \
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)      \
+    if (regs_ever_live[regno] && !call_used_regs[regno])       \
+      offset += TARGET_PRESERVE_FLOAT                          \
+               && ((regno == R6_REGNO) || (regno == R7_REGNO)) \
+               ? 2 : 1;                                        \
+  (DEPTH) = -(offset + get_frame_size ());                     \
+}
+
+/* This is a hack... We need to specify a register.  */
+#define        ELIMINABLE_REGS                                         \
+  {{ FRAME_POINTER_REGNUM, FRAME_POINTER_REGNUM }}
+
+#define        CAN_ELIMINATE(FROM, TO)                                 \
+  (!(((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
+  || ((FROM) == FRAME_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM)))
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)           \
+{                                                              \
+ int regno;                                                    \
+ int offset = 0;                                               \
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)      \
+    if (regs_ever_live[regno] && !call_used_regs[regno])       \
+      offset += TARGET_PRESERVE_FLOAT                          \
+               && ((regno == R6_REGNO) || (regno == R7_REGNO)) \
+               ? 2 : 1;                                        \
+  (OFFSET) = -(offset + get_frame_size ());                    \
+}
+
+
+/* Passing Function Arguments on the Stack  */
+
+#if 0
+#define PUSH_ROUNDING(BYTES) (BYTES)
+#endif
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
+
+/* The following structure is used by calls.c, function.c, c4x.c  */
+
+typedef struct c4x_args
+{
+  int floats;
+  int ints;
+  int maxfloats;
+  int maxints;
+  int init;
+  int var;
+  int prototype;
+  int args;
+}
+CUMULATIVE_ARGS;
+
+extern void c4x_init_cumulative_args();
+
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT)      \
+  (c4x_init_cumulative_args (&CUM, FNTYPE, LIBNAME))
+
+extern void c4x_function_arg_advance();
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)   \
+  (c4x_function_arg_advance (&CUM, MODE, TYPE, NAMED))
+
+extern struct rtx_def *c4x_function_arg();
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+  (c4x_function_arg(&CUM, MODE, TYPE, NAMED))
+
+/* Define the profitability of saving registers around calls.
+   NOTE: For now we turn this off because caller-save assumes
+   that a register with a QFmode quantity can be saved/restored
+   using QImode.  */
+
+/* #define CALLER_SAVE_PROFITABLE(REFS,CALLS) 0 */
+
+/* Never pass data by reference.  */
+
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0
+
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
+
+/* 1 if N is a possible register number for function argument passing. */
+
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+       (  (   ((REGNO) == AR2_REGNO)   /* AR2 */       \
+           || ((REGNO) == R2_REGNO)    /* R2 */        \
+           || ((REGNO) == R3_REGNO)    /* R3 */        \
+           || ((REGNO) == RC_REGNO)    /* RC */        \
+           || ((REGNO) == RS_REGNO)    /* RS */        \
+           || ((REGNO) == RE_REGNO))   /* RE */        \
+        ? 1                                            \
+        : 0)
+
+/* How Scalar Function Values Are Returned  */
+
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+       gen_rtx(REG, TYPE_MODE(VALTYPE), R0_REGNO)      /* Return in R0 */
+
+#define LIBCALL_VALUE(MODE) \
+       gen_rtx(REG, MODE, R0_REGNO)    /* Return in R0 */
+
+#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == R0_REGNO)
+
+/* How Large Values Are Returned  */
+
+#define DEFAULT_PCC_STRUCT_RETURN      0
+#define STRUCT_VALUE_REGNUM            AR0_REGNO       /* AR0 */
+
+
+/* Function Entry and Exit  */
+
+#define FUNCTION_PROLOGUE(FILE, SIZE)  c4x_function_prologue(FILE, SIZE)
+#define FUNCTION_EPILOGUE(FILE, SIZE)  c4x_function_epilogue(FILE, SIZE)
+
+
+/* Generating Code for Profiling  */
+
+/* Note that the generated assembly uses the ^ operator to load the 16
+   MSBs of the address.  This is not supported by the TI assembler.  */
+
+#define FUNCTION_PROFILER(FILE, LABELNO)                       \
+     if (!TARGET_C3X)                                          \
+     {                                                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tldhi\t^LP%d,ar2\n", (LABELNO));       \
+       fprintf (FILE, "\tor\t#LP%d,ar2\n", (LABELNO));         \
+       fprintf (FILE, "\tcall\tmcount\n");                     \
+       fprintf (FILE, "\tpop\tar2\n");                         \
+     }                                                         \
+     else                                                      \
+     {                                                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tldiu\t^LP%d,ar2\n", (LABELNO));       \
+       fprintf (FILE, "\tlsh\t16,ar2\n");                      \
+       fprintf (FILE, "\tor\t#LP%d,ar2\n", (LABELNO));         \
+       fprintf (FILE, "\tcall\tmcount\n");                     \
+       fprintf (FILE, "\tpop\tar2\n");                         \
+     }
+
+/* There are three profiling modes for basic blocks available.
+   The modes are selected at compile time by using the options
+   -a or -ax of the gnu compiler.
+   The variable `profile_block_flag' will be set according to the
+   selected option.
+
+   profile_block_flag == 0, no option used:
+
+      No profiling done.
+
+   profile_block_flag == 1, -a option used.
+
+      Count frequency of execution of every basic block.
+
+   profile_block_flag == 2, -ax option used.
+
+      Generate code to allow several different profiling modes at run time. 
+      Available modes are:
+             Produce a trace of all basic blocks.
+             Count frequency of jump instructions executed.
+      In every mode it is possible to start profiling upon entering
+      certain functions and to disable profiling of some other functions.
+
+    The result of basic-block profiling will be written to a file `bb.out'.
+    If the -ax option is used parameters for the profiling will be read
+    from file `bb.in'.
+
+*/
+
+#define FUNCTION_BLOCK_PROFILER(FILE, BLOCKNO)                         \
+  if (profile_block_flag == 2)                                 \
+    {                                                          \
+      if (!TARGET_C3X)                                         \
+      {                                                                \
+       fprintf (FILE, "\tpush\tst\n");                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tpush\tr2\n");                         \
+       fprintf (FILE, "\tldhi\t^LPBX0,ar2\n");                 \
+       fprintf (FILE, "\tor\t#LPBX0,ar2\n");                   \
+       if (BLOCKNO > 32767)                                    \
+         {                                                     \
+           fprintf (FILE, "\tldhi\t%d,r2\n", (BLOCKNO) >> 16); \
+           fprintf (FILE, "\tor\t%d,r2\n", (BLOCKNO));         \
+         }                                                     \
+       else                                                    \
+         {                                                     \
+           fprintf (FILE, "\tldiu\t%d,r2\n", (BLOCKNO));       \
+         }                                                     \
+       fprintf (FILE, "\tcall\t___bb_init_trace_func\n");      \
+       fprintf (FILE, "\tpop\tr2\n");                          \
+       fprintf (FILE, "\tpop\tar2\n");                         \
+       fprintf (FILE, "\tpop\tst\n");                          \
+      }                                                                \
+      else                                                     \
+      {                                                                \
+       fprintf (FILE, "\tpush\tst\n");                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tpush\tr2\n");                         \
+       fprintf (FILE, "\tldiu\t^LPBX0,ar2\n");                 \
+       fprintf (FILE, "\tlsh\t16,ar2\n");                      \
+       fprintf (FILE, "\tor\t#LPBX0,ar2\n");                   \
+       if (BLOCKNO > 32767)                                    \
+         {                                                     \
+           fprintf (FILE, "\tldi\t%d,r2\n", (BLOCKNO) >> 16);  \
+           fprintf (FILE, "\tlsh\t16,r2\n");                   \
+           fprintf (FILE, "\tor\t%d,r2\n", (BLOCKNO));         \
+         }                                                     \
+       else                                                    \
+         {                                                     \
+           fprintf (FILE, "\tldiu\t%d,r2\n", (BLOCKNO));       \
+         }                                                     \
+       fprintf (FILE, "\tcall\t___bb_init_trace_func\n");      \
+       fprintf (FILE, "\tpop\tr2\n");                          \
+       fprintf (FILE, "\tpop\tar2\n");                         \
+       fprintf (FILE, "\tpop\tst\n");                          \
+      }                                                                \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      if (!TARGET_C3X)                                         \
+      {                                                                \
+       fprintf (FILE, "\tpush\tst\n");                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tldhi\t^LPBX0,ar2\n");                 \
+       fprintf (FILE, "\tor\t#LPBX0,ar2\n");                   \
+       fprintf (FILE, "\tcmpi\t0,*ar2\n");                     \
+       fprintf (FILE, "\tbne\t$+2\n");                         \
+       fprintf (FILE, "\tcall\t___bb_init_func\n");            \
+       fprintf (FILE, "\tpop\tar2\n");                         \
+       fprintf (FILE, "\tpop\tst\n");                          \
+      }                                                                \
+      else                                                     \
+      {                                                                \
+       fprintf (FILE, "\tpush\tst\n");                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tpush\tr2\n");                         \
+       fprintf (FILE, "\tldiu\t^LPBX0,ar2\n");                 \
+       fprintf (FILE, "\tlsh\t16,ar2\n");                      \
+       fprintf (FILE, "\tor\t#LPBX0,ar2\n");                   \
+       fprintf (FILE, "\tldi\t*ar2,r2\n");                     \
+       fprintf (FILE, "\tbne\t$+2\n");                         \
+       fprintf (FILE, "\tcall\t___bb_init_func\n");            \
+       fprintf (FILE, "\tpop\tr2\n");                          \
+       fprintf (FILE, "\tpop\tar2\n");                         \
+       fprintf (FILE, "\tpop\tst\n");                          \
+      }                                                                \
+    }
+
+#define BLOCK_PROFILER(FILE, BLOCKNO)                          \
+  if (profile_block_flag == 2)                                 \
+    {                                                          \
+      if (!TARGET_C3X)                                         \
+      {                                                                \
+       fprintf (FILE, "\tpush\tst\n");                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tpush\tar0\n");                        \
+       fprintf (FILE, "\tldhi\t^___bb,ar2\n");                 \
+       fprintf (FILE, "\tor\t#___bb,ar2\n");                   \
+       if (BLOCKNO > 32767)                                    \
+         {                                                     \
+           fprintf (FILE, "\tldhi\t%d,ar0\n", (BLOCKNO) >> 16);\
+           fprintf (FILE, "\tor\t%d,ar0\n", (BLOCKNO));        \
+         }                                                     \
+       else                                                    \
+         {                                                     \
+           fprintf (FILE, "\tldiu\t%d,ar0\n", (BLOCKNO));      \
+         }                                                     \
+       fprintf (FILE, "\tsti\tar0,*ar2\n");                    \
+       fprintf (FILE, "\tldhi\t^LPBX0,ar0\n");                 \
+       fprintf (FILE, "\tor\t#LPBX0,ar0\n");                   \
+       fprintf (FILE, "\tsti\tar0,*+ar2(1)\n");                \
+       fprintf (FILE, "\tcall\t___bb_trace_func\n");           \
+       fprintf (FILE, "\tpop\tar0\n");                         \
+        fprintf (FILE, "\tpop\tar2\n");                                \
+       fprintf (FILE, "\tpop\tst\n");                          \
+      }                                                                \
+      else                                                     \
+      {                                                                \
+       fprintf (FILE, "\tpush\tst\n");                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tpush\tar0\n");                        \
+       fprintf (FILE, "\tldiu\t^___bb,ar2\n");                 \
+       fprintf (FILE, "\tlsh\t16,ar2\n");                      \
+       fprintf (FILE, "\tor\t#___bb,ar2\n");                   \
+       if (BLOCKNO > 32767)                                    \
+         {                                                     \
+           fprintf (FILE, "\tldi\t%d,ar0\n", (BLOCKNO) >> 16); \
+           fprintf (FILE, "\tlsh\t16,ar0\n");                  \
+           fprintf (FILE, "\tor\t%d,ar0\n", (BLOCKNO));        \
+         }                                                     \
+       else                                                    \
+         {                                                     \
+           fprintf (FILE, "\tldiu\t%d,ar0\n", (BLOCKNO));      \
+         }                                                     \
+       fprintf (FILE, "\tsti\tar0,*ar2\n");                    \
+       fprintf (FILE, "\tldiu\t^LPBX0,ar0\n");                 \
+       fprintf (FILE, "\tlsh\t16,ar0\n");                      \
+       fprintf (FILE, "\tor\t#LPBX0,ar0\n");                   \
+       fprintf (FILE, "\tsti\tar0,*+ar2(1)\n");                \
+       fprintf (FILE, "\tcall\t___bb_trace_func\n");           \
+       fprintf (FILE, "\tpop\tar0\n");                         \
+        fprintf (FILE, "\tpop\tar2\n");                                \
+       fprintf (FILE, "\tpop\tst\n");                          \
+      }                                                                \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      if (!TARGET_C3X)                                         \
+      {                                                                \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tpush\tar0\n");                        \
+       fprintf (FILE, "\tldhi\t^LPBX2+%d,ar2\n", (BLOCKNO));   \
+       fprintf (FILE, "\tor\t#LPBX2+%d,ar2\n", (BLOCKNO));     \
+       fprintf (FILE, "\taddi3\t1,*ar2,ar0\n");                \
+       fprintf (FILE, "\tsti\tar0,*ar2\n");                    \
+       fprintf (FILE, "\tpop\tar0\n");                         \
+        fprintf (FILE, "\tpop\tar2\n");                                \
+      }                                                                \
+      else                                                     \
+      {                                                                \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tpush\tar0\n");                        \
+       fprintf (FILE, "\tldiu\t^LPBX2+%d,ar2\n", (BLOCKNO));   \
+       fprintf (FILE, "\tlsh\t16,ar2\n");                      \
+       fprintf (FILE, "\tor\t#LPBX2+%d,ar2\n", (BLOCKNO));     \
+       fprintf (FILE, "\tldiu\t*ar2,ar0\n");                   \
+       fprintf (FILE, "\taddi\t1,ar0\n");                      \
+       fprintf (FILE, "\tsti\tar0,*ar2\n");                    \
+       fprintf (FILE, "\tpop\tar0\n");                         \
+        fprintf (FILE, "\tpop\tar2\n");                                \
+      }                                                                \
+    }
+
+#define FUNCTION_BLOCK_PROFILER_EXIT(FILE)                     \
+    {                                                          \
+       fprintf (FILE, "\tpush\tst\n");                         \
+       fprintf (FILE, "\tpush\tar2\n");                        \
+       fprintf (FILE, "\tcall\t___bb_trace_ret\n");            \
+       fprintf (FILE, "\tpop\tar2\n");                         \
+       fprintf (FILE, "\tpop\tst\n");                          \
+    }
+
+#define        MACHINE_STATE_SAVE(ID)          \
+       asm("   push    r0");           \
+       asm("   pushf   r0");           \
+       asm("   push    r1");           \
+       asm("   pushf   r1");           \
+       asm("   push    r2");           \
+       asm("   pushf   r2");           \
+       asm("   push    r3");           \
+       asm("   pushf   r3");           \
+       asm("   push    ar0");          \
+       asm("   push    ar1");          \
+       asm("   .if     .BIGMODEL");    \
+       asm("   push    dp");           \
+       asm("   .endif");               \
+       asm("   push    ir0");          \
+       asm("   push    ir1");          \
+       asm("   push    bk");           \
+       asm("   push    rs");           \
+       asm("   push    re");           \
+       asm("   push    rc");           \
+       asm("   .if     .tms320C40");   \
+       asm("   push    r9");           \
+       asm("   pushf   r9");           \
+       asm("   push    r10");          \
+       asm("   pushf   r10");          \
+       asm("   push    r11");          \
+       asm("   pushf   r11");          \
+       asm("   .endif");
+
+#define        MACHINE_STATE_RESTORE(ID)       \
+       asm("   .if     .tms320C40");   \
+       asm("   popf    r11");          \
+       asm("   pop     r11");          \
+       asm("   popf    r10");          \
+       asm("   pop     r10");          \
+       asm("   popf    r9");           \
+       asm("   pop     r9");           \
+       asm("   .endif");               \
+       asm("   pop     rc");           \
+       asm("   pop     re");           \
+       asm("   pop     rs");           \
+       asm("   pop     bk");           \
+       asm("   pop     ir1");          \
+       asm("   pop     ir0");          \
+       asm("   .if     .BIGMODEL");    \
+       asm("   pop     dp");           \
+       asm("   .endif");               \
+       asm("   pop     ar1");          \
+       asm("   pop     ar0");          \
+       asm("   popf    r3");           \
+       asm("   pop     r3");           \
+       asm("   popf    r2");           \
+       asm("   pop     r2");           \
+       asm("   popf    r1");           \
+       asm("   pop     r1");           \
+       asm("   popf    r0");           \
+       asm("   pop     r0");           \
+
+/* Implicit Calls to Library Routines  */
+
+#define MULQI3_LIBCALL      "__mulqi3"
+#define DIVQI3_LIBCALL      "__divqi3"
+#define UDIVQI3_LIBCALL     "__udivqi3"
+#define MODQI3_LIBCALL      "__modqi3"
+#define UMODQI3_LIBCALL     "__umodqi3"
+
+#define DIVQF3_LIBCALL      "__divqf3"
+
+#define MULHF3_LIBCALL      "__mulhf3"
+#define DIVHF3_LIBCALL      "__divhf3"
+
+#define MULHI3_LIBCALL      "__mulhi3"
+#define SMULHI3_LIBCALL     "__smulhi3_high"
+#define UMULHI3_LIBCALL     "__umulhi3_high"
+#define DIVHI3_LIBCALL      "__divhi3"
+#define UDIVHI3_LIBCALL     "__udivhi3"
+#define MODHI3_LIBCALL      "__modhi3"
+#define UMODHI3_LIBCALL     "__umodhi3"
+
+#define FLOATHIQF2_LIBCALL  "__floathiqf2"
+#define FLOATUNSHIQF2_LIBCALL  "__ufloathiqf2"
+#define FIX_TRUNCQFHI2_LIBCALL "__fix_truncqfhi2"
+#define FIXUNS_TRUNCQFHI2_LIBCALL "__ufix_truncqfhi2"
+
+#define FLOATHIHF2_LIBCALL  "__floathihf2"
+#define FLOATUNSHIHF2_LIBCALL  "__ufloathihf2"
+#define FIX_TRUNCHFHI2_LIBCALL "__fix_trunchfhi2"
+#define FIXUNS_TRUNCHFHI2_LIBCALL "__ufix_trunchfhi2"
+
+#define FFS_LIBCALL        "__ffs"
+
+#define TARGET_MEM_FUNCTIONS
+
+/* Add any extra modes needed to represent the condition code.
+
+   On the C4x, we have a "no-overflow" mode which is used when an ADD,
+   SUB, NEG, or MPY insn is used to set the condition code.  This is
+   to prevent the combiner from optimising away a following CMP of the
+   result with zero when a signed conditional branch or load insn
+   follows.
+
+   The problem is a subtle one and deals with the manner in which the
+   negative condition (N) flag is used on the C4x.  This flag does not
+   reflect the status of the actual result but of the ideal result had
+   no overflow occured (when considering signed operands).
+
+   For example, 0x7fffffff + 1 => 0x80000000 Z=0 V=1 N=0 C=0.  Here
+   the flags reflect the untruncated result, not the actual result.
+   While the actual result is less than zero, the N flag is not set
+   since the ideal result of the addition without truncation would
+   have been positive.
+   
+   Note that the while the N flag is handled differently to most other
+   architectures, the use of it is self consistent and is not the
+   cause of the problem.
+
+   Logical operations set the N flag to the MSB of the result so if
+   the result is negative, N is 1.  However, integer and floating
+   point operations set the N flag to be the MSB of the result
+   exclusive ored with the overflow (V) flag.  Thus if an overflow
+   occurs and the result does not have the MSB set (i.e., the result
+   looks like a positive number), the N flag is set.  Conversely, if
+   an overflow occurs and the MSB of the result is set, N is set to 0.
+   Thus the N flag represents the sign of the result if it could have
+   been stored without overflow but does not represent the apparent
+   sign of the result.  Note that most architectures set the N flag to
+   be the MSB of the result.
+
+   The C4x approach to setting the N flag simplifies signed
+   conditional branches and loads which only have to test the state of
+   the N flag, whereas most architectures have to look at both the N
+   and V flags.  The disadvantage is that there is no flag giving the
+   status of the sign bit of the operation.  However, there are no
+   conditional load or branch instructions that make use of this
+   feature (e.g., BMI---branch minus) instruction.  Note that BN and
+   BLT are identical in the C4x.
+   
+   To handle the problem where the N flag is set differently whenever
+   there is an overflow we use a different CC mode, CC_NOOVmode which
+   says that the CC reflects the comparison of the result against zero
+   if no overflow occured.
+
+   For example, 
+
+   [(set (reg:CC_NOOV 21)
+         (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "")
+                                    (match_operand:QI 2 "src_operand" ""))
+                          (const_int 0)))
+    (set (match_operand:QI 0 "ext_reg_operand" "")
+         (minus:QI (match_dup 1)
+                   (match_dup 2)))]
+
+   Note that there is no problem for insns that don't return a result
+   like CMP, since the CC reflects the effect of operation.
+
+   An example of a potential problem is when GCC
+   converts   (LTU (MINUS (0x80000000) (0x7fffffff) (0x80000000)))
+   to         (LEU (MINUS (0x80000000) (0x7fffffff) (0x7fffffff)))
+   to         (GE  (MINUS (0x80000000) (0x7fffffff) (0x00000000)))
+
+   Now (MINUS (0x80000000) (0x7fffffff)) returns 0x00000001 but the
+   C4x sets the N flag since the result without overflow would have
+   been 0xffffffff when treating the operands as signed integers.
+   Thus (GE (MINUS (0x80000000) (0x7fffffff) (0x00000000))) sets the N
+   flag but (GE (0x00000001)) does not set the N flag.
+
+   The upshot is that we can not use signed branch and conditional
+   load instructions after an add, subtract, neg, abs or multiply.
+   We must emit a compare insn to check the result against 0.  */
+
+#define EXTRA_CC_MODES CC_NOOVmode
+
+/* Define the names for the modes specified above.  */
+
+#define EXTRA_CC_NAMES "CC_NOOV"
+
+/* CC_NOOVmode should be used when the first operand is a PLUS, MINUS, NEG
+   or MULT.
+   CCmode should be used when no special processing is needed. */
+#define SELECT_CC_MODE(OP,X,Y) \
+  ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS              \
+    || GET_CODE (X) == NEG || GET_CODE (X) == MULT             \
+    || GET_MODE (X) == ABS                                     \
+    || GET_CODE (Y) == PLUS || GET_CODE (Y) == MINUS           \
+    || GET_CODE (Y) == NEG || GET_CODE (Y) == MULT             \
+    || GET_MODE (Y) == ABS)                                    \
+    ? CC_NOOVmode : CCmode)
+
+extern struct rtx_def *c4x_gen_compare_reg ();
+
+/* Addressing Modes  */
+
+#define HAVE_POST_INCREMENT
+#define HAVE_PRE_INCREMENT
+#define HAVE_POST_DECREMENT
+#define HAVE_PRE_DECREMENT
+#define HAVE_PRE_MODIFY_REG
+#define HAVE_POST_MODIFY_REG
+#define HAVE_PRE_MODIFY_DISP
+#define HAVE_POST_MODIFY_DISP
+
+/* What about LABEL_REF?  */
+#define CONSTANT_ADDRESS_P(X) (GET_CODE (X) == SYMBOL_REF)
+
+#define MAX_REGS_PER_ADDRESS   2
+
+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
+   and check its validity for a certain class.
+   We have two alternate definitions for each of them.
+   The usual definition accepts all pseudo regs; the other rejects
+   them unless they have been allocated suitable hard regs.
+   The symbol REG_OK_STRICT causes the latter definition to be used.
+
+   Most source files want to accept pseudo regs in the hope that
+   they will get allocated to the class that the insn wants them to be in.
+   Source files for reload pass need to be strict.
+   After reload, it makes no difference, since pseudo regs have
+   been eliminated by then.  */
+
+extern int c4x_check_legit_addr ();
+
+#ifndef REG_OK_STRICT
+
+/* Nonzero if X is a hard or pseudo reg that can be used as an base.  */
+
+#define REG_OK_FOR_BASE_P(X) IS_ADDR_OR_PSEUDO_REG(REGNO(X))
+
+/* Nonzero if X is a hard or pseudo reg that can be used as an index.  */
+
+#define REG_OK_FOR_INDEX_P(X) IS_INDEX_OR_PSEUDO_REG(REGNO(X))
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)                                \
+{                                                                      \
+  if (c4x_check_legit_addr (MODE, X, 0))                               \
+    goto ADDR;                                                         \
+}
+
+#else
+
+/* Nonzero if X is a hard reg that can be used as an index.  */
+
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+
+/* Nonzero if X is a hard reg that can be used as a base reg.  */
+
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)                                \
+{                                                                      \
+  if (c4x_check_legit_addr (MODE, X, 1))                               \
+    goto ADDR;                                                         \
+}
+
+#endif
+
+extern struct rtx_def *c4x_legitimize_address ();
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
+{                                                                      \
+  rtx new;                                                             \
+  new = c4x_legitimize_address (X, MODE);                              \
+  if (new != NULL_RTX)                                                 \
+  {                                                                    \
+    (X) = new;                                                         \
+    goto WIN;                                                          \
+  }                                                                    \
+}
+
+
+/* No mode-dependent addresses on the C4x are autoincrements.  */
+
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)      \
+  if (GET_CODE (ADDR) == PRE_DEC       \
+      || GET_CODE (ADDR) == POST_DEC   \
+      || GET_CODE (ADDR) == PRE_INC    \
+      || GET_CODE (ADDR) == POST_INC   \
+      || GET_CODE (ADDR) == POST_MODIFY        \
+      || GET_CODE (ADDR) == PRE_MODIFY)        \
+    goto LABEL
+
+
+/* Nonzero if the constant value X is a legitimate general operand.
+   It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. 
+
+   The C4x can only load 16-bit immediate values, so we only allow
+   a restricted subset of CONST_INT and CONST_DOUBLE and reject
+   LABEL_REF, SYMBOL_REF, CONST, and HIGH codes.  */
+
+#define LEGITIMATE_CONSTANT_P(X)                               \
+  (GET_CODE (X) == CONST_DOUBLE && c4x_H_constant (X)          \
+  || GET_CODE (X) == CONST_INT && c4x_I_constant (X))
+
+
+#define LEGITIMATE_DISPLACEMENT_P(X) IS_DISP8_CONST (INTVAL (X))
+
+/* Descripting Relative Cost of Operations  */
+
+/* Provide the costs of a rtl expression.  This is in the body of a
+   switch on CODE. 
+
+   Note that we return, rather than break so that rtx_cost doesn't
+   include CONST_COSTS otherwise expand_mult will think that it is
+   cheaper to synthesise a multiply rather than to use a multiply
+   instruction.  I think this is because the algorithm synth_mult
+   doesn't take into account the loading of the operands, whereas the
+   calculation of mult_cost does. 
+*/
+
+
+#define RTX_COSTS(RTX, CODE, OUTER_CODE)                               \
+    case MULT:                                                         \
+    return COSTS_N_INSNS (GET_MODE_CLASS (GET_MODE (RTX)) == MODE_FLOAT \
+                         || TARGET_MPYI ? 1 : 14);                     \
+    case DIV:  case UDIV: case MOD: case UMOD:                                 \
+    return COSTS_N_INSNS (GET_MODE_CLASS (GET_MODE (RTX)) == MODE_FLOAT        \
+                         ? 15 : 50);
+
+/* Compute the cost of computing a constant rtl expression RTX
+   whose rtx-code is CODE.  The body of this macro is a portion
+   of a switch statement.  If the code is computed here,
+   return it with a return statement.  Otherwise, break from the switch.
+
+   An insn is assumed to cost 4 units.
+   COSTS_N_INSNS (N) is defined as (N) * 4 - 2.
+
+   Some small integers are effectively free for the C40.  We should
+   also consider if we are using the small memory model.  With
+   the big memory model we require an extra insn for a constant
+   loaded from memory.  */
+
+#define SHIFT_CODE_P(C) ((C) == ASHIFT || (C) == ASHIFTRT || (C) == LSHIFTRT)
+
+#define LOGICAL_CODE_P(C) ((C) == NOT || (C) == AND \
+                           || (C) == IOR || (C) == XOR)
+
+#define NON_COMMUTATIVE_CODE_P ((C) == MINUS || (C) == COMPARE)
+
+#define CONST_COSTS(RTX,CODE,OUTER_CODE)                       \
+       case CONST_INT:                                         \
+           if (c4x_J_constant (RTX))                           \
+            return 0;                                          \
+           if (TARGET_C3X && SHIFT_CODE_P (OUTER_CODE))                \
+            return 3;                                          \
+           if (LOGICAL_CODE_P (OUTER_CODE)                     \
+               ? c4x_L_constant (RTX) : c4x_I_constant (RTX))  \
+            return 2;                                          \
+       case CONST:                                             \
+       case LABEL_REF:                                         \
+       case SYMBOL_REF:                                        \
+          return 4;                                            \
+       case CONST_DOUBLE:                                      \
+          if (c4x_H_constant (RTX))                            \
+            return 2;                                          \
+           if (GET_MODE (RTX) == QFmode)                       \
+            return 4;                                          \
+           else                                                        \
+            return 8;
+
+/* Compute the cost of an address.  This is meant to approximate the size
+   and/or execution delay of an insn using that address.  If the cost is
+   approximated by the RTL complexity, including CONST_COSTS above, as
+   is usually the case for CISC machines, this macro should not be defined.
+   For aggressively RISCy machines, only one insn format is allowed, so
+   this macro should be a constant.  The value of this macro only matters
+   for valid addresses.  We handle the most common address without 
+   a call to c4x_address_cost.  */
+
+extern int c4x_address_cost ();
+
+#define ADDRESS_COST(ADDR) (REG_P (ADDR) ? 1 : c4x_address_cost (ADDR))
+
+#define        CANONICALIZE_COMPARISON(CODE, OP0, OP1)         \
+if (REG_P (OP1) && ! REG_P (OP0))                      \
+{                                                      \
+  rtx tmp = OP0; OP0 = OP1 ; OP1 = tmp;                        \
+  CODE = swap_condition (CODE);                                \
+}
+
+#define EXT_CLASS_P(CLASS) (reg_class_subset_p (CLASS, EXT_REGS))
+#define ADDR_CLASS_P(CLASS) (reg_class_subset_p (CLASS, ADDR_REGS))
+#define INDEX_CLASS_P(CLASS) (reg_class_subset_p (CLASS, INDEX_REGS))
+#define EXPENSIVE_CLASS_P(CLASS) (ADDR_CLASS_P(CLASS) \
+                          || INDEX_CLASS_P(CLASS) || (CLASS) == SP_REG)
+
+/* Make the Rx register a little easier to use so they are used for
+   calculations and the ARx registers are used for addressing. */
+
+#define REGISTER_MOVE_COST(FROM, TO) \
+(EXPENSIVE_CLASS_P(TO) ? 5 : EXPENSIVE_CLASS_P(FROM) ? 4 : 3)
+
+/* Memory move cost is same as fast register move.  Maybe this should
+   be bumped up? */
+
+#define MEMORY_MOVE_COST(M,C,I)                4
+
+/* Branches are kind of expensive (even with delayed branching) so
+   make their cost higher.  */
+
+#define BRANCH_COST                    8
+
+/* Adjust the cost of dependencies.  */
+
+#define ADJUST_COST(INSN,LINK,DEP,COST) \
+  (COST) = c4x_adjust_cost (INSN, LINK, DEP, COST)
+
+#define        WORD_REGISTER_OPERATIONS
+
+/* Dividing the Output into Sections  */
+
+#define TEXT_SECTION_ASM_OP "\t.text"
+
+#define DATA_SECTION_ASM_OP "\t.data"
+
+#define USE_CONST_SECTION 1
+
+#define CONST_SECTION_ASM_OP "\t.sect\t\".const\""
+
+/* Do not use .init section so __main will be called on startup. This will
+   call __do_global_ctors and prepare for __do_global_dtors on exit. */
+
+#if 0
+#define INIT_SECTION_ASM_OP  "\t.sect\t\".init\""
+#endif
+
+#define FINI_SECTION_ASM_OP  "\t.sect\t\".fini\""
+
+/* Support const sections and the ctors and dtors sections for g++.
+   Note that there appears to be two different ways to support const
+   sections at the moment.  You can either #define the symbol
+   READONLY_DATA_SECTION (giving it some code which switches to the
+   readonly data section) or else you can #define the symbols
+   EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS, SELECT_SECTION, and
+   SELECT_RTX_SECTION.  We do both here just to be on the safe side. */
+
+/* Define a few machine-specific details of the implementation of
+   constructors.
+
+   The __CTORS_LIST__ goes in the .ctors section.  Define CTOR_LIST_BEGIN
+   and CTOR_LIST_END to contribute to the .ctors section an instruction to
+   push a word containing 0 (or some equivalent of that).
+
+   Define ASM_OUTPUT_CONSTRUCTOR to push the address of the constructor.  */
+
+#define CTORS_SECTION_ASM_OP   "\t.sect\t\".ctors\""
+#define DTORS_SECTION_ASM_OP    "\t.sect\t\".dtors\""
+
+/* Constructor list on stack is in reverse order.  Go to the end of the
+   list and go backwards to call constructors in the right order.  */
+
+#define DO_GLOBAL_CTORS_BODY                                   \
+do {                                                           \
+  extern func_ptr __CTOR_LIST__[];                             \
+  func_ptr *p, *beg = __CTOR_LIST__ + 1;                       \
+  for (p = beg; *p ; p++) ;                                    \
+  while (p != beg)                                             \
+    (*--p) ();                                                 \
+} while (0)
+
+/* The TI tooling uses atexit. */
+#define        ON_EXIT(FUNC,ARG)       atexit (FUNC)
+
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_const, in_init, in_fini, in_ctors, in_dtors
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS                                        \
+  CONST_SECTION_FUNCTION                                       \
+  INIT_SECTION_FUNCTION                                                \
+  FINI_SECTION_FUNCTION                                                \
+  CTORS_SECTION_FUNCTION                                       \
+  DTORS_SECTION_FUNCTION
+
+#define INIT_SECTION_FUNCTION                                  \
+void                                                           \
+init_section ()                                                        \
+{                                                              \
+  if (in_section != in_init)                                   \
+    {                                                          \
+      fprintf (asm_out_file, ";\t.init\n");                    \
+      in_section = in_init;                                    \
+    }                                                          \
+}
+
+#define FINI_SECTION_FUNCTION                                  \
+void                                                           \
+fini_section ()                                                        \
+{                                                              \
+  if (in_section != in_fini)                                   \
+    {                                                          \
+      fprintf (asm_out_file, "\t%s\n", FINI_SECTION_ASM_OP);   \
+      in_section = in_fini;                                    \
+    }                                                          \
+}
+
+#define READONLY_DATA_SECTION() const_section ()
+
+#define CONST_SECTION_FUNCTION                                         \
+void                                                                   \
+const_section ()                                                       \
+{                                                                      \
+  extern void text_section();                                          \
+  if (!USE_CONST_SECTION)                                              \
+    text_section();                                                    \
+  else if (in_section != in_const)                                     \
+    {                                                                  \
+      fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP);            \
+      in_section = in_const;                                           \
+    }                                                                  \
+}
+
+#define ASM_STABS_OP "\t.stabs"
+
+/* The ctors and dtors sections are not normally put into use 
+   by EXTRA_SECTIONS and EXTRA_SECTION_FUNCTIONS as defined in svr3.h,
+   but it can't hurt to define these macros for whatever systems use them.  */
+
+#define CTORS_SECTION_FUNCTION                                         \
+void                                                                   \
+ctors_section ()                                                       \
+{                                                                      \
+  if (in_section != in_ctors)                                          \
+    {                                                                  \
+      fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP);            \
+      in_section = in_ctors;                                           \
+    }                                                                  \
+}
+
+#define DTORS_SECTION_FUNCTION                                         \
+void                                                                   \
+dtors_section ()                                                       \
+{                                                                      \
+  if (in_section != in_dtors)                                          \
+    {                                                                  \
+      fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP);            \
+      in_section = in_dtors;                                           \
+    }                                                                  \
+}
+
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+   fprintf (FILE, "\t.sect\t\"%s\"\n", NAME);
+
+/* This is machine-dependent because it needs to push something
+   on the stack.  */
+
+/* A C statement (sans semicolon) to output an element in the table of
+   global constructors.  */
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME)                              \
+  do {                                                                 \
+    ctors_section ();                                                  \
+    fprintf (FILE, "\t.word\t ");                                      \
+    assemble_name (FILE, NAME);                                                \
+    fprintf (FILE, "\n");                                              \
+  } while (0)
+
+/* A C statement (sans semicolon) to output an element in the table of
+   global destructors.  */
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME)                                       \
+  do {                                                                 \
+    dtors_section ();                                                  \
+    fprintf (FILE, "\t.word\t ");                                      \
+    assemble_name (FILE, NAME);                                        \
+    fprintf (FILE, "\n");                                              \
+  } while (0)
+
+/* A C statement or statements to switch to the appropriate
+   section for output of DECL.  DECL is either a `VAR_DECL' node
+   or a constant of some sort.  RELOC indicates whether forming
+   the initial value of DECL requires link-time relocations.  */
+
+#define SELECT_SECTION(DECL, RELOC)                                    \
+{                                                                      \
+  if (TREE_CODE (DECL) == STRING_CST)                                  \
+    {                                                                  \
+      if (! flag_writable_strings)                                     \
+       const_section ();                                               \
+      else                                                             \
+       data_section ();                                                \
+    }                                                                  \
+  else if (TREE_CODE (DECL) == VAR_DECL)                               \
+    {                                                                  \
+      if ((0 && RELOC) /* should be (flag_pic && RELOC) */             \
+         || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL)          \
+         || !DECL_INITIAL (DECL)                                       \
+         || (DECL_INITIAL (DECL) != error_mark_node                    \
+             && !TREE_CONSTANT (DECL_INITIAL (DECL))))                 \
+       data_section ();                                                \
+      else                                                             \
+       const_section ();                                               \
+    }                                                                  \
+  else                                                                 \
+    const_section ();                                                  \
+}
+
+/* A C statement or statements to switch to the appropriate
+   section for output of RTX in mode MODE.  RTX is some kind
+   of constant in RTL.  The argument MODE is redundant except
+   in the case of a `const_int' rtx.  Currently, these always
+   go into the const section.  */
+
+#define SELECT_RTX_SECTION(MODE, RTX) const_section()
+
+
+/* Overall Framework of an Assembler File  */
+
+#define ASM_FILE_START(FILE)                                   \
+{                                                              \
+    int dspversion = 0;                                                \
+    if (TARGET_C30) dspversion = 30;                           \
+    if (TARGET_C31) dspversion = 31;                           \
+    if (TARGET_C32) dspversion = 32;                           \
+    if (TARGET_C40) dspversion = 40;                           \
+    if (TARGET_C44) dspversion = 44;                           \
+    fprintf (FILE, "\t.version\t%d\n", dspversion);            \
+    fprintf (FILE, "\t.file\t");                               \
+    if (TARGET_TI)                                             \
+      {                                                                \
+        char *p;                                               \
+        char *after_dir = main_input_filename;                 \
+       for (p = main_input_filename; *p; p++)                  \
+         if (*p == '/')                                        \
+           after_dir = p + 1;                                  \
+       output_quoted_string (FILE, after_dir);                 \
+      }                                                                \
+    else                                                       \
+      output_quoted_string (FILE, main_input_filename);                \
+    fprintf (FILE, "\n");                                      \
+}
+
+#define ASM_FILE_END(FILE)   fprintf (FILE, "\t.end\n")
+
+/* We need to have a data section we can identify so that we can set
+   the DP register back to a data pointer in the small memory model.
+   This is only required for ISRs if we are paranoid that someone
+   may have quietly changed this register on the sly. */
+
+#define ASM_IDENTIFY_GCC(FILE) \
+    if (!TARGET_TI) fputs ("gcc2_compiled.:\n", FILE); \
+      fputs ("\t.data\ndata_sec:\n", FILE);
+
+#define ASM_COMMENT_START      ";"
+
+#define ASM_APP_ON ""
+#define ASM_APP_OFF ""
+
+/* Output float/double constants  QFmode.  */
+
+#define ASM_OUTPUT_BYTE_FLOAT(FILE, VALUE)             \
+{   long l;                                            \
+    char str[30];                                      \
+    REAL_VALUE_TO_TARGET_SINGLE (VALUE, l);            \
+    REAL_VALUE_TO_DECIMAL (VALUE, "%20f", str);                \
+    if (sizeof (int) == sizeof (long))                 \
+      fprintf (FILE, "\t.word\t0%08xh\t; %s\n", l, str);\
+    else                                               \
+      fprintf (FILE, "\t.word\t0%08lxh\t; %s\n", l, str);\
+}
+
+/* Output long double constants  HFmode. 
+   The first word contains the exponent and first part of the mantissa
+   in the same manner as QFmode.  The second word contains the full
+   mantissa.  We should ensure that the two words are allocated within
+   the same page for the large memory model since we only output a single
+   LDP instruction.  FIXME.  The simplest solution probably is to output
+   a LDP for each load.  */
+
+#define ASM_OUTPUT_SHORT_FLOAT(FILE, VALUE)            \
+{   long l[2];                                         \
+    char str[30];                                      \
+    REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l);            \
+    REAL_VALUE_TO_DECIMAL (VALUE, "%20f", str);                \
+    l[1] = (l[0] << 8) | ((l[1] >> 24) & 0xff);                \
+    if (sizeof (int) == sizeof (long))                 \
+      fprintf (FILE, "\t.word\t0%08xh\t; %s\n\t.word\t0%08xh\n", \
+               l[0], str, l[1]);                               \
+    else                                                       \
+      fprintf (FILE, "\t.word\t0%08lxh\t; %s\n\t.word\t0%08lxh\n", \
+               l[0], str, l[1]);                               \
+}
+
+#define ASM_OUTPUT_CHAR(FILE, VALUE)                   \
+{    fprintf (FILE, "\t.word\t");                      \
+     output_addr_const (FILE, VALUE);                  \
+     if (GET_CODE (VALUE) != SYMBOL_REF)               \
+       fprintf (FILE, " ; 0%08xh\n", INTVAL (VALUE));  \
+     else                                              \
+       fputc ('\n', FILE);                             \
+}
+
+#define ASM_OUTPUT_BYTE(FILE, VALUE)  \
+  fprintf (FILE, "\t.word\t0%xh\n", (VALUE))
+
+extern void c4x_output_ascii ();
+#define ASM_OUTPUT_ASCII(FILE, PTR, LEN) c4x_output_ascii (FILE, PTR, LEN)
+
+#define ASM_OPEN_PAREN "("
+#define ASM_CLOSE_PAREN ")"
+
+
+/* Output and Generation of Labels  */
+
+#define NO_DOT_IN_LABEL                /* Only required for TI format */
+
+#define ASM_OUTPUT_LABEL(FILE, NAME)   \
+{ assemble_name (FILE, NAME); fputs (":\n", FILE); }
+
+#define ASM_GLOBALIZE_LABEL(FILE, NAME) \
+{                                       \
+    fprintf (FILE, "\t.global\t");     \
+    assemble_name (FILE, NAME);                \
+    fputs ("\n", FILE);                \
+}
+
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME)  \
+{                                              \
+    fprintf (FILE, "\t.ref\t");                        \
+    assemble_name (FILE, NAME);                        \
+    fputc ('\n', FILE);                        \
+}
+
+/* A C statement to output on FILE an assembler pseudo-op to
+   declare a library function named external.
+   (Only needed to keep asm30 happy for ___divqf3 etc.) */
+
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN)  \
+{                                              \
+    fprintf (FILE, "\t.ref\t");                        \
+    assemble_name (FILE, XSTR (FUN, 0));       \
+    fprintf (FILE, "\n");                      \
+}
+
+/* The prefix to add to user-visible assembler symbols.  */
+
+#define USER_LABEL_PREFIX "_"
+
+/* This is how to output an internal numbered label where
+   PREFIX is the class of label and NUM is the number within the class.  */
+
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE, PREFIX, NUM)   \
+asm_fprintf (FILE, "%s%d:\n", PREFIX, NUM)
+
+/* This is how to store into the string LABEL
+   the symbol_ref name of an internal numbered label where
+   PREFIX is the class of label and NUM is the number within the class.
+   This is suitable for output with `assemble_name'.  */
+
+#define ASM_GENERATE_INTERNAL_LABEL(BUFFER, PREFIX, NUM) \
+    sprintf (BUFFER, "*%s%d", PREFIX, NUM)
+
+/* Store in OUTPUT a string (made with alloca) containing
+   an assembler-name for a local static variable named NAME.
+   LABELNO is an integer which is different for each call.  */
+
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO)  \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10),    \
+  sprintf ((OUTPUT), "%s%d", (NAME), (LABELNO)))
+
+
+/* Output of Dispatch Tables  */
+
+/* This is how to output an element of a case-vector that is absolute.  */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+    fprintf (FILE, "\t.long\tL%d\n", VALUE);
+
+/* This is how to output an element of a case-vector that is relative.  */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+    fprintf (FILE, "\t.long\tL%d-L%d\n", VALUE, REL);
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+#define INT_TYPE_SIZE          32
+#define LONG_LONG_TYPE_SIZE    64
+#define FLOAT_TYPE_SIZE                32
+#define DOUBLE_TYPE_SIZE       32
+#define LONG_DOUBLE_TYPE_SIZE  64 /* actually only 40 */
+
+/* Allow #sccs in preprocessor.  */
+
+#define SCCS_DIRECTIVE
+
+/* Output #ident as a .ident.  */
+
+#define ASM_OUTPUT_IDENT(FILE, NAME) \
+  fprintf (FILE, "\t.ident \"%s\"\n", NAME);
+
+#define CPP_PREDEFINES ""
+
+/* This says how to output an assembler line
+   to define a local common symbol.  */
+
+#undef ASM_OUTPUT_LOCAL
+#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED)  \
+( fputs ("\t.bss\t", FILE),                    \
+  assemble_name (FILE, (NAME)),                \
+  fprintf (FILE, ",%u\n", (ROUNDED)))
+
+/* Output of Uninitialized Variables  */
+
+#undef ASM_OUTPUT_COMMON
+#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED)  \
+(  fputs ("\t.globl\t", FILE), \
+   assemble_name (FILE, (NAME)),       \
+   fputs ("\n\t.bss\t", FILE), \
+   assemble_name (FILE, (NAME)),       \
+   fprintf (FILE, ",%u\n", (ROUNDED)))
+
+/* Macros Controlling Initialization Routines  */
+
+#define OBJECT_FORMAT_COFF
+#define REAL_NM_FILE_NAME "c4x-nm"
+
+/* Output of Assembler Instructions  */
+
+/* Register names when used for integer modes.  */
+
+#define REGISTER_NAMES \
+{                                                              \
+ "r0",   "r1", "r2",   "r3",  "r4",  "r5",  "r6",  "r7",       \
+ "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7",       \
+ "dp",  "ir0", "ir1",  "bk",  "sp",  "st", "die", "iie",       \
+ "iif",         "rs",  "re",  "rc",  "r8",  "r9", "r10", "r11"         \
+}
+
+/* Alternate register names when used for floating point modes.  */
+
+#define FLOAT_REGISTER_NAMES \
+{                                                              \
+ "f0",   "f1", "f2",   "f3",  "f4",  "f5",  "f6",  "f7",       \
+ "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7",       \
+ "dp",  "ir0", "ir1",  "bk",  "sp",  "st", "die", "iie",       \
+ "iif",         "rs",  "re",  "rc",  "f8",  "f9", "f10", "f11"         \
+}
+
+
+extern void c4x_print_operand ();
+#define PRINT_OPERAND(FILE, X, CODE) c4x_print_operand(FILE, X, CODE)
+
+/* Determine which codes are valid without a following integer.  These must
+   not be alphabetic. */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '#')
+
+extern void c4x_print_operand_address ();
+#define PRINT_OPERAND_ADDRESS(FILE, X) c4x_print_operand_address(FILE, X)
+
+/* Define this macro if you want to implement any pragmas.  If defined, it
+   should be a C expression to be executed when #pragma is seen.  The
+   argument STREAM is the stdio input stream from which the source
+   text can be read.  CH is the first character after the #pragma.  The
+   result of the expression is the terminating character found
+   (newline or EOF).  */
+extern int c4x_handle_pragma ();
+#define HANDLE_PRAGMA(GETC, UNGETC, NAME) \
+  c4x_handle_pragma (GETC, UNGETC, NAME)
+
+extern void c4x_set_default_attributes ();
+#define SET_DEFAULT_DECL_ATTRIBUTES(DECL, ATTRIBUTES) \
+  c4x_set_default_attributes (DECL, &ATTRIBUTES)
+
+extern int c4x_valid_type_attribute_p ();
+#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \
+  (c4x_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS))
+
+/* Assembler Commands for Alignment  */
+
+#define ASM_OUTPUT_SKIP(FILE, SIZE) \
+{ int c = SIZE; \
+  for (; c > 0; --c) \
+   fprintf (FILE,"\t.word\t0\n"); \
+}
+
+#define ASM_NO_SKIP_IN_TEXT 1
+
+/* I'm not sure about this one.  FIXME. */
+
+#define ASM_OUTPUT_ALIGN(FILE, LOG)    \
+  if ((LOG) != 0)                      \
+    fprintf (FILE, "\t.align\t%d\n", (1 << (LOG)))
+
+
+/* Macros for SDB and DWARF Output  (use .sdef instead of .def
+   to avoid conflict with TI's use of .def)  */
+
+#define SDB_DELIM "\n"
+#define SDB_DEBUGGING_INFO
+
+#define PUT_SDB_DEF(A)                         \
+do { fprintf (asm_out_file, "\t.sdef\t");      \
+     ASM_OUTPUT_LABELREF (asm_out_file, A);    \
+     fprintf (asm_out_file, SDB_DELIM); } while (0)
+
+#define PUT_SDB_PLAIN_DEF(A)                   \
+  fprintf (asm_out_file,"\t.sdef\t.%s%s", A, SDB_DELIM)
+
+#define PUT_SDB_BLOCK_START(LINE)              \
+  fprintf (asm_out_file,                       \
+          "\t.sdef\t.bb%s\t.val\t.%s\t.scl\t100%s\t.line\t%d%s\t.endef\n", \
+          SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM)
+
+#define PUT_SDB_BLOCK_END(LINE)                        \
+  fprintf (asm_out_file,                       \
+          "\t.sdef\t.eb%s\t.val\t.%s\t.scl\t100%s\t.line\t%d%s\t.endef\n", \
+          SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM)
+
+#define PUT_SDB_FUNCTION_START(LINE)           \
+  fprintf (asm_out_file,                       \
+          "\t.sdef\t.bf%s\t.val\t.%s\t.scl\t101%s\t.line\t%d%s\t.endef\n", \
+          SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM)
+
+#define PUT_SDB_FUNCTION_END(LINE)             \
+  fprintf (asm_out_file,                       \
+          "\t.sdef\t.ef%s\t.val\t.%s\t.scl\t101%s\t.line\t%d%s\t.endef\n", \
+          SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM)
+
+#define PUT_SDB_EPILOGUE_END(NAME)                     \
+do { fprintf (asm_out_file, "\t.sdef\t");              \
+     ASM_OUTPUT_LABELREF (asm_out_file, NAME);         \
+     fprintf (asm_out_file,                            \
+             "%s\t.val\t.%s\t.scl\t-1%s\t.endef\n",    \
+             SDB_DELIM, SDB_DELIM, SDB_DELIM); } while (0)
+
+
+/* Define results of standard character escape sequences.  */
+
+#define TARGET_BELL 007
+#define TARGET_BS 010
+#define TARGET_TAB 011
+#define TARGET_NEWLINE 012
+#define TARGET_VT 013
+#define TARGET_FF 014
+#define TARGET_CR 015
+
+/* This is the kind of divide that is easiest to do in the general case.  */
+
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+
+/* Define this as 1 if `char' should by default be signed; else as 0.  */
+
+#define DEFAULT_SIGNED_CHAR 1
+
+/* A function address in a call instruction is a byte address (for
+   indexing purposes) so give the MEM rtx a byte's mode.  */
+
+#define FUNCTION_MODE QImode
+
+#define SLOW_BYTE_ACCESS 0
+
+/* Specify the machine mode that pointers have.  After generation of
+   RTL, the compiler makes no further distinction between pointers and
+   any other objects of this machine mode.  */
+
+#define Pmode QImode
+
+/* On the C4x we can write the following code. We have to clear the cache
+   every time we execute it because the data in the stack could change.
+
+   laj   $+4
+   addi3 4,r11,ar0
+   lda   *ar0,ar1
+   lda   *+ar0(1),ar0
+   bud   ar1
+   nop
+   nop
+   or   1000h,st
+   .word FNADDR
+   .word CXT
+
+   On the c3x this is a bit more difficult. We have to write self
+   modifying code here. So we have to clear the cache every time
+   we execute it because the data in the stack could change.
+
+   ldiu TOP_OF_FUNCTION,ar1
+   lsh  16,ar1
+   or   BOTTOM_OF_FUNCTION,ar1
+   ldiu TOP_OF_STATIC,ar0
+   bud  ar1
+   lsh  16,ar0
+   or   BOTTOM_OF_STATIC,ar0
+   or   1000h,st
+   
+  */
+
+#define TRAMPOLINE_SIZE (TARGET_C3X ? 8 : 10)
+
+#define TRAMPOLINE_TEMPLATE(FILE)                              \
+{                                                              \
+  if (TARGET_C3X)                                              \
+    {                                                          \
+      asm_fprintf (FILE, "\tldiu\t0,ar1\n");                   \
+      asm_fprintf (FILE, "\tlsh\t16,ar1\n");                   \
+      asm_fprintf (FILE, "\tor\t0,ar1\n");                     \
+      asm_fprintf (FILE, "\tldiu\t0,ar0\n");                   \
+      asm_fprintf (FILE, "\tbud\tar1\n");                      \
+      asm_fprintf (FILE, "\tlsh\t16,ar0\n");                   \
+      asm_fprintf (FILE, "\tor\t0,ar0\n");                     \
+      asm_fprintf (FILE, "\tor\t1000h,st\n");                  \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      asm_fprintf (FILE, "\tlaj\t$+4\n");                      \
+      asm_fprintf (FILE, "\taddi3\t4,r11,ar0\n");              \
+      asm_fprintf (FILE, "\tlda\t*ar0,ar1\n");                 \
+      asm_fprintf (FILE, "\tlda\t*+ar0(1),ar0\n");             \
+      asm_fprintf (FILE, "\tbud\tar1\n");                      \
+      asm_fprintf (FILE, "\tnop\n");                           \
+      asm_fprintf (FILE, "\tnop\n");                           \
+      asm_fprintf (FILE, "\tor\t1000h,st\n");                  \
+      asm_fprintf (FILE, "\t.word\t0\n");                      \
+      asm_fprintf (FILE, "\t.word\t0\n");                      \
+    }                                                          \
+}
+
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT)                      \
+{                                                                      \
+  if (TARGET_C3X)                                                      \
+    {                                                                  \
+      rtx tmp1, tmp2;                                                  \
+      tmp1 = expand_shift (RSHIFT_EXPR, QImode, FNADDR,                        \
+                          size_int (16), 0, 1);                        \
+      tmp2 = expand_shift (LSHIFT_EXPR, QImode,                                \
+                          gen_rtx (CONST_INT, VOIDmode, 0x5069),       \
+                          size_int (16), 0, 1);                        \
+      emit_insn (gen_iorqi3 (tmp1, tmp1, tmp2));                       \
+      emit_move_insn (gen_rtx (MEM, QImode,                            \
+                              plus_constant (tramp, 0)), tmp1);        \
+      tmp1 = expand_and (FNADDR, gen_rtx (CONST_INT, VOIDmode,         \
+                                         0xffff), 0);                  \
+      tmp2 = expand_shift (LSHIFT_EXPR, QImode,                                \
+                          gen_rtx (CONST_INT, VOIDmode, 0x1069),       \
+                          size_int (16), 0, 1);                        \
+      emit_insn (gen_iorqi3 (tmp1, tmp1, tmp2));                       \
+      emit_move_insn (gen_rtx (MEM, QImode,                            \
+                              plus_constant (tramp, 2)), tmp1);        \
+      tmp1 = expand_shift (RSHIFT_EXPR, QImode, CXT,                   \
+                          size_int (16), 0, 1);                        \
+      tmp2 = expand_shift (LSHIFT_EXPR, QImode,                                \
+                          gen_rtx (CONST_INT, VOIDmode, 0x5068),       \
+                          size_int (16), 0, 1);                        \
+      emit_insn (gen_iorqi3 (tmp1, tmp1, tmp2));                       \
+      emit_move_insn (gen_rtx (MEM, QImode,                            \
+                              plus_constant (tramp, 3)), tmp1);        \
+      tmp1 = expand_and (CXT, gen_rtx (CONST_INT, VOIDmode,            \
+                                      0xffff), 0);                     \
+      tmp2 = expand_shift (LSHIFT_EXPR, QImode,                                \
+                          gen_rtx (CONST_INT, VOIDmode, 0x1068),       \
+                          size_int (16), 0, 1);                        \
+      emit_insn (gen_iorqi3 (tmp1, tmp1, tmp2));                       \
+      emit_move_insn (gen_rtx (MEM, QImode,                            \
+                              plus_constant (tramp, 6)), tmp1);        \
+    }                                                                  \
+  else                                                                 \
+    {                                                                  \
+      emit_move_insn (gen_rtx (MEM, QImode,                            \
+                              plus_constant (TRAMP, 8)), FNADDR);      \
+      emit_move_insn (gen_rtx (MEM, QImode,                            \
+                              plus_constant (TRAMP, 9)), CXT);         \
+    }                                                                  \
+}
+
+/* Specify the machine mode that this machine uses for the index in
+   the tablejump instruction.  */
+
+#define CASE_VECTOR_MODE Pmode
+
+/* Max number of (32-bit) bytes we can move from memory to memory
+   in one reasonably fast instruction.  */
+
+#define MOVE_MAX 1
+
+/* MOVE_RATIO is the number of move instructions that is better than a
+   block move. */
+
+#define MOVE_RATIO 2           /* Default value */
+
+#define BSS_SECTION_ASM_OP ".bss"
+
+#define ASM_OUTPUT_REG_PUSH(FILE, REGNO)  \
+  asm_fprintf (FILE, "\tpush\t%s\n", reg_names[REGNO])
+
+/* This is how to output an insn to pop a register from the stack.
+   It need not be very fast code.  */
+
+#define ASM_OUTPUT_REG_POP(FILE, REGNO)  \
+  asm_fprintf (FILE, "\tpop\t%s\n", reg_names[REGNO])
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+   is done just by pretending it is already truncated.  */
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* We need to use direct addressing for large constants and addresses
+   that cannot fit within an instruction.  We must check for these
+   after after the final jump optimisation pass, since this may
+   introduce a local_move insn for a SYMBOL_REF.  This pass
+   must come before delayed branch slot filling since it can generate
+   additional instructions.  */
+
+#define MACHINE_DEPENDENT_REORG(INSNS) c4x_process_after_reload(INSNS)
+
+#define MACHINE_DEPENDENT_COMBINE(INSNS) c4x_combine_parallel(INSNS)
+
+#define DBR_OUTPUT_SEQEND(FILE)                \
+if (final_sequence != NULL_RTX)                \
+{                                      \
+ int count;                            \
+ int laj = GET_CODE (XEXP (XEXP (final_sequence, 0), 0)) == CALL_INSN; \
+                                       \
+ count = dbr_sequence_length();                \
+ while (count < (laj ? 2 : 3))         \
+ {                                     \
+    fputs("\tnop\n", FILE);            \
+    count++;                           \
+ }                                     \
+ if (laj)                              \
+    fputs("\tpush\tr11\n", FILE);      \
+}
+
+#define NO_FUNCTION_CSE
+
+/* Repeat block stuff (hook into strength_reduce() in loop.c).  */
+
+extern void c4x_rptb_process ();
+#define REPEAT_BLOCK_PROCESS(START, END) c4x_rptb_process(START, END)
+
+/* We don't want a leading tab.  */
+
+#define ASM_OUTPUT_ASM(FILE, STRING) fprintf (FILE, "%s\n", STRING)
+
+/* Define the codes that are matched by predicates in c4x.c.  */
+
+#define PREDICATE_CODES                                                \
+  {"fp_zero_operand", {CONST_DOUBLE}},                         \
+  {"const_operand", {CONST_INT, CONST_DOUBLE}},                        \
+  {"stik_const_operand", {CONST_INT}},                         \
+  {"not_const_operand", {CONST_INT}},                          \
+  {"reg_operand", {REG, SUBREG}},                              \
+  {"reg_or_const_operand", {REG, SUBREG, CONST_INT, CONST_DOUBLE}},\
+  {"r0r1_reg_operand", {REG, SUBREG}},                         \
+  {"r2r3_reg_operand", {REG, SUBREG}},                         \
+  {"ext_low_reg_operand", {REG, SUBREG}},                      \
+  {"ext_reg_operand", {REG, SUBREG}},                          \
+  {"std_reg_operand", {REG, SUBREG}},                          \
+  {"addr_reg_operand", {REG, SUBREG}},                         \
+  {"index_reg_operand", {REG, SUBREG}},                                \
+  {"dp_reg_operand", {REG}},                                   \
+  {"sp_reg_operand", {REG}},                                   \
+  {"st_reg_operand", {REG}},                                   \
+  {"call_operand", {REG, SYMBOL_REF}},                         \
+  {"src_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE}}, \
+  {"src_hi_operand", {SUBREG, REG, MEM, CONST_DOUBLE}},        \
+  {"lsrc_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE}}, \
+  {"tsrc_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE}}, \
+  {"any_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE}}, \
+  {"par_ind_operand", {MEM}},                                  \
+  {"parallel_operand", {SUBREG, REG, MEM}},                    \
+  {"mem_operand", {MEM}},                                      \
+
+
+/* Variables in c4x.c */
+
+extern enum reg_class c4x_regclass_map[];/* smallest class containing REGNO */
+extern enum machine_mode c4x_caller_save_map[];
+
+extern struct rtx_def *c4x_compare_op0;        /* operand 0 for comparisons */
+extern struct rtx_def *c4x_compare_op1;        /* operand 1 for comparisons */
+
+extern int c4x_rpts_cycles;            /* max cycles for RPTS */
+extern int c4x_cpu_version;            /* cpu version C30/31/32/40/44 */
+
+/* Functions in c4x.c */
+
+extern void c4x_function_prologue ();
+
+extern void c4x_function_epilogue ();
+
+extern struct rtx_def *c4x_operand_subword ();
+
+extern struct rtx_def *c4x_adj_offsettable_operand ();
+
+extern char *c4x_output_cbranch ();
+
+extern int c4x_null_epilogue_p ();
+
+extern int c4x_autoinc_operand ();
+
+extern int c4x_label_conflict ();
+
+extern int c4x_address_conflict ();
+
+extern int c4x_adjust_cost ();
+
+extern void c4x_process_after_reload ();
+
+extern void c4x_combine_parallel ();
+
+extern int c4x_rptb_nop_p ();
+
+extern int c4x_rptb_rpts_p ();
+
+extern int fp_zero_operand ();
+
+extern int const_operand ();
+
+extern int stik_const_operand ();
+
+extern int not_const_operand ();
+
+extern int reg_operand ();
+
+extern int reg_imm_operand ();
+
+extern int r0r1_reg_operand ();
+
+extern int r2r3_reg_operand ();
+
+extern int ext_low_reg_operand ();
+
+extern int ext_reg_operand ();
+
+extern int std_reg_operand ();
+
+extern int src_operand ();
+
+extern int lsrc_operand ();
+
+extern int tsrc_operand ();
+
+extern int addr_reg_operand ();
+
+extern int index_reg_operand ();
+
+extern int dp_reg_operand ();
+
+extern int sp_reg_operand ();
+
+extern int st_reg_operand ();
+
+extern int call_operand ();
+
+extern int par_ind_operand ();
+
+extern int c4x_H_constant ();
+
+extern int c4x_I_constant ();
+
+extern int c4x_J_constant ();
+
+extern int c4x_L_constant ();
+
+extern int c4x_Q_constraint ();
+
+extern int c4x_R_constraint ();
+
+extern int c4x_S_constraint ();
+
+extern int c4x_T_constraint ();
+
+extern void c4x_emit_libcall ();
+
+extern void c4x_emit_libcall3 ();
+
+extern void c4x_emit_libcall_mulhi ();
+
+extern int c4x_group1_reg_operand ();
+
+extern int c4x_group1_mem_operand ();
+
+extern int c4x_arx_reg_operand ();
+
+extern int legitimize_operands ();
+
+extern int valid_operands ();
+
+extern int valid_parallel_operands_4 ();
+
+extern int valid_parallel_operands_5 ();
+
+extern int valid_parallel_operands_6 ();
diff --git a/gcc/config/c4x/c4x.md b/gcc/config/c4x/c4x.md
new file mode 100644 (file)
index 0000000..21e62ea
--- /dev/null
@@ -0,0 +1,6798 @@
+;; Machine description for the TMS320C[34]x for GNU C compiler
+;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+
+;; Contributed by Michael Hayes (m.hayes@elec.canterbury.cri.nz)
+;;            and Herman Ten Brugge (Haj.Ten.Brugge@net.HCC.nl)
+
+;; This file is part of GNU CC.
+
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;
+; TODO :
+;        Set up addressing macros to handle direct memory references properly
+;        Try using PQImode again for addresses since C30 only uses
+;        24-bit addresses.   Ideally GCC would emit different insns
+;        for QImode and Pmode, whether Pmode was QImode or PQImode.
+;        For addresses we wouldn't have to have a clobber of the CC
+;        associated with each insn and we could use MPYI in address
+;        calculations without having to synthesise a proper 32 bit multiply.
+
+; Additional C30/C40 instructions not coded:
+; CALLcond, IACK, IDLE, LDE, LDFI, LDII, LDM, NORM, RETIcond
+; ROLC, RORC, SIGI, STFI, STII, SUBC, SWI, TRAPcond
+
+; Additional C40 instructions not coded:
+; LDEP, LDPE, LWRct, FRIEEE, TOIEEE, LAJcond, LATcond, RETIcondD
+
+;
+; C4x MODES
+;
+; QImode                char, short, int, long (32-bits)
+; HImode                long long              (64-bits)
+; QFmode                float, double          (32-bits)
+; HFmode                long double            (40-bits)
+; CCmode               
+; CC_NOOVmode          
+
+;
+; C4x PREDICATES:
+;
+; comparison_operator   LT, GT, LE, GE, LTU, GTU, LEU, GEU, EQ, NE
+; memory_operand        memory                                     [m]
+; immediate_operand     immediate constant                         [IKN]
+; register_operand      register                                   [rf]
+; general_operand       register, memory, constant                 [rfmI]
+
+; addr_reg_operand      AR0-AR7, pseudo reg                        [a]
+; sp_reg_operand        SP                                         [b]
+; std_reg_operand       AR0-AR7, IR0-IR1, RC, RS, RE, SP, pseudo   [c]
+; ext_reg_operand       R0-R11, pseudo reg                         [f]
+; ext_low_reg_operand   R0-R7, pseudo reg                          [q]
+; index_reg_operand     IR0-IR1, pseudo reg                        [x]
+; st_reg_operand        ST                                         [y]
+; dp_reg_operand        DP                                         [z]
+; stik_const_operand    5-bit const                                [K]
+; src_operand           general operand                            [rfmHI]
+; par_ind_operand       indirect S mode (ARx + 0, 1, IRx)          [S<>]
+; parallel_operand      par_ind_operand or ext_low_reg_operand
+
+; ADDI src2, src1, dst  three operand op
+; ADDI src, dst         two operand op
+
+;  Note that the predicates are only used when selecting a pattern
+;  to determine if an operand is valid.
+
+;  The constraints then select which of the possible valid operands
+;  is present (and guide register selection). The actual assembly
+;  instruction is then selected on the basis of the constraints.
+
+;  The extra constraint (valid_operands) is used to determine if
+;  the combination of operands is legitimate for the pattern.
+
+;
+; C4x CONSTRAINTS:
+;
+; a   address reg          AR0-AR7
+; b   stack pointer        SP
+; c   other int reg        AR0-AR7, IR0-IR1, RC, RS, RE
+; d   fp reg               R0-R11 (sets CC when dst) 
+; f   fp reg               R0-R11 (sets CC when dst)
+; g   general reg, memory, constant
+; h   fp reg               R0-R11 (sets CC when dst) 
+; i   immediate int constant
+; m   memory
+; q   low fp reg           R0-R7  (sets CC when dst)
+; r   general reg          R0-R11, AR0-AR7, IR0-IR1, RC, RS, RE
+; s   immediate int (value not explicit)
+; t                        R0-R1
+; u                        R2-R3
+; x   index reg            IR0-IR1
+; y   status (CC) reg      ST
+; z   data pointer         DP
+
+; G   fp zero
+; H   fp 16-bit constant
+; I   signed 16-bit
+; J   signed 8-bit    (C4x only)
+; K   signed 5-bit    (C4x only)
+; L   unsigned 16-bit
+; M   unsigned 8-bit  (C4x only)
+; N   ones complement of unsigned 16-bit
+; O   16 bit high constant
+; Q   ARx + 9-bit signed disp
+; R   ARx + 5-bit unsigned disp  (C4x only)
+; S   ARx + 0, 1, IRx disp
+; T   symbol ref (direct)
+; <   memory operand with autodecrement addressing
+; >   memory operand with autoincrement addressing
+; {   memory operand with pre-modify addressing
+; }   memory operand with post-modify addressing
+
+;  Note that the d, f, and h constraints are equivalent.
+;  The m constraint is equivalent to QT<>{}
+
+;  Note that the constraints are used to select the operands
+;  for a chosen pattern.  The constraint that requires the fewest
+;  instructions to load an operand is chosen.
+
+;  Note that the 'r' constraint is mostly only used for src integer register 
+;  operands,  while 'c' and 'd' constraints are generally only used for dst
+;  integer register operands (the 'r' constraint is the union of the 'c' and
+;  'd' constraints).  When a register satisfying the 'd' constraint
+;  is used as a dst operand, the CC gets clobbered (except for LDIcond)---but 
+;  not for 'c'.
+
+;  The 'f' constraint is only for float register operands---when 
+;  a register satisying the 'f' constraint is used as a dst operand,
+;  the CC gets clobbered (except for LDFcond).
+
+;  The ! in front of the 'b' constaint says to GCC to disparage the
+;  use of this constraint.  The 'b' constraint applies only to the SP.
+
+;  Note that we deal with the condition code CC like some of the RISC
+;  architectures (arm, sh, sparc) where it is stored in a general register,
+;  in this case the hard register ST (21).  Unlike these other architectures
+;  that do not set the CC with many instructions, the C[34]x architectures
+;  sets the CC for many instructions when the destination register is
+;  an extended precision register.  While it would have been easier
+;  to use the generic cc0 register to store the CC, as with most of
+;  the other ported architectures, this constrains the setting and testing
+;  of the CC to be consecutive insns.  Thus we would reduce the benefit
+;  of scheduling instructions to avoid pipeline conflicts and filling of
+;  delayed branch slots.
+
+;  Since the C[34]x has many instructions that set the CC, we pay the
+;  price of having to explicity define which insns clobber the CC
+;  (rather than using the macro NOTICE_UPDATE_CC). 
+
+;  Note that many patterns say that the CC is clobbered when in fact
+;  that it may not be (depending on the destination register).
+;  We have to cover ourselves if an extended precision register
+;  is allocated to the destination register.
+;  Unfortunately, it is not easy to tell GCC that the clobbering of CC
+;  is register dependent.  If we could tolerate the ST register being
+;  copied about, then we could store the CC in a pseudo register and
+;  use constructs such as (clobber (match_scratch:CC N "&y,X")) to
+;  indicate that the 'y' class (ST register) is clobbered for the
+;  first combination of operands, but not with the second.
+;  I tried this approach for a while but reload got unhappy since I
+;  didn't allow it to move the CC around.
+
+;  Note that fundamental operations, such as moves, must not clobber the
+;  CC.  Thus movqi choses a move instruction that doesn't clobber the CC.
+;  If GCC wants to combine a move with a compare, it is smart enough to
+;  chose the move instruction that sets the CC.
+
+;  Unfortunately, the C[34]x instruction set does not have arithmetic or
+;  logical operations that never touch the CC.  We thus have to assume
+;  that the CC may be clobbered at all times.  If we define patterns
+;  such as addqi without the clobber of CC, then GCC will be forced
+;  to use registers such as the auxiliary registers which can cause
+;  horrible pipeline conflicts.  The tradeoff is that GCC can't now
+;  sneak in an add instruction between setting and testing of the CC.
+
+;  Most of the C[34]x instructions require operands of the following formats,
+;  where imm represents an immediate constant, dir a direct memory reference,
+;  ind an indirect memory reference, and reg a register:
+
+;        src2 (op2)             src1 (op1)      dst (op0)
+; imm  dir  ind  reg  |  imm  dir  ind  reg  |  reg      Notes
+;---------------------+----------------------+------
+; ILH   T   Q<>   r   |   -    -    -    0   |   r       2 operand
+;  -    -   S<>   r   |   -    -   S<>   r   |   r       
+;  J    -    R    -   |   -    -    R    r   |   r       C4x
+
+;  Arithmetic operations use the I, J constraints for immediate constants,
+;  while logical operations use the L, J constraints.  Floating point
+;  operations use the H constraint for immediate constants.
+
+;  With most instructions the src2 and src1 operands are commutative
+;  (except for SUB, SUBR, ANDN).  The assembler considers
+;  ADDI 10, R0, R1 and ADDI R0, 10, R1 to be equivalent.
+;  We thus match src2 and src1 with the src_operand predicate and
+;  use valid_operands as the extra constraint to reject invalid
+;  operand combinations.  For example, ADDI @foo, @bar, R0.
+
+;  Note that we use the ? modifier so that reload doesn't preferentially
+;  try the alternative where three registers are acceptable as
+;  operands (whenever an operand requires reloading).  Instead it will try
+;  the 2 operand form which will produce better code since it won't require
+;  a new spill register.
+
+;  Note that the floating point representation of 0.0 on the C4x
+;  is 0x80000000 (-2147483648).  This value produces an warning
+;  message on 32-bit machines about the decimal constant being so large
+;  that it is unsigned.
+
+;  With two operand instructions patterns having two sets,
+;  the compare set must come first to keep the combiner happy.
+;  While the combiner seems to cope most of the time with the
+;  compare set coming second, it's best to have it first.
+
+;
+; C4x CONSTANT attributes
+;
+(define_attr "cpu" "c4x,c3x"
+ (const
+  (cond [(symbol_ref "TARGET_C3X") (const_string "c3x")]
+         (const_string "c4x"))))
+
+;
+; C4x INSN ATTRIBUTES:
+;
+; lda           load address, non-clobber CC
+; store         memory store, non-clobber CC
+; load_load     parallel memory loads, non-clobber CC
+; load_store    parallel memory load and store, non-clobber CC
+; store_load    parallel memory store and load, non-clobber CC
+; store_store   parallel memory stores, non-clobber CC
+; unary         two operand arithmetic, non-clobber CC
+; unarycc       two operand arithmetic, clobber CC
+; binary        three operand arithmetic, non-clobber CC
+; binarycc      three operand arithmetic, clobber CC
+; compare       compare, clobber CC
+; call          function call
+; rets          return from subroutine
+; jump          unconditional branch
+; jmpc          conditional branch
+; db            decrement and branch (unconditional)
+; dbc           decrement and branch (conditional)
+; ldp           load DP
+; push         stack push
+; pop          stack pop
+; repeat        block repeat
+; repeat_top    block repeat top
+; laj           link and jump
+; multi         multiple instruction
+; misc          nop            (default)
+
+;  The only real instructions that affect things are the ones that modify
+;  address registers and ones that call or jump.  Note that the number
+;  of operands refers to the RTL insn pattern, not the number of explicit
+;  operands in the machine instruction.
+;
+(define_attr "type" "lda,store,unary,unarycc,binary,binarycc,compare,call,rets,jump,jmpc,db,dbc,misc,ldp,repeat,repeat_top,laj,load_load,load_store,store_load,store_store,push,pop,multi"
+             (const_string "misc"))
+
+
+; Some instructions operate on unsigned data constants, some on signed data
+; constants, or the ones complement of unsigned constants.
+; This differentiates them.  Default to signed.  This attribute
+; is used by the macro SMALL_CONST () (defined in c4x.h) to determine
+; whether an immediate integer constant will fit within the instruction,
+; or will have to be loaded using direct addressing from memory.
+; Note that logical operations assume unsigned integers whereas
+; arithmetic operations assume signed integers.  Note that the C4x
+; small immediate constant (J) used as src2 in three operand instructions
+; is always signed.  not_uint16 refers to a number that fits into 16-bits
+; when one's complemented.
+;
+(define_attr "data" "int16,uint16,high_16,not_uint16" (const_string "int16"))
+
+(define_asm_attributes
+  [(set_attr "type" "multi")])
+
+;
+; C4x DELAY SLOTS
+;
+; Define delay slot scheduling for branch and call instructions.
+; The C[34]x has three delay slots. Note that none of the three instructions
+; that follow a delayed branch can be a Bcond, BcondD, BR, BRD, DBcond,
+; DBcondD, CALL, CALLcond, TRAPcond, RETIcond, RETScond, RPTB, RPTS, or IDLE.
+;
+; Annulled branches are a bit difficult because the next instructions
+; are preprocessed.
+; The table below shows what phase of the c4x is executed.
+;        BccA[TF] label
+;        op1             fetch, decode and read executed
+;        op2             fetch and decode executed
+;        op3             fetch executed
+; This means that we can allow any instruction in the last delay slot
+; and only instructions which modify registers in the first two. 
+; lda can not be executed in the first delay slot 
+; and ldpk can not be executed in the first two delay slots.
+
+(define_attr "onlyreg" "false,true"
+       (cond [(eq_attr "type" "unary,unarycc")
+                       (if_then_else (and (match_operand 0 "reg_imm_operand" "")
+                                          (match_operand 1 "reg_imm_operand" ""))
+                                     (const_string "true") (const_string "false"))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (and (match_operand 0 "reg_imm_operand" "")
+                                          (and (match_operand 1 "reg_imm_operand" "")
+                                               (match_operand 2 "reg_imm_operand" "")))
+                                     (const_string "true") (const_string "false"))]
+             (const_string "false")))
+
+(define_attr "onlyreg_nomod" "false,true"
+       (cond [(eq_attr "type" "unary,unarycc,compare,lda,store")
+                       (if_then_else (and (match_operand 0 "not_modify_reg" "")
+                                          (match_operand 1 "not_modify_reg" ""))
+                                     (const_string "true") (const_string "false"))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (and (match_operand 0 "not_modify_reg" "")
+                                          (and (match_operand 1 "not_modify_reg" "")
+                                               (match_operand 2 "not_modify_reg" "")))
+                                     (const_string "true") (const_string "false"))]
+             (const_string "false")))
+
+(define_attr "not_repeat_reg" "false,true"
+       (cond [(eq_attr "type" "unary,unarycc,compare,lda,store")
+                       (if_then_else (and (match_operand 0 "not_rc_reg" "")
+                                          (match_operand 1 "not_rc_reg" ""))
+                                     (const_string "true") (const_string "false"))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (and (match_operand 0 "not_rc_reg" "")
+                                          (and (match_operand 1 "not_rc_reg" "")
+                                               (match_operand 2 "not_rc_reg" "")))
+                                     (const_string "true") (const_string "false"))]
+             (const_string "false")))
+
+(define_attr "in_annul_slot_1" "false,true"
+  (if_then_else (and (and (eq_attr "cpu" "c4x")
+                         (eq_attr "type" "!jump,call,rets,jmpc,compare,db,dbc,repeat,repeat_top,laj,push,pop,lda,ldp,multi"))
+                    (eq_attr "onlyreg" "true"))
+               (const_string "true")
+               (const_string "false")))
+
+(define_attr "in_annul_slot_2" "false,true"
+  (if_then_else (and (and (eq_attr "cpu" "c4x")
+                         (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,push,pop,ldp,multi"))
+                    (eq_attr "onlyreg_nomod" "true"))
+               (const_string "true")
+               (const_string "false")))
+
+(define_attr "in_annul_slot_3" "false,true"
+  (if_then_else (and (eq_attr "cpu" "c4x")
+                    (eq_attr "type" "!jump,call,rets,jmpc,unarycc,binarycc,compare,db,dbc,repeat,repeat_top,laj,push,pop,multi"))
+               (const_string "true")
+               (const_string "false")))
+
+(define_attr "in_delay_slot" "false,true"
+  (if_then_else (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,multi")
+               (const_string "true")
+               (const_string "false")))
+
+(define_attr "in_repeat_slot" "false,true"
+  (if_then_else (and (eq_attr "cpu" "c4x")
+                    (and (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,multi")
+                         (eq_attr "not_repeat_reg" "true")))
+               (const_string "true")
+               (const_string "false")))
+
+(define_attr "in_dbc_slot" "false,true"
+  (if_then_else (eq_attr "type" "!jump,call,rets,jmpc,unarycc,binarycc,compare,db,dbc,repeat,repeat_top,laj,multi")
+               (const_string "true")
+               (const_string "false")))
+
+(define_delay (eq_attr "type" "jmpc")
+              [(eq_attr "in_delay_slot" "true")
+               (eq_attr "in_annul_slot_1" "true")
+               (eq_attr "in_annul_slot_1" "true")
+
+               (eq_attr "in_delay_slot" "true")
+               (eq_attr "in_annul_slot_2" "true")
+               (eq_attr "in_annul_slot_2" "true")
+
+               (eq_attr "in_delay_slot" "true")
+               (eq_attr "in_annul_slot_3" "true")
+               (eq_attr "in_annul_slot_3" "true") ])
+
+
+(define_delay (eq_attr "type" "repeat_top")
+              [(eq_attr "in_repeat_slot" "true") (nil) (nil)
+               (eq_attr "in_repeat_slot" "true") (nil) (nil)
+               (eq_attr "in_repeat_slot" "true") (nil) (nil)])
+
+(define_delay (eq_attr "type" "jump,db")
+              [(eq_attr "in_delay_slot" "true") (nil) (nil)
+               (eq_attr "in_delay_slot" "true") (nil) (nil)
+               (eq_attr "in_delay_slot" "true") (nil) (nil)])
+
+
+; Decrement and branch conditional instructions cannot modify the
+; condition codes for the cycles in the delay slots.
+;
+(define_delay (eq_attr "type" "dbc")
+              [(eq_attr "in_dbc_slot" "true") (nil) (nil)
+               (eq_attr "in_dbc_slot" "true") (nil) (nil)
+               (eq_attr "in_dbc_slot" "true") (nil) (nil)])
+
+; The LAJ instruction has three delay slots but the last slot is
+; used for pushing the return address.  Thus we can only use two slots.
+;
+(define_delay (eq_attr "type" "laj")
+              [(eq_attr "in_delay_slot" "true") (nil) (nil)
+               (eq_attr "in_delay_slot" "true") (nil) (nil)])
+
+;
+; C4x UNSPEC NUMBERS
+;
+;  1 BU/BUD
+;  2 RPTS
+;  3 LSH
+;  4 cmphi
+;  5 RCPF
+;  6 RND
+;  7 repeat block filler
+;  8 loadhf_int
+;  9 storehf_int
+; 10 RSQRF
+
+
+;
+; C4x FUNCTIONAL UNITS
+;
+; Define functional units for instruction scheduling to minimise
+; pipeline conflicts.
+;
+; With the C3x, an external memory write (with no wait states) takes
+; two cycles and an external memory read (with no wait states) takes
+; one cycle.  However, an external read following an external write
+; takes two cycles.  With internal memory, reads and writes take
+; half a cycle.
+;
+; When a C4x address register is loaded it will not be available for
+; an extra machine cycle.  Calculating with a C4x address register
+; makes it unavailable for 2 machine cycles.  To notify GCC of these
+; pipeline delays, each of the auxiliary and index registers are declared
+; as separate functional units.
+;
+; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
+;                      TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
+;
+; MULTIPLICITY 1 (C4x has no independent identical function units)
+; SIMULTANEITY 0 (C4x is pipelined)
+; READY_DELAY  1 (Results usually ready after every cyle)
+; ISSUE_DELAY  1 (Can issue insns every cycle)
+
+; Just some dummy definitions. The real work is done in c4x_adjust_cost.
+; These are needed so the min/max READY_DELAY is known.
+
+(define_function_unit "dummy" 1 0 (const_int 0) 1 1)
+(define_function_unit "dummy" 1 0 (const_int 0) 2 1)
+(define_function_unit "dummy" 1 0 (const_int 0) 3 1)
+
+;(define_function_unit "ar0" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar0" "1")
+;                 (eq_attr "usear0" "1")))
+;       3 1 )
+
+;(define_function_unit "ar0" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar0" "1")
+;                 (eq_attr "usear0" "1")))
+;       2 1 )
+
+;(define_function_unit "ar0" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear0" "1")
+;                 (eq_attr "readar0" "1")))
+;       2 1 )
+
+; The attribute setar0 is set to 1 for insns where ar0 is a dst operand.
+; Note that the attributes unarycc and binarycc do not apply
+; if ar0 is a dst operand (only loading an ext. prec. reg. sets CC)
+(define_attr "setar0" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar0_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar0" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar0_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+; The attribute usear0 is set to 1 for insns where ar0 is used
+; for addressing, as a src operand, or as a dst operand.
+(define_attr "usear0" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar0_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar0_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar0_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar0_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+; The attribute readar0 is set to 1 for insns where ar0 is a src operand.
+(define_attr "readar0" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar0_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar0_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar0_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ar1" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar1" "1")
+;                 (eq_attr "usear1" "1")))
+;       3 1 )
+
+;(define_function_unit "ar1" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar1" "1")
+;                 (eq_attr "usear1" "1")))
+;       2 1 )
+
+;(define_function_unit "ar1" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear1" "1")
+;                 (eq_attr "readar1" "1")))
+;       2 1 )
+
+(define_attr "setar1" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar1_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar1" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar1_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usear1" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar1_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar1_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar1_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar1_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readar1" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar1_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar1_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar1_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ar2" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar2" "1")
+;                 (eq_attr "usear2" "1")))
+;       3 1 )
+
+;(define_function_unit "ar2" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar2" "1")
+;                 (eq_attr "usear2" "1")))
+;       2 1 )
+
+;(define_function_unit "ar2" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear2" "1")
+;                 (eq_attr "readar2" "1")))
+;       2 1 )
+
+(define_attr "setar2" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar2_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar2" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar2_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usear2" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar2_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar2_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar2_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar2_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readar2" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar2_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar2_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar2_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ar3" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar3" "1")
+;                 (eq_attr "usear3" "1")))
+;       3 1 )
+
+;(define_function_unit "ar3" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar3" "1")
+;                 (eq_attr "usear3" "1")))
+;       2 1 )
+
+;(define_function_unit "ar3" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear3" "1")
+;                 (eq_attr "readar3" "1")))
+;       2 1 )
+
+(define_attr "setar3" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar3_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar3" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar3_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usear3" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar3_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar3_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar3_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar3_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readar3" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar3_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar3_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar3_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ar4" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar4" "1")
+;                 (eq_attr "usear4" "1")))
+;       3 1 )
+
+;(define_function_unit "ar4" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar4" "1")
+;                 (eq_attr "usear4" "1")))
+;       2 1 )
+
+;(define_function_unit "ar4" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear4" "1")
+;                 (eq_attr "readar4" "1")))
+;       2 1 )
+
+(define_attr "setar4" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar4_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar4" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar4_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usear4" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar4_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar4_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar4_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar4_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readar4" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar4_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar4_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar4_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ar5" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar5" "1")
+;                 (eq_attr "usear5" "1")))
+;       3 1 )
+
+;(define_function_unit "ar5" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar5" "1")
+;                 (eq_attr "usear5" "1")))
+;       2 1 )
+
+;(define_function_unit "ar5" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear5" "1")
+;                 (eq_attr "readar5" "1")))
+;       2 1 )
+
+(define_attr "setar5" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar5_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar5" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar5_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usear5" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar5_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar5_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar5_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar5_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readar5" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar5_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar5_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar5_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ar6" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar6" "1")
+;                 (eq_attr "usear6" "1")))
+;       3 1 )
+
+;(define_function_unit "ar6" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar6" "1")
+;                 (eq_attr "usear6" "1")))
+;       2 1 )
+
+;(define_function_unit "ar6" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear6" "1")
+;                 (eq_attr "readar6" "1")))
+;       2 1 )
+
+(define_attr "setar6" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar6_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar6" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar6_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usear6" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar6_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar6_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar6_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar6_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readar6" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar6_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar6_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar6_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ar7" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setar7" "1")
+;                 (eq_attr "usear7" "1")))
+;       3 1 )
+
+;(define_function_unit "ar7" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ar7" "1")
+;                 (eq_attr "usear7" "1")))
+;       2 1 )
+
+;(define_function_unit "ar7" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "usear7" "1")
+;                 (eq_attr "readar7" "1")))
+;       2 1 )
+
+(define_attr "setar7" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ar7_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ar7" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ar7_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usear7" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ar7_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar7_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar7_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "db,dbc")
+                       (if_then_else (match_operand 0 "ar7_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readar7" ""
+       (cond [(eq_attr "type" "compare")
+                       (if_then_else (match_operand 0 "ar7_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ar7_reg_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ar7_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ir0" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setir0" "1")
+;                 (eq_attr "useir0" "1")))
+;       3 1 )
+
+;(define_function_unit "ir0" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ir0" "1")
+;                 (eq_attr "useir0" "1")))
+;       2 1 )
+
+(define_attr "setir0" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ir0_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ir0" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ir0_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "useir0" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ir0_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ir0_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ir0_mem_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;(define_function_unit "ir1" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setir1" "1")
+;                 (eq_attr "useir1" "1")))
+;       3 1 )
+
+;(define_function_unit "ir1" 1 0
+;       (and (eq_attr "cpu" "c4x")
+;            (and (eq_attr "setlda_ir1" "1")
+;                 (eq_attr "useir1" "1")))
+;       2 1 )
+
+(define_attr "setir1" ""
+       (cond [(eq_attr "type" "unary,binary")
+                       (if_then_else (match_operand 0 "ir1_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "setlda_ir1" ""
+       (cond [(eq_attr "type" "lda")
+                       (if_then_else (match_operand 0 "ir1_reg_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "useir1" ""
+       (cond [(eq_attr "type" "compare,store")
+                       (if_then_else (match_operand 0 "ir1_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc")
+                       (if_then_else (match_operand 1 "ir1_mem_operand" "")
+                                     (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+                       (if_then_else (match_operand 2 "ir1_mem_operand" "")
+                                     (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+; With the C3x, things are simpler, but slower, i.e. more pipeline conflicts :(
+; There are three functional groups:
+; (1) AR0-AR7, IR0-IR1, BK
+; (2) DP
+; (3) SP
+;
+; When a register in one of these functional groups is loaded,
+; the contents of that or any other register in its group
+; will not be available to the next instruction for 2 machine cycles.
+; Similarly, when a register in one of the functional groups is read
+; excepting (IR0-IR1, BK, DP) the contents of that or any other register
+; in its group will not be available to the next instruction for
+; 1 machine cycle.
+;
+; Let's ignore functional groups 2 and 3 for now, since they are not
+; so important.
+
+;(define_function_unit "group1" 1 0
+;       (and (eq_attr "cpu" "c3x")
+;            (and (eq_attr "setgroup1" "1")
+;                 (eq_attr "usegroup1" "1")))
+;       3 1)
+
+;(define_function_unit "group1" 1 0
+;       (and (eq_attr "cpu" "c3x")
+;            (and (eq_attr "usegroup1" "1")
+;                 (eq_attr "readarx" "1")))
+;       2 1)
+
+(define_attr "setgroup1" ""
+       (cond [(eq_attr "type" "lda,unary,binary")
+                  (if_then_else (match_operand 0 "group1_reg_operand" "")
+                                (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "usegroup1" ""
+       (cond [(eq_attr "type" "compare,store,store_store,store_load")
+              (if_then_else (match_operand 0 "group1_mem_operand" "")
+                            (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc,load_load,load_store")
+              (if_then_else (match_operand 1 "group1_mem_operand" "")
+                            (const_int 1) (const_int 0))
+              (eq_attr "type" "store_store,load_store")
+              (if_then_else (match_operand 2 "group1_mem_operand" "")
+                            (const_int 1) (const_int 0))
+              (eq_attr "type" "load_load,store_load")
+              (if_then_else (match_operand 3 "group1_mem_operand" "")
+                            (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+(define_attr "readarx" ""
+       (cond [(eq_attr "type" "compare")
+              (if_then_else (match_operand 0 "arx_reg_operand" "")
+                            (const_int 1) (const_int 0))
+              (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc")
+              (if_then_else (match_operand 1 "arx_reg_operand" "")
+                            (const_int 1) (const_int 0))
+              (eq_attr "type" "binary,binarycc")
+              (if_then_else (match_operand 2 "arx_reg_operand" "")
+                            (const_int 1) (const_int 0))]
+             (const_int 0)))
+
+;
+; TWO OPERAND INTEGER INSTRUCTIONS
+;
+
+;
+; LDP/LDPK
+;
+(define_insn "set_ldp"
+  [(set (match_operand:QI 0 "dp_reg_operand" "=z")
+        (high:QI (match_operand:QI 1 "" "")))]
+  "!TARGET_SMALL"
+  "* return (TARGET_C3X) ? \"ldp\\t%A1\" : \"ldpk\\t%A1\";"
+  [(set_attr "type" "ldp")])
+
+
+; Used when moving a constant label reference to an external
+; location, this will make sure the original label is still
+; used so the optimizer will not optimize it away.
+;
+(define_insn "set_ldp_use"
+  [(parallel [(set (match_operand:QI 0 "dp_reg_operand" "=z")
+                   (high:QI (match_operand:QI 1 "" "")))
+              (use (match_operand 2 "" ""))])]
+  "!TARGET_SMALL"
+  "* return (TARGET_C3X) ? \"ldp\\t%A1\" : \"ldpk\\t%A1\";"
+  [(set_attr "type" "ldp")])
+
+(define_insn "set_high_use"
+  [(parallel [(set (match_operand:QI 0 "std_reg_operand" "=c")
+                   (high:QI (match_operand:QI 1 "" "")))
+              (use (match_operand 2 "" ""))])]
+  "!TARGET_C3X && !TARGET_SMALL"
+  "ldhi\\t^%H1,%0"
+  [(set_attr "type" "unary")])
+
+(define_insn "set_ior_lo_use"
+  [(parallel [(set (match_operand:QI 0 "std_reg_operand" "=c")
+                   (ior:QI (match_dup 0)
+                           (and:QI (match_operand:QI 1 "" "")
+                                   (const_int 65535))))
+              (use (match_operand 2 "" ""))])]
+  "!TARGET_C3X && !TARGET_SMALL"
+  "or\\t#%H1,%0"
+  [(set_attr "type" "unary")])
+
+;
+; LDIU/LDA/STI/STIK
+; The following moves will not set the condition codes register.
+;
+
+; This must come before the general case
+(define_insn "*movqi_stik"
+  [(set (match_operand:QI 0 "memory_operand" "=m")
+        (match_operand:QI 1 "stik_const_operand" "K"))]
+  "!TARGET_C3X"
+  "stik\\t%1,%0"
+  [(set_attr "type" "store")])
+
+; We must provide an alternative to store to memory in case we have to
+; spill a register.
+(define_insn "movqi_noclobber"
+  [(set (match_operand:QI 0 "src_operand" "=d,*c,m,r")
+        (match_operand:QI 1 "src_hi_operand" "rmI,rmI,r,O"))]
+  "reg_operand (operands[0], QImode)
+   || reg_operand (operands[1], QImode)"
+  "*
+   if (which_alternative == 2)
+     return \"sti\\t%1,%0\";
+
+   if (!TARGET_C3X && which_alternative == 3)
+     {
+       operands[1] = gen_rtx (CONST_INT, VOIDmode,
+                              (INTVAL (operands[1]) >> 16) & 0xffff);
+       return \"ldhi\\t%1,%0\";
+     }
+
+   /* The lda instruction cannot use the same register as source
+      and destination.  */
+   if (!TARGET_C3X && which_alternative == 1
+       && (   IS_ADDR_REG (REGNO (operands[0]))
+           || IS_INDEX_REG (REGNO (operands[0]))
+           || IS_SP_REG (REGNO (operands[0])))
+       && (REGNO (operands[0]) != REGNO (operands[1])))
+      return \"lda\\t%1,%0\";
+   return \"ldiu\\t%1,%0\";
+  "
+  [(set_attr "type" "unary,lda,store,unary")
+   (set_attr "data" "int16,int16,int16,high_16")])
+
+;
+; LDI
+;
+
+; We shouldn't need these peepholes, but the combiner seems to miss them...
+(define_peephole
+  [(set (match_operand:QI 0 "ext_reg_operand" "=d")
+        (match_operand:QI 1 "src_operand" "g"))
+   (set (reg:CC 21)
+        (compare:CC (match_dup 0) (const_int 0)))]
+  ""
+  "@
+  ldi\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "int16")])
+
+(define_insn "*movqi_set"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:QI 1 "src_operand" "g") 
+                    (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d")
+        (match_dup 1))]
+  ""
+  "@
+  ldi\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "int16")])
+
+; This pattern probably gets in the way and requires a scratch register
+; when a simple compare with zero will suffice.
+;(define_insn "*movqi_test"
+; [(set (reg:CC 21)
+;       (compare:CC (match_operand:QI 1 "src_operand" "g") 
+;                   (const_int 0)))
+;  (clobber (match_scratch:QI 0 "=d"))]
+; ""
+; "@
+;  ldi\\t%1,%0"
+;  [(set_attr "type" "unarycc")
+;   (set_attr "data" "int16")])
+
+;  If one of the operands is not a register, then we should
+;  emit two insns, using a scratch register.  This will produce
+;  better code in loops if the source operand is invariant, since
+;  the source reload can be optimised out.  During reload we cannot
+;  use change_address or force_reg which will allocate new pseudo regs.
+
+;  Unlike most other insns, the move insns can't be split with
+;  different predicates, because register spilling and other parts of
+;  the compiler, have memoized the insn number already.
+
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "src_operand" "")
+        (match_operand:QI 1 "src_operand" ""))]
+  ""
+  "
+   /* We shouldn't have to do this, since reload is supposed to
+      be able to do this if we have a memory constraint.  */
+   if (CONSTANT_P (operands[1])
+       && !const_operand (operands[1], QImode))
+     {
+        operands[1] = force_const_mem (QImode, operands[1]);
+        if (!memory_address_p (QImode, XEXP (operands[1], 0))
+            && !reload_in_progress)
+          operands[1] = change_address (operands[1], QImode,
+                                        XEXP (operands[1], 0));
+     }
+
+   if (!reload_in_progress
+       && !reg_operand (operands[0], QImode) 
+       && !reg_operand (operands[1], QImode)
+       && !(stik_const_operand (operands[1], QImode) 
+            && !push_operand (operands[0], QImode)))
+     operands[1] = force_reg (QImode, operands[1]);")
+
+(define_insn "*movqi_update"
+  [(set (match_operand:QI 0 "reg_operand" "=r") 
+        (mem:QI (plus:QI (match_operand:QI 1 "addr_reg_operand" "a")
+                         (match_operand:QI 2 "index_reg_operand" "x"))))
+   (set (match_dup 1)
+        (plus:QI (match_dup 1) (match_dup 2)))]
+  ""
+  "ldiu\\t*%1++(%2),%0"
+  [(set_attr "type" "unary")
+   (set_attr "data" "int16")])
+
+(define_insn "movqi_parallel"
+  [(set (match_operand:QI 0 "parallel_operand" "=q,S<>,q,S<>")
+        (match_operand:QI 1 "parallel_operand" "S<>,q,S<>,q"))
+   (set (match_operand:QI 2 "parallel_operand" "=q,S<>,S<>,q")
+        (match_operand:QI 3 "parallel_operand" "S<>,q,q,S<>"))]
+  "valid_parallel_operands_4 (operands, QImode)"
+  "@
+   ldi1\\t%1,%0\\n||\\tldi2\\t%3,%2
+   sti1\\t%1,%0\\n||\\tsti2\\t%3,%2
+   ldi\\t%1,%0\\n||\\tsti\\t%3,%2
+   ldi\\t%3,%2\\n||\\tsti\\t%1,%0"
+  [(set_attr "type" "load_load,store_store,load_store,store_load")])
+
+;
+; PUSH/POP
+;
+(define_insn "*pushqi"
+  [(set (mem:QI (pre_inc:QI (reg:QI 20)))
+        (match_operand:QI 0 "reg_operand" "r"))]
+  ""
+  "push\\t%0"
+  [(set_attr "type" "push")])
+
+(define_insn "*popqi"
+  [(set (match_operand:QI 0 "reg_operand" "=r")
+        (mem:QI (post_dec:QI (reg:QI 20))))
+   (clobber (reg:CC 21))]
+  ""
+  "pop\\t%0"
+  [(set_attr "type" "pop")])
+
+;
+; ABSI
+;
+(define_expand "absqi2"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (abs:QI (match_operand:QI 1 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "")
+
+(define_insn "*absqi2_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (abs:QI (match_operand:QI 1 "src_operand" "g,g")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "absi\\t%1,%0"
+  [(set_attr "type" "unarycc,unary")
+   (set_attr "data" "int16,int16")])
+
+(define_insn "*absqi2_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "g"))
+                         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d"))]
+  ""
+  "absi\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "int16")])
+
+(define_insn "*absqi2_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "g"))
+                         (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d")
+        (abs:QI (match_dup 1)))]
+  ""
+  "absi\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "int16")])        
+
+;
+; NEGI
+;
+(define_expand "negqi2"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (neg:QI (match_operand:QI 1 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+""
+"")
+
+(define_insn "*negqi2_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (neg:QI (match_operand:QI 1 "src_operand" "g,g")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "negi\\t%1,%0"
+  [(set_attr "type" "unarycc,unary")
+   (set_attr "data" "int16,int16")])
+
+(define_insn "*negqi2_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "g"))
+                         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d"))]
+  ""
+  "negi\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "int16")])
+
+(define_insn "*negqi2_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "g"))
+                         (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d")
+        (neg:QI (match_dup 1)))]
+  ""
+  "negi\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "int16")])        
+
+(define_insn "*negbqi2_clobber"
+  [(set (match_operand:QI 0 "ext_reg_operand" "=d")
+        (neg:QI (match_operand:QI 1 "src_operand" "g")))
+   (use (reg:CC_NOOV 21))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "negb\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "int16")])        
+
+;
+; NOT
+;
+(define_expand "one_cmplqi2"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (not:QI (match_operand:QI 1 "lsrc_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "")
+
+(define_insn "*one_cmplqi2_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (not:QI (match_operand:QI 1 "lsrc_operand" "g,g")))
+   (clobber (reg:CC 21))]
+  ""
+  "not\\t%1,%0"
+  [(set_attr "type" "unarycc,unary")
+   (set_attr "data" "uint16,uint16")])
+
+(define_insn "*one_cmplqi2_test"
+  [(set (reg:CC 21)
+        (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "g"))
+                    (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d"))]
+  ""
+  "not\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "uint16")])
+
+(define_insn "*one_cmplqi2_set"
+  [(set (reg:CC 21)
+        (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "g"))
+                    (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d")        
+        (not:QI (match_dup 1)))]
+  ""
+  "not\\t%1,%0"
+  [(set_attr "type" "unarycc")
+   (set_attr "data" "uint16")])        
+
+(define_insn "*one_cmplqi2_const_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (match_operand:QI 1 "not_const_operand" "N,N"))
+   (clobber (reg:CC 21))]
+  ""
+  "@
+   not\\t%N1,%0
+   not\\t%N1,%0"
+   [(set_attr "type" "unarycc,unary")
+    (set_attr "data" "not_uint16,not_uint16")])
+
+; movqi can use this for loading an integer that can't normally
+; fit into a 16-bit signed integer.  The drawback is that it cannot
+; go into R0-R11 since that will clobber the CC and movqi shouldn't
+; do that.  This can cause additional reloading but in most cases
+; this will cause only an additional register move.  With the large
+; memory model we require an extra instruction to load DP anyway,
+; if we're loading the constant from memory.  The big advantage of
+; allowing constants that satisfy not_const_operand in movqi, is that
+; it allows andn to be generated more often.
+; However, there is a problem if GCC has decided that it wants
+; to use R0-R11, since we won't have a matching pattern...
+; In interim, we prevent immed_const allowing `N' constants.
+(define_insn "*one_cmplqi2_const_noclobber"
+  [(set (match_operand:QI 0 "std_reg_operand" "=c")
+        (match_operand:QI 1 "not_const_operand" "N"))]
+  ""
+  "not\\t%N1,%0"
+  [(set_attr "type" "unary")
+   (set_attr "data" "not_uint16")])
+
+;
+; ROL
+;
+(define_expand "rotlqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (rotate:QI (match_operand:QI 1 "reg_operand" "")
+                              (match_operand:QI 2 "const_int_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "if (INTVAL (operands[2]) >= 4)
+     FAIL; /* Open code as two shifts and an or */
+   if (INTVAL (operands[2]) > 1)
+     {
+        int i;
+
+        /* If we have 4 or fewer shifts, then it is probably faster
+           to emit separate ROL instructions.  A C3x requires
+           at least 4 instructions (a C4x requires at least 3), to
+           perform a rotation by shifts.  */
+
+        for (i = 0; i < INTVAL (operands[2]); i++)
+          emit_insn (gen_rotl_1_clobber (operands[0], operands[1]));
+        DONE;
+     }")
+
+(define_insn "rotl_1_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (rotate:QI (match_operand:QI 1 "reg_operand" "0,0")
+                   (const_int 1)))
+   (clobber (reg:CC 21))]
+  ""
+  "rol\\t%0"
+  [(set_attr "type" "unarycc,unary")])
+; Default to int16 data attr.
+
+;
+; ROR
+;
+(define_expand "rotrqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (rotatert:QI (match_operand:QI 1 "reg_operand" "")
+                                (match_operand:QI 2 "const_int_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "if (INTVAL (operands[2]) >= 4)
+     FAIL; /* Open code as two shifts and an or */
+   if (INTVAL (operands[2]) > 1)
+     {
+        int i;
+        /* If we have 4 or fewer shifts, then it is probably faster
+           to emit separate ROL instructions.  A C3x requires
+           at least 4 instructions (a C4x requires at least 3), to
+           perform a rotation by shifts.  */
+        for (i = 0; i < INTVAL (operands[2]); i++)
+          emit_insn (gen_rotr_1_clobber (operands[0], operands[1]));
+        DONE;
+     }")
+
+(define_insn "rotr_1_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (rotatert:QI (match_operand:QI 1 "reg_operand" "0,0")
+                     (const_int 1)))
+   (clobber (reg:CC 21))]
+  ""
+  "ror\\t%0"
+  [(set_attr "type" "unarycc,unary")])
+; Default to int16 data attr.
+
+
+;
+; THREE OPERAND INTEGER INSTRUCTIONS
+;
+
+;
+; ADDI
+;
+(define_expand "addqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (plus:QI (match_operand:QI 1 "src_operand" "")
+                            (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "legitimize_operands (PLUS, operands, QImode);")
+
+(define_insn "*addqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (PLUS, operands, QImode)"
+  "@
+   addi3\\t%2,%1,%0
+   addi3\\t%2,%1,%0
+   addi\\t%2,%0
+   addi3\\t%2,%1,%0
+   addi3\\t%2,%1,%0
+   addi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+(define_insn "*addqi3_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d,?d,d"))]
+  "valid_operands (PLUS, operands, QImode)"
+  "@
+   addi3\\t%2,%1,%0
+   addi3\\t%2,%1,%0
+   addi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+; Default to int16 data attr.
+
+; gcc does this in combine.c we just reverse it here
+(define_insn "*cmp_neg"
+  [(set (reg:CC_NOOV 21)
+       (compare:CC_NOOV (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                        (neg: QI (match_operand:QI 2 "src_operand" "JR,rS<>,g"))))
+   (clobber (match_scratch:QI 0 "=d,?d,d"))]
+  "valid_operands (PLUS, operands, QImode)"
+  "@
+   addi3\\t%2,%1,%0
+   addi3\\t%2,%1,%0
+   addi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+  
+(define_peephole
+  [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
+                   (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                            (match_operand:QI 2 "src_operand" "JR,rS<>,g")))
+              (clobber (reg:CC_NOOV 21))])
+   (set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (match_dup 0) (const_int 0)))]
+  "valid_operands (PLUS, operands, QImode)"
+  "@
+   addi3\\t%2,%1,%0
+   addi3\\t%2,%1,%0
+   addi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+(define_insn "*addqi3_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                         (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
+        (plus:QI (match_dup 1) (match_dup 2)))]
+  "valid_operands (PLUS, operands, QImode)"
+  "@
+   addi3\\t%2,%1,%0
+   addi3\\t%2,%1,%0
+   addi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+; Default to int16 data attr.
+
+; This pattern is required primarily for manipulating the stack pointer
+; where GCC doesn't expect CC to be clobbered.
+(define_insn "addqi3_noclobber"
+  [(set (match_operand:QI 0 "std_reg_operand" "=c,?c,c")
+        (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,g")))]
+  "valid_operands (PLUS, operands, QImode)"
+  "@
+   addi3\\t%2,%1,%0
+   addi3\\t%2,%1,%0
+   addi\\t%2,%0"
+  [(set_attr "type" "binary,binary,binary")])
+; Default to int16 data attr.
+
+
+(define_insn "*addqi3_carry_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+   (use (reg:CC_NOOV 21))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (PLUS, operands, QImode)"
+  "@
+   addc3\\t%2,%1,%0
+   addc3\\t%2,%1,%0
+   addc\\t%2,%0
+   addc3\\t%2,%1,%0
+   addc3\\t%2,%1,%0
+   addc\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+
+;
+; SUBI/SUBRI
+;
+(define_expand "subqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (minus:QI (match_operand:QI 1 "src_operand" "")
+                             (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "legitimize_operands (MINUS, operands, QImode);")
+
+(define_insn "*subqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c")
+        (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g,rR,rS<>,0,g")
+                  (match_operand:QI 2 "src_operand" "JR,rS<>,g,0,JR,rS<>,g,0")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (MINUS, operands, QImode)"
+  "@
+   subi3\\t%2,%1,%0
+   subi3\\t%2,%1,%0
+   subi\\t%2,%0
+   subri\\t%1,%0
+   subi3\\t%2,%1,%0
+   subi3\\t%2,%1,%0
+   subi\\t%2,%0
+   subri\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc,binary,binary,binary,binary")])
+; Default to int16 data attr.
+
+(define_insn "*subqi3_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
+                                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,0"))
+                         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d,?d,d,d"))]
+  "valid_operands (MINUS, operands, QImode)"
+  "@
+   subi3\\t%2,%1,%0
+   subi3\\t%2,%1,%0
+   subi\\t%2,%0
+   subri\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+; Default to int16 data attr.
+
+(define_peephole
+  [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
+                   (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
+                             (match_operand:QI 2 "src_operand" "JR,rS<>,g,0")))
+              (clobber (reg:CC_NOOV 21))])
+   (set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (match_dup 0) (const_int 0)))]
+  "valid_operands (MINUS, operands, QImode)"
+  "@
+   subi3\\t%2,%1,%0
+   subi3\\t%2,%1,%0
+   subi\\t%2,%0
+   subri\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+  
+(define_insn "*subqi3_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
+                                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,0"))
+                         (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
+        (minus:QI (match_dup 1)
+                  (match_dup 2)))]
+  "valid_operands (MINUS, operands, QImode)"
+  "@
+   subi3\\t%2,%1,%0
+   subi3\\t%2,%1,%0
+   subi\\t%2,%0
+   subri\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+; Default to int16 data attr.
+
+(define_insn "*subqi3_carry_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c")
+        (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g,rR,rS<>,0,g")
+                  (match_operand:QI 2 "src_operand" "JR,rS<>,0,g,JR,rS<>,g,0")))
+   (use (reg:CC_NOOV 21))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (MINUS, operands, QImode)"
+  "@
+   subb3\\t%2,%1,%0
+   subb3\\t%2,%1,%0
+   subb\\t%2,%0
+   subrb\\t%1,%0
+   subb3\\t%2,%1,%0
+   subb3\\t%2,%1,%0
+   subb\\t%2,%0
+   subrb\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc,binary,binary,binary,binary")])
+; Default to int16 data attr.
+
+(define_insn "*subqi3_carry_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
+                                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,0"))
+                         (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
+        (minus:QI (match_dup 1)
+                  (match_dup 2)))
+   (use (reg:CC_NOOV 21))]
+  "valid_operands (MINUS, operands, QImode)"
+  "@
+   subb3\\t%2,%1,%0
+   subb3\\t%2,%1,%0
+   subb\\t%2,%0
+   subrb\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+; Default to int16 data attr.
+
+;
+; MPYI
+;
+(define_expand "mulqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (mult:QI (match_operand:QI 1 "src_operand" "")
+                            (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "if (TARGET_MPYI || (GET_CODE (operands[2]) == CONST_INT
+       && exact_log2 (INTVAL (operands[2])) >= 0))
+     legitimize_operands (MULT, operands, QImode);
+   else
+     {        
+       if (GET_CODE (operands[2]) == CONST_INT)
+         {
+          /* Let GCC try to synthesise the multiplication using shifts
+             and adds.  In most cases this will be more profitable than
+             using the C3x MPYI.  */
+            FAIL;
+         }
+       if (operands[1] == operands[2])
+         {
+            /* Do the squaring operation in-line.  */
+            emit_insn (gen_sqrqi2_inline(operands[0], operands[1]));
+            DONE;
+         }
+       if (TARGET_INLINE)
+         {
+            emit_insn (gen_mulqi3_inline(operands[0], operands[1],
+                                         operands[2]));
+            DONE;
+         }
+       c4x_emit_libcall3 (MULQI3_LIBCALL, MULT, QImode, operands);
+       DONE;
+     }
+  ")
+
+(define_insn "*mulqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (MULT, operands, QImode)"
+  "*
+  if (which_alternative == 2 || which_alternative == 5)
+    {
+      if (TARGET_C3X
+          && GET_CODE (operands[2]) == CONST_INT
+          && exact_log2 (INTVAL (operands[2])) >= 0)
+        return \"ash\\t%L2,%0\";
+      else
+        return \"mpyi\\t%2,%0\";
+    }
+  else
+      return \"mpyi3\\t%2,%1,%0\";"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+(define_insn "*mulqi3_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d,?d,d"))]
+  "valid_operands (MULT, operands, QImode)"
+  "*
+  if (which_alternative == 2)
+    {
+      if (TARGET_C3X 
+          && GET_CODE (operands[2]) == CONST_INT
+          && exact_log2 (INTVAL (operands[2])) >= 0)
+        return \"ash\\t%L2,%0\";
+      else
+        return \"mpyi\\t%2,%0\";
+    } 
+  else
+      return \"mpyi3\\t%2,%1,%0\";"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+; Default to int16 data attr.
+
+(define_insn "*mulqi3_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                         (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
+        (mult:QI (match_dup 1)
+                 (match_dup 2)))]
+  "valid_operands (MULT, operands, QImode)"
+  "*
+  if (which_alternative == 2)
+    {
+      if (TARGET_C3X 
+          && GET_CODE (operands[2]) == CONST_INT
+          && exact_log2 (INTVAL (operands[2])) >= 0)
+        return \"ash\\t%L2,%0\";
+      else
+        return \"mpyi\\t%2,%0\";
+    }
+    else
+        return \"mpyi3\\t%2,%1,%0\";"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+; Default to int16 data attr.
+
+; The C3x multiply instruction assumes 24-bit signed integer operands
+; and the 48-bit result is truncated to 32-bits.
+(define_insn "*mulqi3_24_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (mult:QI
+         (sign_extend:QI
+          (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
+                  (const_int 16777215)))
+         (sign_extend:QI
+          (and:QI (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")
+                  (const_int 16777215)))))
+   (clobber (reg:CC_NOOV 21))]
+  "TARGET_C3X && valid_operands (MULT, operands, QImode)"
+  "@
+   mpyi3\\t%2,%1,%0
+   mpyi3\\t%2,%1,%0
+   mpyi\\t%2,%0
+   mpyi3\\t%2,%1,%0
+   mpyi3\\t%2,%1,%0
+   mpyi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+
+; Fast square function for C3x where TARGET_MPYI not asserted
+(define_expand "sqrqi2_inline"
+  [(set (match_dup 7) (match_operand:QI 1 "src_operand" ""))
+   (parallel [(set (match_dup 3)
+                   (lshiftrt:QI (match_dup 7) (const_int 16)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 2)
+                   (and:QI (match_dup 7) (const_int 65535)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 4)
+                   (mult:QI (sign_extend:QI (and:QI (match_dup 2) 
+                                                    (const_int 16777215)))
+                            (sign_extend:QI (and:QI (match_dup 2) 
+                                                    (const_int 16777215)))))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 5)
+                   (mult:QI (sign_extend:QI (and:QI (match_dup 2) 
+                                                    (const_int 16777215)))
+                            (sign_extend:QI (and:QI (match_dup 3) 
+                                                    (const_int 16777215)))))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 6)
+                   (ashift:QI (match_dup 5) (const_int 17)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (plus:QI (match_dup 4) (match_dup 6)))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "
+  operands[2] = gen_reg_rtx (QImode); /* a = val & 0xffff */
+  operands[3] = gen_reg_rtx (QImode); /* b = val >> 16 */
+  operands[4] = gen_reg_rtx (QImode); /* a * a */
+  operands[5] = gen_reg_rtx (QImode); /* a * b */
+  operands[6] = gen_reg_rtx (QImode); /* (a * b) << 17 */
+  operands[7] = gen_reg_rtx (QImode); /* val */
+  ")
+
+; Inlined integer multiply for C3x
+(define_expand "mulqi3_inline"
+  [(set (match_dup 12) (const_int -16))
+   (set (match_dup 13) (match_operand:QI 1 "src_operand" ""))
+   (set (match_dup 14) (match_operand:QI 2 "src_operand" ""))
+   (parallel [(set (match_dup 4)
+                   (lshiftrt:QI (match_dup 13) (neg:QI (match_dup 12))))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 6)
+                   (lshiftrt:QI (match_dup 14) (neg:QI (match_dup 12))))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 3)
+                   (and:QI (match_dup 13)
+                           (const_int 65535)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 5)
+                   (and:QI (match_dup 14) 
+                           (const_int 65535)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 7)
+                   (mult:QI (sign_extend:QI (and:QI (match_dup 4) 
+                                                    (const_int 16777215)))
+                            (sign_extend:QI (and:QI (match_dup 5) 
+                                                    (const_int 16777215)))))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 8)
+                   (mult:QI (sign_extend:QI (and:QI (match_dup 3) 
+                                                    (const_int 16777215)))
+                            (sign_extend:QI (and:QI (match_dup 5) 
+                                                    (const_int 16777215)))))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 9)
+                   (mult:QI (sign_extend:QI (and:QI (match_dup 3) 
+                                                    (const_int 16777215)))
+                            (sign_extend:QI (and:QI (match_dup 6) 
+                                                    (const_int 16777215)))))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 10)
+                   (plus:QI (match_dup 7) (match_dup 9)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 11)
+                   (ashift:QI (match_dup 10) (const_int 16)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (plus:QI (match_dup 8) (match_dup 11)))
+              (clobber (reg:CC_NOOV 21))])]
+  "TARGET_C3X"
+  "
+  operands[3] = gen_reg_rtx (QImode); /* a = arg1 & 0xffff */
+  operands[4] = gen_reg_rtx (QImode); /* b = arg1 >> 16 */
+  operands[5] = gen_reg_rtx (QImode); /* a = arg2 & 0xffff */
+  operands[6] = gen_reg_rtx (QImode); /* b = arg2 >> 16 */
+  operands[7] = gen_reg_rtx (QImode); /* b * c */
+  operands[8] = gen_reg_rtx (QImode); /* a * c */
+  operands[9] = gen_reg_rtx (QImode); /* a * d */
+  operands[10] = gen_reg_rtx (QImode); /* b * c + a * d */
+  operands[11] = gen_reg_rtx (QImode); /* (b *c + a * d) << 16 */
+  operands[12] = gen_reg_rtx (QImode); /* -16 */
+  operands[13] = gen_reg_rtx (QImode); /* arg1 */
+  operands[14] = gen_reg_rtx (QImode); /* arg2 */
+  ")
+
+;
+; MPYSHI (C4x only)
+;
+(define_expand "smulqi3_highpart"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (truncate:QI
+                    (lshiftrt:HI
+                     (mult:HI
+                      (sign_extend:HI (match_operand:QI 1 "src_operand" ""))
+                      (sign_extend:HI (match_operand:QI 2 "src_operand" "")))
+                 (const_int 32))))
+              (clobber (reg:CC_NOOV 21))])]
+ ""
+ "legitimize_operands (MULT, operands, QImode);
+  if (TARGET_C3X)
+    {
+       c4x_emit_libcall_mulhi (SMULHI3_LIBCALL, SIGN_EXTEND, QImode, operands);
+       DONE;
+    }
+ ")
+
+(define_insn "*smulqi3_highpart_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (truncate:QI 
+         (lshiftrt:HI
+          (mult:HI
+           (sign_extend:HI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0"))
+           (sign_extend:HI (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+      (const_int 32))))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X && valid_operands (MULT, operands, QImode)"
+  "@
+   mpyshi3\\t%2,%1,%0
+   mpyshi3\\t%2,%1,%0
+   mpyshi\\t%2,%0
+   mpyshi3\\t%2,%1,%0
+   mpyshi3\\t%2,%1,%0
+   mpyshi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")
+   (set_attr "data" "int16,int16,int16,int16,int16,int16")])
+
+;
+; MPYUHI (C4x only)
+;
+(define_expand "umulqi3_highpart"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+               (truncate:QI
+                (lshiftrt:HI
+                 (mult:HI
+                  (zero_extend:HI (match_operand:QI 1 "src_operand" ""))
+                  (zero_extend:HI (match_operand:QI 2 "lsrc_operand" "")))
+                 (const_int 32))))
+              (clobber (reg:CC_NOOV 21))])]
+ ""
+ "legitimize_operands (MULT, operands, QImode);
+  if (TARGET_C3X) 
+    {
+      c4x_emit_libcall_mulhi (UMULHI3_LIBCALL, ZERO_EXTEND, QImode, operands);
+      DONE;
+    }
+ ")
+
+(define_insn "*umulqi3_highpart_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (truncate:QI
+         (lshiftrt:HI
+          (mult:HI 
+           (zero_extend:HI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0"))
+           (zero_extend:HI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,g,JR,rS<>,g")))
+          (const_int 32))))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X && valid_operands (MULT, operands, QImode)"
+  "@
+   mpyuhi3\\t%2,%1,%0
+   mpyuhi3\\t%2,%1,%0
+   mpyuhi\\t%2,%0
+   mpyuhi3\\t%2,%1,%0
+   mpyuhi3\\t%2,%1,%0
+   mpyuhi\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")
+   (set_attr "data" "uint16,uint16,uint16,uint16,uint16,uint16")])
+
+;
+; AND
+;
+(define_expand "andqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (and:QI (match_operand:QI 1 "src_operand" "")
+                           (match_operand:QI 2 "tsrc_operand" "")))
+              (clobber (reg:CC 21))])]
+ ""
+ "legitimize_operands (AND, operands, QImode);")
+
+(define_insn "*andqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c")
+        (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,0,rR,rS<>,0,0")
+                (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm,JR,rS<>,N,rLm")))
+   (clobber (reg:CC 21))]
+  "valid_operands (AND, operands, QImode)"
+  "@
+   and3\\t%2,%1,%0
+   and3\\t%2,%1,%0
+   andn\\t%N2,%0
+   and\\t%2,%0
+   and3\\t%2,%1,%0
+   and3\\t%2,%1,%0
+   andn\\t%N2,%0
+   and\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc,binary,binary,binary,binary")
+   (set_attr "data" "int16,uint16,not_uint16,uint16,int16,uint16,not_uint16,uint16")])
+
+(define_insn "*andqi3_test"
+  [(set (reg:CC 21)
+        (compare:CC (and:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,r")
+                            (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm"))
+                    (const_int 0)))
+   (clobber (match_scratch:QI 0 "=X,X,d,X"))]
+  "valid_operands (AND, operands, QImode)"
+  "@
+   tstb3\\t%2,%1
+   tstb3\\t%2,%1
+   andn\\t%N2,%0
+   tstb\\t%2,%1"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,not_uint16,uint16")])
+
+(define_peephole
+  [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
+                   (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,0")
+                           (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm")))
+              (clobber (reg:CC 21))])
+   (set (reg:CC 21)
+        (compare:CC (match_dup 0) (const_int 0)))]
+  "valid_operands (AND, operands, QImode)"
+  "@
+   and3\\t%2,%1,%0
+   and3\\t%2,%1,%0
+   andn\\t%N2,%0
+   and\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,not_uint16,uint16")])
+  
+(define_insn "*andqi3_set"
+  [(set (reg:CC 21)
+        (compare:CC (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,0")
+                            (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm"))
+                    (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
+        (and:QI (match_dup 1)
+                (match_dup 2)))]
+  "valid_operands (AND, operands, QImode)"
+  "@
+   and3\\t%2,%1,%0
+   and3\\t%2,%1,%0
+   andn\\t%N2,%0
+   and\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,not_uint16,uint16")])
+
+;
+; ANDN
+;
+; NB, this insn doesn't have commutative operands, but valid_operands
+; assumes that the code AND does.  We might have to kludge this if
+; we make valid_operands stricter.
+(define_insn "*andnqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (and:QI (not:QI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm,JR,rS<>,rLm"))
+                (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")))
+   (clobber (reg:CC 21))]
+  "valid_operands (AND, operands, QImode)"
+  "@
+   andn3\\t%2,%1,%0
+   andn3\\t%2,%1,%0
+   andn\\t%2,%0
+   andn3\\t%2,%1,%0
+   andn3\\t%2,%1,%0
+   andn\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")
+   (set_attr "data" "int16,uint16,uint16,int16,uint16,uint16")])
+
+(define_insn "*andnqi3_test"
+  [(set (reg:CC 21)
+        (compare:CC (and:QI (not:QI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm"))
+                            (match_operand:QI 1 "src_operand" "rR,rS<>,0"))
+                    (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d,?d,d"))]
+  "valid_operands (AND, operands, QImode)"
+  "@
+   andn3\\t%2,%1,%0
+   andn3\\t%2,%1,%0
+   andn\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,uint16")])
+
+(define_insn "*andnqi3_set"
+  [(set (reg:CC 21)
+        (compare:CC (and:QI (not:QI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm"))
+                            (match_operand:QI 1 "src_operand" "rR,rS<>,0"))
+                    (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
+        (and:QI (not:QI (match_dup 2))
+                (match_dup 1)))]
+  "valid_operands (AND, operands, QImode)"
+  "@
+   andn3\\t%2,%1,%0
+   andn3\\t%2,%1,%0
+   andn\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,uint16")])
+
+;
+; OR
+;
+(define_expand "iorqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (ior:QI (match_operand:QI 1 "src_operand" "")
+                           (match_operand:QI 2 "lsrc_operand" "")))
+              (clobber (reg:CC 21))])]
+ ""
+ "legitimize_operands (IOR, operands, QImode);")
+
+(define_insn "*iorqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
+                (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm,JR,rS<>,rLm")))
+   (clobber (reg:CC 21))]
+  "valid_operands (IOR, operands, QImode)"
+  "@
+   or3\\t%2,%1,%0
+   or3\\t%2,%1,%0
+   or\\t%2,%0
+   or3\\t%2,%1,%0
+   or3\\t%2,%1,%0
+   or\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")
+   (set_attr "data" "int16,uint16,uint16,int16,uint16,uint16")])
+
+(define_insn "*iorqi3_test"
+  [(set (reg:CC 21)
+        (compare:CC (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                            (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm"))
+                    (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d,?d,d"))]
+  "valid_operands (IOR, operands, QImode)"
+  "@
+   or3\\t%2,%1,%0
+   or3\\t%2,%1,%0
+   or\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,uint16")])
+
+(define_peephole
+  [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
+                   (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                           (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")))
+              (clobber (reg:CC 21))])
+   (set (reg:CC 21)
+        (compare:CC (match_dup 0) (const_int 0)))]
+  "valid_operands (IOR, operands, QImode)"
+  "@
+   or3\\t%2,%1,%0
+   or3\\t%2,%1,%0
+   or\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,uint16")])
+  
+(define_insn "*iorqi3_set"
+  [(set (reg:CC 21)
+        (compare:CC (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                            (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm"))
+                    (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
+        (ior:QI (match_dup 1)
+                (match_dup 2)))]
+  "valid_operands (IOR, operands, QImode)"
+  "@
+   or3\\t%2,%1,%0
+   or3\\t%2,%1,%0
+   or\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,uint16")])
+
+; This pattern is used for loading symbol references in several parts. 
+(define_insn "iorqi3_noclobber"
+  [(set (match_operand:QI 0 "std_reg_operand" "=c,?c,c")
+        (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")))]
+  "valid_operands (IOR, operands, QImode)"
+  "@
+   or3\\t%2,%1,%0
+   or3\\t%2,%1,%0
+   or\\t%2,%0"
+  [(set_attr "type" "binary,binary,binary")
+   (set_attr "data" "int16,uint16,uint16")])
+
+;
+; XOR
+;
+(define_expand "xorqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (xor:QI (match_operand:QI 1 "src_operand" "")
+                           (match_operand:QI 2 "lsrc_operand" "")))
+              (clobber (reg:CC 21))])]
+ ""
+ "legitimize_operands (XOR, operands, QImode);")
+
+(define_insn "*xorqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (xor:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
+                (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm,JR,rS<>,rLm")))
+   (clobber (reg:CC 21))]
+  "valid_operands (XOR, operands, QImode)"
+  "@
+   xor3\\t%2,%1,%0
+   xor3\\t%2,%1,%0
+   xor\\t%2,%0
+   xor3\\t%2,%1,%0
+   xor3\\t%2,%1,%0
+   xor\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")
+   (set_attr "data" "int16,uint16,uint16,int16,uint16,uint16")])
+
+(define_insn "*xorqi3_test"
+  [(set (reg:CC 21)
+        (compare:CC (xor:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                            (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm"))
+                    (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d,?d,d"))]
+  "valid_operands (XOR, operands, QImode)"
+  "@
+   xor3\\t%2,%1,%0
+   xor3\\t%2,%1,%0
+   xor\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,uint16")])
+
+(define_insn "*xorqi3_set"
+  [(set (reg:CC 21)
+        (compare:CC (xor:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
+                            (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm"))
+                    (const_int 0)))
+   (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
+        (xor:QI (match_dup 1)
+                (match_dup 2)))]
+  "valid_operands (XOR, operands, QImode)"
+  "@
+   xor3\\t%2,%1,%0
+   xor3\\t%2,%1,%0
+   xor\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")
+   (set_attr "data" "int16,uint16,uint16")])
+
+;
+; LSH/ASH (left)
+;
+; The C3x and C4x have two shift instructions ASH and LSH
+; If the shift count is positive, a left shift is performed
+; otherwise a right shift is performed.  The number of bits
+; shifted is determined by the seven LSBs of the shift count.
+; If the absolute value of the count is 32 or greater, the result
+; using the LSH instruction is zero; with the ASH insn the result
+; is zero or negative 1.   Note that the ISO C standard allows 
+; the result to be machine dependent whenever the shift count
+; exceeds the size of the object.
+(define_expand "ashlqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (ashift:QI (match_operand:QI 1 "src_operand" "")
+                              (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+ ""
+ "legitimize_operands (ASHIFT, operands, QImode);")
+
+(define_insn "*ashlqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")
+                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+   (clobber (reg:CC 21))]
+  "valid_operands (ASHIFT, operands, QImode)"
+  "@
+   ash3\\t%2,%1,%0
+   ash3\\t%2,%1,%0
+   ash\\t%2,%0
+   ash3\\t%2,%1,%0
+   ash3\\t%2,%1,%0
+   ash\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+(define_insn "*ashlqi3_set"
+  [(set (reg:CC 21)
+        (compare:CC
+          (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")
+                     (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g"))
+          (const_int 0)))
+   (set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (ashift:QI (match_dup 1)
+                   (match_dup 2)))]
+  "valid_operands (ASHIFT, operands, QImode)"
+  "@
+   ash3\\t%2,%1,%0
+   ash3\\t%2,%1,%0
+   ash\\t%2,%0
+   ash3\\t%2,%1,%0
+   ash3\\t%2,%1,%0
+   ash\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+; This is only used by lshrhi3_reg where we need a LSH insn that will
+; shift both ways.
+(define_insn "*lshlqi3_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")
+                   (unspec [(match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")] 3)))
+   (clobber (reg:CC 21))]
+  "valid_operands (ASHIFT, operands, QImode)"
+  "@
+   lsh3\\t%2,%1,%0
+   lsh3\\t%2,%1,%0
+   lsh\\t%2,%0
+   lsh3\\t%2,%1,%0
+   lsh3\\t%2,%1,%0
+   lsh\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+;
+; LSH (right)
+;
+; Logical right shift on the C[34]x works by negating the shift count,
+; then emitting a right shift with the shift count negated.  This means
+; that all actual shift counts in the RTL will be positive.
+;
+(define_expand "lshrqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (lshiftrt:QI (match_operand:QI 1 "src_operand" "")
+                                (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "legitimize_operands (LSHIFTRT, operands, QImode);")
+
+; When the shift count is greater than the size of the word
+; the result can be implementation specific
+(define_insn "*lshrqi3_const_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c,?d,?c")
+        (lshiftrt:QI (match_operand:QI 1 "src_operand" "0,0,r,r")
+                     (match_operand:QI 2 "const_int_operand" "n,n,J,J")))
+   (clobber (reg:CC 21))]
+  "valid_operands (LSHIFTRT, operands, QImode)"
+  "@
+   lsh\\t%n2,%0
+   lsh\\t%n2,%0
+   lsh3\\t%n2,%1,%0
+   lsh3\\t%n2,%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+
+; When the shift count is greater than the size of the word
+; the result can be implementation specific
+(define_insn "*lshrqi3_const_set"
+  [(set (reg:CC 21)
+        (compare:CC
+          (lshiftrt:QI (match_operand:QI 1 "src_operand" "0,0,r,r")
+                       (match_operand:QI 2 "const_int_operand" "n,n,J,J"))
+          (const_int 0)))
+   (set (match_operand:QI 0 "reg_operand" "=?d,?c,d,c")
+        (lshiftrt:QI (match_dup 1)
+                     (match_dup 2)))]
+  "valid_operands (LSHIFTRT, operands, QImode)"
+  "@
+   lsh\\t%n2,%0
+   lsh\\t%n2,%0
+   lsh3\\t%n2,%1,%0
+   lsh3\\t%n2,%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+
+(define_insn "*lshrqi3_nonconst_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (lshiftrt:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")
+                     (neg:QI (match_operand:QI 2 "src_operand" "R,rS<>,rm,R,rS<>,rm"))))
+   (clobber (reg:CC 21))]
+  "valid_operands (LSHIFTRT, operands, QImode)"
+  "@
+   lsh3\\t%2,%1,%0
+   lsh3\\t%2,%1,%0
+   lsh\\t%2,%0
+   lsh3\\t%2,%1,%0
+   lsh3\\t%2,%1,%0
+   lsh\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+;
+; ASH (right)
+;
+; Arithmetic right shift on the C[34]x works by negating the shift count,
+; then emitting a right shift with the shift count negated.  This means
+; that all actual shift counts in the RTL will be positive.
+
+(define_expand "ashrqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (ashiftrt:QI (match_operand:QI 1 "src_operand" "")
+                                (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "legitimize_operands (ASHIFTRT, operands, QImode);")
+
+; When the shift count is greater than the size of the word
+; the result can be implementation specific
+(define_insn "*ashrqi3_const_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c,?d,?c")
+        (ashiftrt:QI (match_operand:QI 1 "src_operand" "0,0,r,r")
+                     (match_operand:QI 2 "const_int_operand" "n,n,J,J")))
+   (clobber (reg:CC 21))]
+  "valid_operands (ASHIFTRT, operands, QImode)"
+  "@
+   ash\\t%n2,%0
+   ash\\t%n2,%0
+   ash3\\t%n2,%1,%0
+   ash3\\t%n2,%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+
+; When the shift count is greater than the size of the word
+; the result can be implementation specific
+(define_insn "*ashrqi3_const_set"
+  [(set (reg:CC 21)
+        (compare:CC
+          (ashiftrt:QI (match_operand:QI 1 "src_operand" "0,0,r,r")
+                       (match_operand:QI 2 "const_int_operand" "n,n,J,J"))
+          (const_int 0)))
+   (set (match_operand:QI 0 "reg_operand" "=?d,?c,d,c")
+        (ashiftrt:QI (match_dup 1)
+                     (match_dup 2)))]
+  "valid_operands (ASHIFTRT, operands, QImode)"
+  "@
+   ash\\t%n2,%0
+   ash\\t%n2,%0
+   ash3\\t%n2,%1,%0
+   ash3\\t%n2,%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+
+(define_insn "*ashrqi3_nonconst_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
+        (ashiftrt:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")
+                     (neg:QI (match_operand:QI 2 "src_operand" "R,rS<>,rm,R,rS<>,rm"))))
+   (clobber (reg:CC 21))]
+  "valid_operands (ASHIFTRT, operands, QImode)"
+  "@
+   ash3\\t%2,%1,%0
+   ash3\\t%2,%1,%0
+   ash\\t%2,%0
+   ash3\\t%2,%1,%0
+   ash3\\t%2,%1,%0
+   ash\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")])
+; Default to int16 data attr.
+
+;
+; CMPI
+;
+; Unfortunately the C40 doesn't allow cmpi3 7, *ar0++ so the next best
+; thing would be to get the small constant loaded into a register (say r0)
+; so that it could be hoisted out of the loop so that we only
+; would need to do cmpi3 *ar0++, r0.  Now the loop optimisation pass
+; comes before the flow pass (which finds autoincrements) so we're stuck.
+; Ideally, GCC requires another loop optimisation pass (preferably after
+; reload) so that it can hoist invariants out of loops.
+; The current solution modifies legitimize_operands () so that small
+; constants are forced into a pseudo register.
+; 
+(define_expand "cmpqi"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:QI 0 "src_operand" "")
+                    (match_operand:QI 1 "src_operand" "")))]
+  ""
+  "legitimize_operands (COMPARE, operands, QImode);
+   c4x_compare_op0 = operands[0];
+   c4x_compare_op1 = operands[1];
+   DONE;")
+
+(define_insn "*cmpqi_test"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:QI 0 "src_operand" "rR,?rS<>,r")
+                    (match_operand:QI 1 "src_operand" "JR,rS<>,g")))]
+  "valid_operands (COMPARE, operands, QImode)"
+  "@
+   cmpi3\\t%1,%0
+   cmpi3\\t%1,%0
+   cmpi\\t%1,%0"
+  [(set_attr "type" "compare,compare,compare")])
+
+(define_insn "*cmpqi_test_noov"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (match_operand:QI 0 "src_operand" "rR,?rS<>,r")
+                         (match_operand:QI 1 "src_operand" "JR,rS<>,g")))]
+  "valid_operands (COMPARE, operands, QImode)"
+  "@
+   cmpi3\\t%1,%0
+   cmpi3\\t%1,%0
+   cmpi\\t%1,%0"
+  [(set_attr "type" "compare,compare,compare")])
+
+(define_expand "udivqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (udiv:QI (match_operand:QI 1 "src_operand" "")
+                            (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (UDIVQI3_LIBCALL, UDIV, QImode, operands);
+   DONE;")
+
+(define_expand "divqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (div:QI (match_operand:QI 1 "src_operand" "")
+                            (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (DIVQI3_LIBCALL, DIV, QImode, operands);
+   DONE;")
+
+(define_expand "umodqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (umod:QI (match_operand:QI 1 "src_operand" "")
+                            (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (UMODQI3_LIBCALL, UMOD, QImode, operands);
+   DONE;")
+
+(define_expand "modqi3"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (mod:QI (match_operand:QI 1 "src_operand" "")
+                           (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (MODQI3_LIBCALL, MOD, QImode, operands);
+   DONE;")
+
+(define_expand "ffsqi2"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (ffs:QI (match_operand:QI 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FFS_LIBCALL, FFS, QImode, QImode, 2, operands);
+   DONE;")
+
+;
+; BIT-FIELD INSTRUCTIONS
+;
+
+;
+; LBx/LHw (C4x only)
+;
+(define_expand "extv"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (sign_extract:QI (match_operand:QI 1 "src_operand" "")
+                                    (match_operand:QI 2 "const_int_operand" "")
+                                    (match_operand:QI 3 "const_int_operand" "")))
+              (clobber (reg:CC 21))])]
+ "!TARGET_C3X"
+ "if ((INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16)
+      || (INTVAL (operands[3]) % INTVAL (operands[2]) != 0))
+        FAIL;
+ ")
+
+(define_insn "*extv_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (sign_extract:QI (match_operand:QI 1 "src_operand" "g,g")
+                         (match_operand:QI 2 "const_int_operand" "n,n")
+                         (match_operand:QI 3 "const_int_operand" "n,n")))
+   (clobber (reg:CC 21))]
+  "!TARGET_C3X
+   && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
+   && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)"
+  "*
+   if (INTVAL (operands[2]) == 8)
+     {
+       operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 8);
+       return \"lb%3\\t%1,%0\";
+     }
+   operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 16);
+   return \"lh%3\\t%1,%0\";
+  "
+  [(set_attr "type" "binarycc,binary")
+   (set_attr "data" "int16,int16")])
+
+(define_insn "*extv_clobber_test"
+  [(set (reg:CC 21)
+        (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "g")
+                                     (match_operand:QI 2 "const_int_operand" "n")
+                                     (match_operand:QI 3 "const_int_operand" "n"))
+                   (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d"))]
+  "!TARGET_C3X
+   && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
+   && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)"
+  "*
+   if (INTVAL (operands[2]) == 8)
+     {
+       operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 8);
+       return \"lb%3\\t%1,%0\";
+     }
+   operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 16);
+   return \"lh%3\\t%1,%0\";
+  "
+  [(set_attr "type" "binarycc")
+   (set_attr "data" "int16")])
+
+(define_insn "*extv_clobber_set"
+  [(set (reg:CC 21)
+        (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "g")
+                                     (match_operand:QI 2 "const_int_operand" "n")
+                                     (match_operand:QI 3 "const_int_operand" "n"))
+                   (const_int 0)))
+   (set (match_operand:QI 0 "reg_operand" "=d")
+        (sign_extract:QI (match_dup 1)
+                         (match_dup 2)
+                         (match_dup 3)))]
+  "!TARGET_C3X
+   && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
+   && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)"
+  "*
+   if (INTVAL (operands[2]) == 8)
+     {
+       operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 8);
+       return \"lb%3\\t%1,%0\";
+     }
+   operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 16);
+   return \"lh%3\\t%1,%0\";
+  "
+  [(set_attr "type" "binarycc")
+   (set_attr "data" "int16")])
+
+;
+; LBUx/LHUw (C4x only)
+;
+(define_expand "extzv"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (zero_extract:QI (match_operand:QI 1 "src_operand" "")
+                                    (match_operand:QI 2 "const_int_operand" "")
+                                    (match_operand:QI 3 "const_int_operand" "")))
+              (clobber (reg:CC 21))])]
+ "!TARGET_C3X"
+ "if ((INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16)
+      || (INTVAL (operands[3]) % INTVAL (operands[2]) != 0))
+        FAIL;
+ ")
+
+(define_insn "*extzv_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (zero_extract:QI (match_operand:QI 1 "src_operand" "g,g")
+                         (match_operand:QI 2 "const_int_operand" "n,n")
+                         (match_operand:QI 3 "const_int_operand" "n,n")))
+   (clobber (reg:CC 21))]
+  "!TARGET_C3X
+   && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
+   && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)"
+  "*
+   if (INTVAL (operands[2]) == 8)
+     {
+       operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 8);
+       return \"lbu%3\\t%1,%0\";
+     }
+   operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 16);
+   return \"lhu%3\\t%1,%0\";
+  "
+  [(set_attr "type" "binarycc,binary")
+   (set_attr "data" "uint16,uint16")])
+
+(define_insn "*extzv_test"
+  [(set (reg:CC 21)
+        (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "g")
+                                     (match_operand:QI 2 "const_int_operand" "n")
+                                     (match_operand:QI 3 "const_int_operand" "n"))
+                   (const_int 0)))
+   (clobber (match_scratch:QI 0 "=d"))]
+  "!TARGET_C3X
+   && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
+   && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)"
+  "*
+   if (INTVAL (operands[2]) == 8)
+     {
+       operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 8);
+       return \"lbu%3\\t%1,%0\";
+     }
+   operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 16);
+   return \"lhu%3\\t%1,%0\";
+  "
+  [(set_attr "type" "binarycc")
+   (set_attr "data" "uint16")])
+
+(define_insn "*extzv_set"
+  [(set (reg:CC 21)
+        (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "g")
+                                     (match_operand:QI 2 "const_int_operand" "n")
+                                     (match_operand:QI 3 "const_int_operand" "n"))
+                   (const_int 0)))
+   (set (match_operand:QI 0 "reg_operand" "=d")
+        (zero_extract:QI (match_dup 1)
+                         (match_dup 2)
+                         (match_dup 3)))]
+  "!TARGET_C3X
+   && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
+   && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)"
+  "*
+   if (INTVAL (operands[2]) == 8)
+     {
+       operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 8);
+       return \"lbu%3\\t%1,%0\";
+     }
+   operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[3]) / 16);
+   return \"lhu%3\\t%1,%0\";
+  "
+  [(set_attr "type" "binarycc")
+   (set_attr "data" "uint16")])
+
+;
+; MBx/MHw (C4x only)
+;
+(define_expand "insv"
+  [(parallel [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "")
+                                    (match_operand:QI 1 "const_int_operand" "")
+                                    (match_operand:QI 2 "const_int_operand" ""))
+                   (match_operand:QI 3 "src_operand" ""))
+              (clobber (reg:CC 21))])]
+ "!TARGET_C3X"
+ "if (!(((INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
+         && (INTVAL (operands[2]) % INTVAL (operands[1]) == 0))
+        || (INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8)))
+    FAIL;
+ ")
+
+(define_insn "*insv_clobber"
+  [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "=d,c")
+                         (match_operand:QI 1 "const_int_operand" "n,n")
+                         (match_operand:QI 2 "const_int_operand" "n,n"))
+        (match_operand:QI 3 "src_operand" "g,g"))
+   (clobber (reg:CC 21))]
+  "!TARGET_C3X
+   && (((INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
+        && (INTVAL (operands[2]) % INTVAL (operands[1]) == 0))
+       || (INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8))"
+  "*
+   if (INTVAL (operands[1]) == 8)
+     {
+       operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) / 8);
+       return \"mb%2\\t%3,%0\";
+     }
+   else if (INTVAL (operands[1]) == 16)
+     {
+       operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) / 16);
+       return \"mh%2\\t%3,%0\";
+     }
+   return \"lwl1\\t%3,%0\";
+  "
+  [(set_attr "type" "binarycc,binary")
+   (set_attr "data" "uint16,uint16")])
+
+(define_peephole
+  [(parallel [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "=d")
+                                    (match_operand:QI 1 "const_int_operand" "n")
+                                    (match_operand:QI 2 "const_int_operand" "n"))
+                   (match_operand:QI 3 "src_operand" "g"))
+             (clobber (reg:CC 21))])
+   (set (reg:CC 21)
+        (compare:CC (match_dup 0) (const_int 0)))]
+  "!TARGET_C3X
+   && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
+   && (INTVAL (operands[2]) % INTVAL (operands[1]) == 0)"
+  "*
+   if (INTVAL (operands[1]) == 8)
+     {
+       operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) / 8);
+       return \"mb%2\\t%3,%0\";
+     }
+   operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) / 16);
+   return \"mh%2\\t%3,%0\";
+  "
+  [(set_attr "type" "binarycc")
+   (set_attr "data" "uint16")])
+
+;
+; TWO OPERAND FLOAT INSTRUCTIONS
+;
+
+;
+; LDF/STF
+;
+;  If one of the operands is not a register, then we should
+;  emit two insns, using a scratch register.  This will produce
+;  better code in loops if the source operand is invariant, since
+;  the source reload can be optimised out.  During reload we cannot
+;  use change_address or force_reg.
+(define_expand "movqf"
+  [(set (match_operand:QF 0 "src_operand" "")
+        (match_operand:QF 1 "src_operand" ""))]
+ ""
+ "
+  if (CONSTANT_P (operands[1]) && !const_operand (operands[1], QFmode))
+    {
+      operands[1] = force_const_mem (QFmode, operands[1]);
+      if (!memory_address_p (QFmode, XEXP (operands[1], 0))
+          && !reload_in_progress)
+        operands[1] = change_address (operands[1], QFmode,
+                                      XEXP (operands[1], 0));
+    }
+
+  if (!reload_in_progress
+      && !reg_operand (operands[0], QFmode)
+      && !reg_operand (operands[1], QFmode))
+    operands[1] = force_reg (QFmode, operands[1]);
+ ")
+
+; We must provide an alternative to store to memory in case we have to
+; spill a register.
+(define_insn "*movqf_noclobber"
+ [(set (match_operand:QF 0 "src_operand" "=f,m")
+       (match_operand:QF 1 "src_operand" "fmH,f"))]
+ "reg_operand (operands[0], QFmode)
+  || reg_operand (operands[1], QFmode)"
+ "@
+  ldfu\\t%1,%0
+  stf\\t%1,%0"
+  [(set_attr "type" "unary,store")])
+
+;(define_insn "*movqf_clobber"
+;  [(set (match_operand:QF 0 "reg_operand" "=f")
+;        (match_operand:QF 1 "src_operand" "fmH"))
+;   (clobber (reg:CC 21))]
+; "0"
+; "ldf\\t%1,%0"
+;  [(set_attr "type" "unarycc")])
+
+(define_insn "*movqf_test"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:QF 1 "src_operand" "fmH")
+                    (const_int 0)))
+   (clobber (match_scratch:QF 0 "=f"))]
+ ""
+ "ldf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*movqf_set"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:QF 1 "src_operand" "fmH")
+                    (match_operand:QF 2 "fp_zero_operand" "G")))
+    (set (match_operand:QF 0 "reg_operand" "=f")
+         (match_dup 1))]
+ ""
+ "ldf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*movqf_update"
+  [(set (match_operand:QF 0 "reg_operand" "=r") 
+        (mem:QF (plus:QI (match_operand:QI 1 "addr_reg_operand" "a")
+                         (match_operand:QI 2 "index_reg_operand" "x"))))
+   (set (match_dup 1)
+        (plus:QI (match_dup 1) (match_dup 2)))]
+  ""
+  "ldfu\\t*%1++(%2),%0"
+  [(set_attr "type" "unary")])
+
+(define_insn "*movqf_parallel"
+ [(set (match_operand:QF 0 "parallel_operand" "=q,S<>,q,S<>")
+       (match_operand:QF 1 "parallel_operand" "S<>,q,S<>,q"))
+  (set (match_operand:QF 2 "parallel_operand" "=q,S<>,S<>,q")
+       (match_operand:QF 3 "parallel_operand" "S<>,q,q,S<>"))]
+ "valid_parallel_operands_4 (operands, QFmode)"
+ "@
+  ldf1\\t%1,%0\\n||\\tldf2\\t%3,%2
+  stf1\\t%1,%0\\n||\\tstf2\\t%3,%2
+  ldf\\t%1,%0\\n||\\tstf\\t%3,%2
+  ldf\\t%3,%2\\n||\\tstf\\t%1,%0"
+  [(set_attr "type" "load_load,store_store,load_store,store_load")])
+
+
+;
+; PUSH/POP
+;
+(define_insn "*pushqf"
+  [(set (mem:QF (pre_inc:QI (reg:QI 20)))
+        (match_operand:QF 0 "reg_operand" "f"))]
+ ""
+ "pushf\\t%0"
+ [(set_attr "type" "push")])
+
+(define_insn "*popqf"
+  [(set (match_operand:QF 0 "reg_operand" "=f")
+        (mem:QF (post_dec:QI (reg:QI 20))))
+   (clobber (reg:CC 21))]
+ ""
+ "popf\\t%0"
+ [(set_attr "type" "pop")])
+
+
+;
+; ABSF
+;
+(define_expand "absqf2"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (abs:QF (match_operand:QF 1 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+""
+"")
+
+(define_insn "*absqf2_clobber"
+  [(set (match_operand:QF 0 "reg_operand" "=f")
+        (abs:QF (match_operand:QF 1 "src_operand" "fmH")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "absf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*absqf2_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fmH"))
+                         (match_operand:QF 2 "fp_zero_operand" "G")))
+   (clobber (match_scratch:QF 0 "=f"))]
+  ""
+  "absf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*absqf2_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fmH"))
+                         (match_operand:QF 2 "fp_zero_operand" "G")))
+   (set (match_operand:QF 0 "reg_operand" "=f")
+        (abs:QF (match_dup 1)))]
+
+  ""
+  "absf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; NEGF
+;
+(define_expand "negqf2"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (neg:QF (match_operand:QF 1 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+""
+"")
+
+(define_insn "*negqf2_clobber"
+  [(set (match_operand:QF 0 "reg_operand" "=f")
+        (neg:QF (match_operand:QF 1 "src_operand" "fmH")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "negf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*negqf2_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fmH"))
+                         (match_operand:QF 2 "fp_zero_operand" "G")))
+   (clobber (match_scratch:QF 0 "=f"))]
+  ""
+  "negf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*negqf2_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fmH"))
+                         (match_operand:QF 2 "fp_zero_operand" "G")))
+   (set (match_operand:QF 0 "reg_operand" "=f")
+        (neg:QF (match_dup 1)))]
+  ""
+  "negf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; FLOAT
+;
+(define_insn "floatqiqf2"
+  [(set (match_operand:QF 0 "reg_operand" "=f")
+        (float:QF (match_operand:QI 1 "src_operand" "g")))
+   (clobber (reg:CC 21))]
+ ""
+ "float\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*floatqiqf2_set"
+  [(set (reg:CC 21)
+        (compare:CC (float:QF (match_operand:QI 1 "src_operand" "g"))
+                    (match_operand:QF 2 "fp_zero_operand" "G")))
+   (set (match_operand:QF 0 "reg_operand" "=f")
+        (float:QF (match_dup 1)))]
+
+ ""
+ "float\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+; Unsigned conversions are a little tricky because we need to
+; add the value for the high bit if necessary.
+;
+(define_expand "floatunsqiqf2"
+ [(set (match_dup 2) (match_dup 3))
+  (parallel [(set (reg:CC 21)
+                  (compare:CC (float:QF (match_operand:QI 1 "src_operand" ""))
+                              (match_dup 3)))
+             (set (match_dup 4)
+                  (float:QF (match_dup 1)))])
+  (set (match_dup 2)
+       (if_then_else:QF (lt (reg:CC 21) (const_int 0))
+                        (mem:QF (symbol_ref:QF "*___unsfltconst"))
+                        (match_dup 2)))
+  (parallel [(set (match_operand:QF 0 "reg_operand" "")
+                  (plus:QF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])]
+ ""
+ "operands[2] = gen_reg_rtx (QFmode);
+  operands[3] = CONST0_RTX (QFmode); 
+  operands[4] = gen_reg_rtx (QFmode);
+ ")
+
+(define_insn "floatqihf2"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (float:HF (match_operand:QI 1 "src_operand" "g")))
+   (clobber (reg:CC 21))]
+ ""
+ "float\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; FIX
+;
+(define_insn "fixqfqi_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=d,c")
+        (fix:QI (match_operand:QF 1 "src_operand" "fmH,fmH")))
+   (clobber (reg:CC 21))]
+ ""
+ "fix\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*fixqfqi_set"
+  [(set (reg:CC 21)
+        (compare:CC (fix:QI (match_operand:QF 1 "src_operand" "fmH"))
+                    (const_int 0)))
+   (set (match_operand:QI 0 "reg_operand" "=d")
+        (fix:QI (match_dup 1)))]
+ ""
+ "fix\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; The C[34]x fix instruction implements a floor, not a straight trunc,
+; so we have to invert the number, fix it, and reinvert it if negative
+;
+(define_expand "fix_truncqfqi2"
+  [(parallel [(set (match_dup 2)
+                   (fix:QI (match_operand:QF 1 "src_operand" "")))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 3) (neg:QF (match_dup 1)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (fix:QI (match_dup 3)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (reg:CC_NOOV 21)
+                   (compare:CC_NOOV (neg:QI (match_dup 4)) (const_int 0)))
+              (set (match_dup 5) (neg:QI (match_dup 4)))])
+   (set (match_dup 2)
+        (if_then_else:QI (le (reg:CC 21) (const_int 0))
+                         (match_dup 5)
+                         (match_dup 2)))
+   (set (match_operand:QI 0 "reg_operand" "=r") (match_dup 2))]
+ ""
+ "if (TARGET_FAST_FIX)
+    {
+       emit_insn (gen_fixqfqi_clobber (operands[0], operands[1]));
+       DONE;
+    }
+  operands[2] = gen_reg_rtx (QImode);
+  operands[3] = gen_reg_rtx (QFmode);
+  operands[4] = gen_reg_rtx (QImode);
+  operands[5] = gen_reg_rtx (QImode);
+ ")
+
+(define_expand "fix_truncqfhi2"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (fix:HI (match_operand:QF 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FIX_TRUNCQFHI2_LIBCALL, FIX, HImode, QFmode, 2, operands);
+   DONE;")
+
+(define_expand "fixuns_truncqfqi2"
+ [(set (match_dup 2) (match_dup 4))
+  (set (reg:CC 21)
+       (compare:CC (match_operand:QF 1 "reg_operand" "")
+                   (mem:QF (symbol_ref "*___unsfltcompare"))))
+  (set (match_dup 2)
+       (if_then_else:QF (ge (reg:CC 21) (const_int 0))
+                        (mem:QF (symbol_ref "*___unsfltconst"))
+                        (match_dup 2)))
+  (parallel [(set (match_dup 3)
+                  (minus:QF (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC_NOOV 21))])
+  (parallel [(set (match_operand:QI 0 "reg_operand" "")
+                  (fix:QI (match_dup 3)))
+             (clobber (reg:CC 21))])]
+ ""
+ "operands[2] = gen_reg_rtx (QFmode);
+  operands[3] = gen_reg_rtx (QFmode);
+  operands[4] = CONST0_RTX (QFmode);
+ ")
+
+(define_expand "fixuns_truncqfhi2"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (unsigned_fix:HI (match_operand:QF 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FIXUNS_TRUNCQFHI2_LIBCALL, UNSIGNED_FIX, 
+                     HImode, QFmode, 2, operands);
+   DONE;")
+
+;
+; RCPF
+;
+(define_insn "*rcpfqf_clobber"
+  [(set (match_operand:QF 0 "reg_operand" "=f")
+        (unspec [(match_operand:QF 1 "src_operand" "fmH")] 5))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X"
+  "rcpf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; RSQRF
+;
+(define_insn "*rsqrfqf_clobber"
+  [(set (match_operand:QF 0 "reg_operand" "=f")
+        (unspec [(match_operand:QF 1 "src_operand" "fmH")] 10))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X"
+  "rsqrf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; RNDF
+;
+(define_insn "*rndqf_clobber"
+  [(set (match_operand:QF 0 "reg_operand" "=f")
+        (unspec [(match_operand:QF 1 "src_operand" "fmH")] 6))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X"
+  "rnd\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+
+; Inlined float square root for C4x
+(define_expand "sqrtqf2_inline"
+  [(parallel [(set (match_dup 2)
+                  (unspec [(match_operand:QF 1 "src_operand" "")] 10))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 3) (mult:QF (match_dup 5) (match_dup 1)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:QF (match_dup 6) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 2) (mult:QF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:QF (match_dup 6) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 2) (mult:QF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 1)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_operand:QF 0 "reg_operand" "")
+                  (unspec [(match_dup 4)] 6))
+             (clobber (reg:CC_NOOV 21))])]
+  "!TARGET_C3X"
+  "if (!reload_in_progress
+       && !reg_operand (operands[1], QFmode))
+     operands[1] = force_reg (QFmode, operands[1]);
+   operands[2] = gen_reg_rtx (QFmode);
+   operands[3] = gen_reg_rtx (QFmode);
+   operands[4] = gen_reg_rtx (QFmode);
+   operands[5] = immed_real_const_1 (REAL_VALUE_ATOF (\"0.5\", QFmode),
+                                     QFmode);
+   operands[6] = immed_real_const_1 (REAL_VALUE_ATOF (\"1.5\", QFmode),
+                                     QFmode);")
+
+(define_expand "sqrtqf2"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (sqrt:QF (match_operand:QF 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "if (TARGET_C3X || !TARGET_INLINE)
+     FAIL;
+   else
+     {
+       emit_insn (gen_sqrtqf2_inline( operands[0], operands[1]));
+       DONE;
+     }
+  ")
+
+;
+; THREE OPERAND FLOAT INSTRUCTIONS
+;
+
+;
+; ADDF
+;
+(define_expand "addqf3"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (plus:QF (match_operand:QF 1 "src_operand" "")
+                            (match_operand:QF 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "legitimize_operands (PLUS, operands, QFmode);")
+
+(define_insn "*addqf3_clobber"
+  [(set (match_operand:QF 0 "reg_operand" "=f,?f,f")
+        (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
+                 (match_operand:QF 2 "src_operand" "R,fS<>,fmH")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (PLUS, operands, QFmode)"
+  "@
+   addf3\\t%2,%1,%0
+   addf3\\t%2,%1,%0
+   addf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+(define_insn "*addqf3_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                         (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
+   (clobber (match_scratch:QF 0 "=f,?f,f"))]
+  "valid_operands (PLUS, operands, QFmode)"
+  "@
+   addf3\\t%2,%1,%0
+   addf3\\t%2,%1,%0
+   addf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+(define_insn "*addqf3_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                         (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
+   (set (match_operand:QF 0 "reg_operand" "=f,?f,f")
+        (plus:QF (match_dup 1)
+                 (match_dup 2)))]
+  "valid_operands (PLUS, operands, QFmode)"
+  "@
+   addf3\\t%2,%1,%0
+   addf3\\t%2,%1,%0
+   addf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+;
+; SUBF/SUBRF
+;
+(define_expand "subqf3"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (minus:QF (match_operand:QF 1 "src_operand" "")
+                             (match_operand:QF 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "legitimize_operands (MINUS, operands, QFmode);")
+
+(define_insn "*subqf3_clobber"
+   [(set (match_operand:QF 0 "reg_operand" "=f,?f,f,f")
+         (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH")
+                   (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (MINUS, operands, QFmode)"
+  "@
+   subf3\\t%2,%1,%0
+   subf3\\t%2,%1,%0
+   subf\\t%2,%0
+   subrf\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+
+(define_insn "*subqf3_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH")
+                                   (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0"))
+                         (match_operand:QF 3 "fp_zero_operand" "G,G,G,G")))
+   (clobber (match_scratch:QF 0 "=f,?f,f,f"))]
+  "valid_operands (MINUS, operands, QFmode)"
+  "@
+   subf3\\t%2,%1,%0
+   subf3\\t%2,%1,%0
+   subf\\t%2,%0
+   subrf\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+
+(define_insn "*subqf3_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH")
+                                   (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0"))
+                         (match_operand:QF 3 "fp_zero_operand" "G,G,G,G")))
+   (set (match_operand:QF 0 "reg_operand" "=f,?f,f,f")
+        (minus:QF (match_dup 1)
+                 (match_dup 2)))]
+  "valid_operands (MINUS, operands, QFmode)"
+  "@
+   subf3\\t%2,%1,%0
+   subf3\\t%2,%1,%0
+   subf\\t%2,%0
+   subrf\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")])
+
+;
+; MPYF
+;
+(define_expand "mulqf3"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (mult:QF (match_operand:QF 1 "src_operand" "")
+                            (match_operand:QF 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "legitimize_operands (MULT, operands, QFmode);")
+
+(define_insn "*mulqf3_clobber"
+  [(set (match_operand:QF 0 "reg_operand" "=f,?f,f")
+        (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
+                 (match_operand:QF 2 "src_operand" "R,fS<>,fmH")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (MULT, operands, QFmode)"
+  "@
+   mpyf3\\t%2,%1,%0
+   mpyf3\\t%2,%1,%0
+   mpyf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+(define_insn "*mulqf3_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                         (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
+   (clobber (match_scratch:QF 0 "=f,?f,f"))]
+  "valid_operands (MULT, operands, QFmode)"
+  "@
+   mpyf3\\t%2,%1,%0
+   mpyf3\\t%2,%1,%0
+   mpyf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+(define_insn "*mulqf3_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                         (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
+   (set (match_operand:QF 0 "reg_operand" "=f,?f,f")
+        (mult:QF (match_dup 1)
+                 (match_dup 2)))]
+  "valid_operands (MULT, operands, QFmode)"
+  "@
+   mpyf3\\t%2,%1,%0
+   mpyf3\\t%2,%1,%0
+   mpyf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+;
+; CMPF
+;
+(define_expand "cmpqf"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:QF 0 "src_operand" "")
+                    (match_operand:QF 1 "src_operand" "")))]
+  ""
+  "legitimize_operands (COMPARE, operands, QFmode);
+   c4x_compare_op0 = operands[0];
+   c4x_compare_op1 = operands[1];
+   DONE;")
+
+(define_insn "*cmpqf"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:QF 0 "src_operand" "fR,?fS<>,f")
+                    (match_operand:QF 1 "src_operand" "R,fS<>,fmH")))]
+  "valid_operands (COMPARE, operands, QFmode)"
+  "@
+   cmpf3\\t%1,%0
+   cmpf3\\t%1,%0
+   cmpf\\t%1,%0"
+  [(set_attr "type" "compare,compare,compare")])
+
+(define_insn "*cmpqf_noov"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (match_operand:QF 0 "src_operand" "fR,?fS<>,f")
+                         (match_operand:QF 1 "src_operand" "R,fS<>,fmH")))]
+  "valid_operands (COMPARE, operands, QFmode)"
+  "@
+   cmpf3\\t%1,%0
+   cmpf3\\t%1,%0
+   cmpf\\t%1,%0"
+  [(set_attr "type" "compare,compare,compare")])
+
+; Inlined float divide for C4x
+(define_expand "divqf3_inline"
+  [(parallel [(set (match_dup 3)
+                  (unspec [(match_operand:QF 2 "src_operand" "")] 5))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:QF (match_dup 5) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 3) (mult:QF (match_dup 3) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:QF (match_dup 5) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 3) (mult:QF (match_dup 3) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 3)
+                  (mult:QF (match_operand:QF 1 "src_operand" "")
+                           (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_operand:QF 0 "reg_operand" "")
+                  (unspec [(match_dup 3)] 6))
+             (clobber (reg:CC_NOOV 21))])]
+  "!TARGET_C3X"
+  "if (!reload_in_progress
+      && !reg_operand (operands[2], QFmode))
+     operands[2] = force_reg (QFmode, operands[2]);
+   operands[3] = gen_reg_rtx (QFmode);
+   operands[4] = gen_reg_rtx (QFmode);
+   operands[5] = CONST2_RTX (QFmode);")
+
+(define_expand "divqf3"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (div:QF (match_operand:QF 1 "src_operand" "")
+                            (match_operand:QF 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "if (TARGET_C3X || !TARGET_INLINE)
+     {
+       c4x_emit_libcall3 (DIVQF3_LIBCALL, DIV, QFmode, operands);
+       DONE;
+     }
+   else
+     {
+       emit_insn (gen_divqf3_inline( operands[0], operands[1], operands[2]));
+       DONE;
+     }
+  ")
+
+;
+; CONDITIONAL MOVES
+;
+
+(define_insn "*ldi_conditional"
+  [(set (match_operand:QI 0 "reg_operand" "=r,r")
+        (if_then_else:QI (match_operator 1 "comparison_operator"
+                          [(reg:CC 21) (const_int 0)])
+                         (match_operand:QI 2 "src_operand" "g,0")
+                         (match_operand:QI 3 "src_operand" "0,g")))]
+ ""
+ "@
+  ldi%1\\t%2,%0
+  ldi%I1\\t%3,%0"
+ [(set_attr "type" "binary")])
+
+(define_insn "*ldi_conditional_noov"
+  [(set (match_operand:QI 0 "reg_operand" "=r,r")
+        (if_then_else:QI (match_operator 1 "comparison_operator"
+                          [(reg:CC_NOOV 21) (const_int 0)])
+                         (match_operand:QI 2 "src_operand" "g,0")
+                         (match_operand:QI 3 "src_operand" "0,g")))]
+ "GET_CODE(operands[1]) != LE
+  && GET_CODE(operands[1]) != GE
+  && GET_CODE(operands[1]) != LT
+  && GET_CODE(operands[1]) != GT"
+ "@
+  ldi%1\\t%2,%0
+  ldi%I1\\t%3,%0"
+ [(set_attr "type" "binary")])
+
+; Move operand 2 to operand 0 if condition (operand 1) is true
+; else move operand 3 to operand 0.
+; The temporary register is required below because some of the operands
+; might be identical (namely 0 and 2). 
+;
+(define_expand "movqicc"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (if_then_else:QI (match_operand 1 "comparison_operator" "")
+                         (match_operand:QI 2 "src_operand" "")
+                         (match_operand:QI 3 "src_operand" "")))]
+ ""
+ "{ 
+    enum rtx_code code = GET_CODE (operands[1]);
+    rtx ccreg = c4x_gen_compare_reg (code, c4x_compare_op0, c4x_compare_op1);
+    if (ccreg == NULL_RTX) FAIL;
+    emit_insn (gen_rtx (SET, QImode, operands[0],
+                        gen_rtx (IF_THEN_ELSE, QImode,
+                                 gen_rtx (code, VOIDmode, ccreg, const0_rtx),
+                                          operands[2], operands[3])));
+    DONE;}")
+                      
+(define_insn "*ldf_conditional"
+  [(set (match_operand:QF 0 "reg_operand" "=f,f")
+        (if_then_else:QF (match_operator 1 "comparison_operator"
+                          [(reg:CC 21) (const_int 0)])
+                         (match_operand:QF 2 "src_operand" "fmH,0")
+                         (match_operand:QF 3 "src_operand" "0,fmH")))]
+ ""
+ "@
+  ldf%1\\t%2,%0
+  ldf%I1\\t%3,%0"
+ [(set_attr "type" "binary")])
+
+(define_insn "*ldf_conditional_noov"
+  [(set (match_operand:QF 0 "reg_operand" "=f,f")
+        (if_then_else:QF (match_operator 1 "comparison_operator"
+                          [(reg:CC_NOOV 21) (const_int 0)])
+                         (match_operand:QF 2 "src_operand" "fmH,0")
+                         (match_operand:QF 3 "src_operand" "0,fmH")))]
+ "GET_CODE(operands[1]) != LE
+  && GET_CODE(operands[1]) != GE
+  && GET_CODE(operands[1]) != LT
+  && GET_CODE(operands[1]) != GT"
+ "@
+  ldf%1\\t%2,%0
+  ldf%I1\\t%3,%0"
+ [(set_attr "type" "binary")])
+
+(define_expand "movqfcc"
+  [(set (match_operand:QF 0 "reg_operand" "")
+        (if_then_else:QF (match_operand 1 "comparison_operator" "")
+                         (match_operand:QF 2 "src_operand" "")
+                         (match_operand:QF 3 "src_operand" "")))]
+ ""
+ "{ 
+    enum rtx_code code = GET_CODE (operands[1]);
+    rtx ccreg = c4x_gen_compare_reg (code, c4x_compare_op0, c4x_compare_op1);
+    if (ccreg == NULL_RTX) FAIL;
+    emit_insn (gen_rtx (SET, QFmode, operands[0],
+                        gen_rtx (IF_THEN_ELSE, QFmode,
+                                 gen_rtx (code, VOIDmode, ccreg, const0_rtx),
+                                          operands[2], operands[3])));
+    DONE;}")
+
+(define_expand "seq"
+ [(set (match_operand:QI 0 "reg_operand" "")
+       (const_int 0))
+  (set (match_dup 0)
+       (if_then_else:QI (eq (match_dup 1) (const_int 0))
+                       (const_int 1)
+                       (match_dup 0)))]
+ ""
+ "operands[1] = c4x_gen_compare_reg (EQ, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "sne"
+ [(set (match_operand:QI 0 "reg_operand" "")
+       (const_int 0))
+  (set (match_dup 0)
+       (if_then_else:QI (ne (match_dup 1) (const_int 0))
+                       (const_int 1)
+                       (match_dup 0)))]
+ ""
+ "operands[1] = c4x_gen_compare_reg (NE, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "slt"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (lt (match_dup 1) (const_int 0))
+                       (const_int 1)
+                        (match_dup 0)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LT, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "sltu"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (ltu (match_dup 1) (const_int 0))
+                       (const_int 1)
+                        (match_dup 0)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LTU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "sgt"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (gt (match_dup 1) (const_int 0))
+                       (const_int 1)
+                        (match_dup 0)))]
+  "" 
+  "operands[1] = c4x_gen_compare_reg (GT, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "sgtu"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (gtu (match_dup 1) (const_int 0))
+                       (const_int 1)
+                        (match_dup 0)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (GTU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "sle"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (le (match_dup 1) (const_int 0))
+                        (const_int 1)
+                        (match_dup 0)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LE, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "sleu"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (leu (match_dup 1) (const_int 0))
+                        (const_int 1)
+                        (match_dup 0)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LEU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "sge"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (ge (match_dup 1) (const_int 0))
+                        (const_int 1)
+                        (match_dup 0)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (GE, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "sgeu"
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (geu (match_dup 1) (const_int 0))
+                        (const_int 1)
+                        (match_dup 0)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (GEU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_split
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (match_operator 1 "comparison_operator" [(reg:CC 21) (const_int 0)]))]
+  "reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (match_op_dup 1 [(reg:CC 21) (const_int 0)])
+                       (const_int 1)
+                        (match_dup 0)))]
+  "")
+
+(define_split
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (match_operator 1 "comparison_operator" [(reg:CC_NOOV 21) (const_int 0)]))]
+  "reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (set (match_dup 0)
+        (if_then_else:QI (match_op_dup 1 [(reg:CC_NOOV 21) (const_int 0)])
+                        (const_int 1)
+                        (match_dup 0)))]
+  "")
+
+(define_insn "*bu"
+  [(set (pc)
+        (unspec [(match_operand:QI 0 "reg_operand" "r")] 1))]
+  ""
+  "bu%#\\t%0"
+  [(set_attr "type" "jump")])
+
+(define_expand "caseqi"
+  [(parallel [(set (match_dup 5)
+                   (minus:QI (match_operand:QI 0 "reg_operand" "")
+                             (match_operand:QI 1 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])
+   (set (reg:CC 21)
+        (compare:CC (match_dup 5)
+                    (match_operand:QI 2 "src_operand" "")))
+   (set (pc)
+        (if_then_else (gtu (reg:CC 21)
+                           (const_int 0))
+                      (label_ref (match_operand 4 "" ""))
+                      (pc)))
+   (parallel [(set (match_dup 6)
+                   (plus:QI (match_dup 5)
+                            (label_ref:QI (match_operand 3 "" ""))))
+              (clobber (reg:CC_NOOV 21))])
+   (set (match_dup 7)
+        (mem:QI (match_dup 6)))
+   (set (pc) (match_dup 7))]
+  ""
+  "operands[5] = gen_reg_rtx (QImode);
+   operands[6] = gen_reg_rtx (QImode);
+   operands[7] = gen_reg_rtx (QImode);")
+                
+;
+; PARALLEL FLOAT INSTRUCTIONS
+;
+; This patterns are under development
+
+;
+; ABSF/STF
+;
+
+(define_insn "*absqf2_movqf_clobber"
+  [(set (match_operand:QF 0 "ext_low_reg_operand" "=q")
+        (abs:QF (match_operand:QF 1 "par_ind_operand" "S<>")))
+   (set (match_operand:QF 2 "par_ind_operand" "=S<>")
+        (match_operand:QF 3 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC_NOOV 21))]
+  "TARGET_PARALLEL"
+  "absf\\t%1,%0\\n||\\tstf\\t%3,%2"
+  [(set_attr "type" "binarycc")])
+
+;
+; ADDF/STF
+;
+
+(define_insn "*addqf3_movqf_clobber"
+  [(set (match_operand:QF 0 "ext_low_reg_operand" "=q")
+        (plus:QF (match_operand:QF 1 "parallel_operand" "%q")
+                 (match_operand:QF 2 "parallel_operand" "S<>")))
+   (set (match_operand:QF 3 "par_ind_operand" "=S<>")
+        (match_operand:QF 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QFmode)"
+  "addf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; FLOAT/STF
+;
+
+(define_insn "*floatqiqf_movqf_clobber"
+  [(set (match_operand:QF 0 "ext_low_reg_operand" "=q")
+        (float:QF (match_operand:QI 1 "par_ind_operand" "S<>")))
+   (set (match_operand:QF 2 "par_ind_operand" "=S<>")
+        (match_operand:QF 3 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "float\\t%1,%0\\n||\\tstf\\t%3,%2"
+  [(set_attr "type" "binarycc")])
+
+;
+; MPYF/ADDF
+;
+
+(define_insn "*mulqf3_addqf3_clobber"
+  [(set (match_operand:QF 0 "r0r1_reg_operand" "=t")
+        (mult:QF (match_operand:QF 1 "parallel_operand" "S<>q")
+                 (match_operand:QF 2 "parallel_operand" "S<>q")))
+   (set (match_operand:QF 3 "r2r3_reg_operand" "=u")
+        (plus:QF (match_operand:QF 4 "parallel_operand" "S<>q")
+                 (match_operand:QF 5 "parallel_operand" "S<>q")))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL_MPY && valid_parallel_operands_6 (operands, QFmode)"
+  "mpyf3\\t%2,%1,%0\\n||\\taddf3\\t%5,%4,%3"
+  [(set_attr "type" "binarycc")])
+
+
+;
+; MPYF/STF
+;
+
+(define_insn "*mulqf3_movqf_clobber"
+  [(set (match_operand:QF 0 "ext_low_reg_operand" "=q")
+        (mult:QF (match_operand:QF 1 "parallel_operand" "%q")
+                 (match_operand:QF 2 "parallel_operand" "S<>")))
+   (set (match_operand:QF 3 "par_ind_operand" "=S<>")
+        (match_operand:QF 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QFmode)"
+  "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; MPYF/SUBF
+;
+
+(define_insn "*mulqf3_subqf3_clobber"
+  [(set (match_operand:QF 0 "r0r1_reg_operand" "=t")
+        (mult:QF (match_operand:QF 1 "parallel_operand" "S<>q")
+                 (match_operand:QF 2 "parallel_operand" "S<>q")))
+   (set (match_operand:QF 3 "r2r3_reg_operand" "=u")
+        (minus:QF (match_operand:QF 4 "parallel_operand" "S<>q")
+                  (match_operand:QF 5 "parallel_operand" "S<>q")))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL_MPY && valid_parallel_operands_6 (operands, QFmode)"
+  "mpyf3\\t%2,%1,%0\\n||\\tsubf3\\t%5,%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; NEGF/STF
+;
+
+(define_insn "*negqf2_movqf_clobber"
+  [(set (match_operand:QF 0 "ext_low_reg_operand" "=q")
+        (neg:QF (match_operand:QF 1 "par_ind_operand" "S<>")))
+   (set (match_operand:QF 2 "par_ind_operand" "=S<>")
+        (match_operand:QF 3 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "negf\\t%1,%0\\n||\\tstf\\t%3,%2"
+  [(set_attr "type" "binarycc")])
+
+;
+; SUBF/STF
+;
+
+(define_insn "*subqf3_movqf_clobber"
+  [(set (match_operand:QF 0 "ext_low_reg_operand" "=q")
+        (minus:QF (match_operand:QF 1 "ext_low_reg_operand" "q")
+                 (match_operand:QF 2 "par_ind_operand" "S<>")))
+   (set (match_operand:QF 3 "par_ind_operand" "=S<>")
+        (match_operand:QF 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "subf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; PARALLEL INTEGER INSTRUCTIONS
+;
+; These patterns are under development
+
+;
+; ABSI/STI
+;
+
+(define_insn "*absqi2_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (abs:QI (match_operand:QI 1 "par_ind_operand" "S<>")))
+   (set (match_operand:QI 2 "par_ind_operand" "=S<>")
+        (match_operand:QI 3 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC_NOOV 21))]
+  "TARGET_PARALLEL"
+  "absi\\t%1,%0\\n||\\tsti\\t%3,%2"
+  [(set_attr "type" "binarycc")])
+
+;
+; ADDI/STI
+;
+
+(define_insn "*addqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (plus:QI (match_operand:QI 1 "parallel_operand" "%q")
+                 (match_operand:QI 2 "parallel_operand" "S<>")))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)"
+  "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; AND/STI
+;
+
+(define_insn "*andqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (and:QI (match_operand:QI 1 "parallel_operand" "%q")
+                (match_operand:QI 2 "parallel_operand" "S<>")))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)"
+  "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; ASH(left)/STI 
+;
+
+(define_insn "*ashlqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (ashift:QI (match_operand:QI 1 "par_ind_operand" "S<>")
+                   (match_operand:QI 2 "ext_low_reg_operand" "q")))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; ASH(right)/STI 
+;
+
+(define_insn "*ashlqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (ashiftrt:QI (match_operand:QI 1 "par_ind_operand" "S<>")
+                     (neg:QI (match_operand:QI 2 "ext_low_reg_operand" "q"))))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; FIX/STI
+;
+
+(define_insn "*fixqfqi2_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (fix:QI (match_operand:QF 1 "par_ind_operand" "S<>")))
+   (set (match_operand:QI 2 "par_ind_operand" "=S<>")
+        (match_operand:QI 3 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "fix\\t%1,%0\\n||\\tsti\\t%3,%2"
+  [(set_attr "type" "binarycc")])
+
+;
+; LSH(right)/STI 
+;
+
+(define_insn "*lshrqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (lshiftrt:QI (match_operand:QI 1 "par_ind_operand" "S<>")
+                     (neg:QI (match_operand:QI 2 "ext_low_reg_operand" "q"))))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "lsh3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; MPYI/ADDI
+;
+
+(define_insn "*mulqi3_addqi3_clobber"
+  [(set (match_operand:QI 0 "r0r1_reg_operand" "=t")
+        (mult:QI (match_operand:QI 1 "parallel_operand" "S<>q")
+                 (match_operand:QI 2 "parallel_operand" "S<>q")))
+   (set (match_operand:QI 3 "r2r3_reg_operand" "=u")
+        (plus:QI (match_operand:QI 4 "parallel_operand" "S<>q")
+                 (match_operand:QI 5 "parallel_operand" "S<>q")))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL_MPY && TARGET_MPYI 
+   && valid_parallel_operands_6 (operands, QImode)"
+  "mpyi3\\t%2,%1,%0\\n||\\taddi3\\t%5,%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; MPYI/STI
+;
+
+(define_insn "*mulqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (mult:QI (match_operand:QI 1 "parallel_operand" "%q")
+                 (match_operand:QI 2 "parallel_operand" "S<>")))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL && TARGET_MPYI
+   && valid_parallel_operands_5 (operands, QImode)"
+  "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; MPYI/SUBI
+;
+
+(define_insn "*mulqi3_subqi3_clobber"
+  [(set (match_operand:QI 0 "r0r1_reg_operand" "=t")
+        (mult:QI (match_operand:QI 1 "parallel_operand" "S<>q")
+                 (match_operand:QI 2 "parallel_operand" "S<>q")))
+   (set (match_operand:QI 3 "r2r3_reg_operand" "=u")
+        (minus:QI (match_operand:QI 4 "parallel_operand" "S<>q")
+                  (match_operand:QI 5 "parallel_operand" "S<>q")))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL_MPY && TARGET_MPYI
+   && valid_parallel_operands_6 (operands, QImode)"
+  "mpyi3\\t%2,%1,%0\\n||\\tsubi3\\t%5,%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; NEGI/STI
+;
+
+(define_insn "*negqi2_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (neg:QI (match_operand:QI 1 "par_ind_operand" "S<>")))
+   (set (match_operand:QI 2 "par_ind_operand" "=S<>")
+        (match_operand:QI 3 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "negi\\t%1,%0\\n||\\tsti\\t%3,%2"
+  [(set_attr "type" "binarycc")])
+
+;
+; NOT/STI
+;
+
+(define_insn "*notqi2_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (not:QI (match_operand:QI 1 "par_ind_operand" "S<>")))
+   (set (match_operand:QI 2 "par_ind_operand" "=S<>")
+        (match_operand:QI 3 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "not\\t%1,%0\\n||\\tsti\\t%3,%2"
+  [(set_attr "type" "binarycc")])
+
+;
+; OR/STI
+;
+
+(define_insn "*iorqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (ior:QI (match_operand:QI 1 "parallel_operand" "%q")
+                (match_operand:QI 2 "parallel_operand" "S<>")))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)"
+  "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; SUBI/STI
+;
+
+(define_insn "*subqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (minus:QI (match_operand:QI 1 "ext_low_reg_operand" "q")
+                  (match_operand:QI 2 "par_ind_operand" "S<>")))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL"
+  "subi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; XOR/STI
+;
+
+(define_insn "*xorqi3_movqi_clobber"
+  [(set (match_operand:QI 0 "ext_low_reg_operand" "=q")
+        (xor:QI (match_operand:QI 1 "parallel_operand" "%q")
+                (match_operand:QI 2 "parallel_operand" "S<>")))
+   (set (match_operand:QI 3 "par_ind_operand" "=S<>")
+        (match_operand:QI 4 "ext_low_reg_operand" "q"))
+   (clobber (reg:CC 21))]
+  "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)"
+  "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3"
+  [(set_attr "type" "binarycc")])
+
+;
+; BRANCH/CALL INSTRUCTIONS
+;
+
+;
+; Branch instructions
+;
+(define_insn "*b"
+  [(set (pc) (if_then_else (match_operator 0 "comparison_operator"
+                          [(reg:CC 21) (const_int 0)])
+                           (label_ref (match_operand 1 "" ""))
+                           (pc)))]
+  ""
+  "*
+   return c4x_output_cbranch (0, insn);"
+  [(set_attr "type" "jmpc")])
+
+(define_insn "*b_rev"
+  [(set (pc) (if_then_else (match_operator 0 "comparison_operator"
+                          [(reg:CC 21) (const_int 0)])
+                           (pc)
+                           (label_ref (match_operand 1 "" ""))))]
+  ""
+  "*
+   return c4x_output_cbranch (1, insn);"
+  [(set_attr "type" "jmpc")])
+
+(define_insn "*b_noov"
+  [(set (pc) (if_then_else (match_operator 0 "comparison_operator"
+                          [(reg:CC_NOOV 21) (const_int 0)])
+                           (label_ref (match_operand 1 "" ""))
+                           (pc)))]
+ "GET_CODE(operands[0]) != LE
+  && GET_CODE(operands[0]) != GE
+  && GET_CODE(operands[0]) != LT
+  && GET_CODE(operands[0]) != GT"
+  "*
+   return c4x_output_cbranch (0, insn);"
+  [(set_attr "type" "jmpc")])
+
+(define_insn "*b_noov_rev"
+  [(set (pc) (if_then_else (match_operator 0 "comparison_operator"
+                          [(reg:CC_NOOV 21) (const_int 0)])
+                           (pc)
+                           (label_ref (match_operand 1 "" ""))))]
+ "GET_CODE(operands[0]) != LE
+  && GET_CODE(operands[0]) != GE
+  && GET_CODE(operands[0]) != LT
+  && GET_CODE(operands[0]) != GT"
+  "*
+   return c4x_output_cbranch (1, insn);"
+  [(set_attr "type" "jmpc")])
+
+(define_expand "beq"
+  [(set (pc) (if_then_else (eq (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (EQ, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "bne"
+  [(set (pc) (if_then_else (ne (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (NE, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "blt"
+  [(set (pc) (if_then_else (lt (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LT, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "bltu"
+  [(set (pc) (if_then_else (ltu (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LTU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "bgt"
+  [(set (pc) (if_then_else (gt (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (GT, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "bgtu"
+  [(set (pc) (if_then_else (gtu (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (GTU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "ble"
+  [(set (pc) (if_then_else (le (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LE, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "bleu"
+  [(set (pc) (if_then_else (leu (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (LEU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_expand "bge"
+  [(set (pc) (if_then_else (ge (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (GE, c4x_compare_op0, c4x_compare_op1);
+   if (operands[1] == NULL_RTX) FAIL;")
+
+(define_expand "bgeu"
+  [(set (pc) (if_then_else (geu (match_dup 1) (const_int 0))
+                           (label_ref (match_operand 0 "" ""))
+                           (pc)))]
+  ""
+  "operands[1] = c4x_gen_compare_reg (GEU, c4x_compare_op0, c4x_compare_op1);")
+
+(define_insn "*b_reg"
+ [(set (pc) (match_operand:QI 0 "reg_operand" "r"))]
+ ""
+ "bu%#\\t%0"
+  [(set_attr "type" "jump")])
+
+(define_expand "indirect_jump"
+ [(set (pc) (match_operand:QI 0 "reg_operand" ""))]
+ ""
+ "")
+
+(define_insn "tablejump"
+  [(set (pc) (match_operand:QI 0 "src_operand" "r"))
+   (use (label_ref (match_operand 1 "" "")))]
+  ""
+  "bu%#\\t%0"
+  [(set_attr "type" "jump")])
+
+;
+; CALL
+;
+(define_insn "*call_c3x"
+ [(call (match_operand:QI 0 "call_operand" "T,!o")
+        (match_operand:QI 1 "general_operand" ""))
+  (clobber (reg:QI 31))]
+  ;; Operand 1 not really used on the C4x.  The C30 doesn't have reg 31.
+
+  "TARGET_C3X"
+  "@
+   call\\t%C0
+   callu\\t%R0"
+  [(set_attr "type" "call,call")])
+
+; LAJ requires R11 (31) for the return address
+(define_insn "*laj"
+ [(call (match_operand:QI 0 "call_operand" "T,!o")
+        (match_operand:QI 1 "general_operand" ""))
+  (clobber (reg:QI 31))]
+  ;; Operand 1 not really used on the C4x.
+
+  "!TARGET_C3X"
+  "*
+   if (which_alternative == 0)
+     {
+       if (final_sequence)
+         return \"laj\\t%C0\";
+       else
+         return \"call\\t%C0\";
+     }
+   if (which_alternative == 1)
+     {
+       if (final_sequence)
+         return \"laju\\t%R0\";
+       else
+         return \"callu\\t%R0\";
+     }"
+  [(set_attr "type" "laj,laj")])
+
+(define_expand "call"
+ [(parallel [(call (match_operand:QI 0 "call_operand" "")
+                   (match_operand:QI 1 "general_operand" ""))
+             (clobber (reg:QI 31))])]
+ ""
+ "")
+
+(define_insn "*callv_c3x"
+ [(set (match_operand 0 "" "=r,r")
+       (call (match_operand:QI 1 "call_operand" "T,!o")
+             (match_operand:QI 2 "general_operand" "")))
+  (clobber (reg:QI 31))]
+  ;; Operand 0 and 2 not really used for the C4x. 
+  ;; The C30 doesn't have reg 31.
+
+  "TARGET_C3X"
+  "@
+   call\\t%C1
+   callu\\t%R1"
+  [(set_attr "type" "call,call")])
+
+; LAJ requires R11 (31) for the return address
+(define_insn "*lajv"
+ [(set (match_operand 0 "" "=r,r")
+       (call (match_operand:QI 1 "call_operand" "T,!o")
+             (match_operand:QI 2 "general_operand" "")))
+  (clobber (reg:QI 31))]
+  ;; Operand 0 and 2 not really used in the C30 instruction.
+
+  "!TARGET_C3X"
+  "*
+   if (which_alternative == 0)
+     {
+       if (final_sequence)
+         return \"laj\\t%C1\";
+       else
+         return \"call\\t%C1\";
+     }
+   if (which_alternative == 1)
+     {
+       if (final_sequence)
+         return \"laju\\t%R1\";
+       else
+         return \"callu\\t%R1\";
+     }"
+  [(set_attr "type" "laj,laj")])
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "" "")
+                  (call (match_operand:QI 1 "call_operand" "")
+                        (match_operand:QI 2 "general_operand" "")))
+             (clobber (reg:QI 31))])]
+ ""
+ "")
+
+(define_insn "return"
+  [(return)]
+  "c4x_null_epilogue_p ()"
+  "rets"
+  [(set_attr "type" "rets")])
+
+(define_insn "*return_cc"
+  [(set (pc)
+        (if_then_else (match_operator 0 "comparison_operator"
+                      [(reg:CC 21) (const_int 0)])
+                      (return)
+                       (pc)))]
+  "c4x_null_epilogue_p ()"
+  "rets%0"
+  [(set_attr "type" "rets")])
+
+(define_insn "*return_cc_noov"
+  [(set (pc)
+        (if_then_else (match_operator 0 "comparison_operator"
+                      [(reg:CC_NOOV 21) (const_int 0)])
+                      (return)
+                       (pc)))]
+  "GET_CODE(operands[0]) != LE
+   && GET_CODE(operands[0]) != GE
+   && GET_CODE(operands[0]) != LT
+   && GET_CODE(operands[0]) != GT
+   && c4x_null_epilogue_p ()"
+  "rets%0"
+  [(set_attr "type" "rets")])
+
+(define_insn "*return_cc_inverse"
+  [(set (pc)
+        (if_then_else (match_operator 0 "comparison_operator"
+                      [(reg:CC 21) (const_int 0)])
+                       (pc)
+                      (return)))]
+  "c4x_null_epilogue_p ()"
+  "rets%I0"
+  [(set_attr "type" "rets")])
+
+(define_insn "*return_cc_noov_inverse"
+  [(set (pc)
+        (if_then_else (match_operator 0 "comparison_operator"
+                      [(reg:CC_NOOV 21) (const_int 0)])
+                       (pc)
+                      (return)))]
+  "GET_CODE(operands[0]) != LE
+   && GET_CODE(operands[0]) != GE
+   && GET_CODE(operands[0]) != LT
+   && GET_CODE(operands[0]) != GT
+   && c4x_null_epilogue_p ()"
+  "rets%I0"
+  [(set_attr "type" "rets")])
+
+(define_insn "jump"
+  [(set (pc) (label_ref (match_operand 0 "" "")))]
+  ""
+  "br%#\\t%l0"
+  [(set_attr "type" "jump")])
+
+;
+; DBcond
+;
+; Note we have to emit a dbu instruction if there are no delay slots
+; to fill.
+; Also note that GCC will try to reverse a loop to see if it can
+; utilise this instruction.  However, if there are more than one
+; memory reference in the loop, it cannot guarantee that reversing
+; the loop will work :(  (see check_dbra_loop() in loop.c)
+; Note that the C3x only decrements the 24 LSBs of the address register
+; and the 8 MSBs are untouched.  The C4x uses all 32-bits.  We thus
+; have an option to disable this instruction.
+(define_insn "*db"
+  [(set (pc)
+        (if_then_else (ne (match_operand:QI 0 "addr_reg_operand" "+a,!d,!m")
+                          (const_int 0))
+                      (label_ref (match_operand 1 "" ""))
+                      (pc)))
+   (set (match_dup 0)
+        (plus:QI (match_dup 0)
+                 (const_int -1)))]
+  "TARGET_DB && TARGET_LOOP_UNSIGNED"
+  "*
+  if (IS_ADDR_REG (REGNO (operands[0])))
+    {
+        return \"dbu%#\\t%0,%l1\";
+    }
+  else if (IS_EXT_REG (REGNO (operands[0])))
+    {
+        return \"subi\\t1,%0\\n\\tbge%#\\t%l1\";
+    }
+  else
+    {
+        return \"push\\tr0\\n\\tldi\\t%0,r0\\n\\tsubi\\t1,r0\\n\\tsti\\tr0,%0\\n\\tpop\\tr0\\n\\tbhs%#\\t%l1\";
+    }
+  "
+  [(set_attr "type" "db")])
+
+(define_insn "decrement_and_branch_until_zero"
+  [(set (pc)
+        (if_then_else (ge (plus:QI (match_operand:QI 0 "addr_reg_operand" "+a,!d,!m")
+                          (const_int -1)) (const_int 0))
+                      (label_ref (match_operand 1 "" ""))
+                      (pc)))
+   (set (match_dup 0)
+        (plus:QI (match_dup 0)
+                 (const_int -1)))]
+  "TARGET_DB && find_reg_note (insn, REG_NONNEG, 0)"
+  "*
+  if (IS_ADDR_REG (REGNO (operands[0])))
+    {
+        return \"dbu%#\\t%0,%l1\";
+    }
+  else if (IS_EXT_REG (REGNO (operands[0])))
+    {
+        return \"subi\\t1,%0\\n\\tbge%#\\t%l1\";
+    }
+  else
+    {
+        return \"push\\tr0\\n\\tldi\\t%0,r0\\n\\tsubi\\t1,r0\\n\\tsti\\tr0,%0\\n\\t\\tpop\\tr0\\n\\tbhs%#\\t%l1\";
+    }
+  "
+  [(set_attr "type" "db")])
+
+;
+; MISC INSTRUCTIONS
+;
+
+;
+; NOP
+;
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop")
+; Default to misc type attr.
+
+;
+; RPTS
+;
+; Should we disallow RPTS if we get a silly number of shifts?
+(define_insn "rpts"
+  [(set (reg:QI 27)
+        (unspec [(match_operand:QI 0 "src_operand" "g")] 2))
+   (clobber (reg:QI 25))
+   (clobber (reg:QI 26))]
+  ""
+  "rpts\\t%0"
+  [(set_attr "type" "repeat")])
+
+;
+; RPTB
+;
+(define_insn "rptb_top"
+  [(set (reg:QI 25) (label_ref (match_operand 0 "" "")))
+   (set (reg:QI 26) (label_ref (match_operand 1 "" "")))]
+  ""
+  "*
+   return !final_sequence && c4x_rptb_rpts_p (insn, operands[0])
+        ? \"rpts\\trc\" : \"rptb%#\\t%l1-1\";
+  "
+  [(set_attr "type" "repeat_top")])
+
+; operand 0 is the loop depth
+; operand 1 is the loop count
+(define_expand "repeat_block_top"
+  [(set (reg:QI 27) (match_operand:QI 1 "src_operand" ""))
+   (use (match_operand:QI 0 "immediate_operand" ""))
+   (parallel[(set (reg:QI 25) (label_ref (match_operand 2 "" "")))
+             (set (reg:QI 26) (label_ref (match_operand 3 "" "")))])]
+  ""
+  "if (CONSTANT_P (operands[1])
+       && !const_operand (operands[1], QImode))
+     operands[1] = force_const_mem (QImode, operands[1]);"
+ )
+
+; operand 0 is the loop depth
+(define_insn "repeat_block_end"
+  [(set (pc)
+        (if_then_else (ne (reg:QI 27) (const_int 0))
+                      (label_ref (match_operand 1 "" ""))
+                      (pc)))
+   (use (match_operand:QI 0 "immediate_operand" ""))
+   (use (reg:QI 25))
+   (use (reg:QI 26))
+   (set (reg:QI 27)
+        (plus:QI (reg:QI 27)
+                 (const_int -1)))]
+  ""
+  "*
+   return c4x_rptb_nop_p(insn) ? \"nop\" : \"\";"
+  [(set_attr "type" "repeat")])
+
+; to prevent labels being coalesced and to leave a space to sink insns
+; out of a repeat block loop.
+(define_insn "repeat_block_filler"
+  [(unspec [(const_int 0)] 7)]
+  ""
+  ""
+  [(set_attr "type" "repeat")])
+
+
+(define_expand "movstrqi_small2"
+  [(parallel [(set (mem:BLK (match_operand:BLK 0 "src_operand" ""))
+                   (mem:BLK (match_operand:BLK 1 "src_operand" "")))
+              (use (match_operand:QI 2 "immediate_operand" ""))
+              (use (match_operand:QI 3 "immediate_operand" ""))
+              (clobber (match_operand:QI 4 "ext_low_reg_operand" ""))])]
+  ""
+  "
+ {
+    rtx src, dst, tmp;
+    rtx src_mem, dst_mem;    
+    int len;
+    int i;
+
+    dst = operands[0];
+    src = operands[1];
+    len = INTVAL (operands[2]);
+    tmp = operands[4];
+
+    src_mem = gen_rtx (MEM, QImode, src);
+    dst_mem = gen_rtx (MEM, QImode, dst);
+
+    emit_insn (gen_movqi (tmp, src_mem));      
+    emit_insn (gen_addqi3_noclobber (src, src, const1_rtx));   
+    for (i = 1; i < len; i++)
+      {
+         emit_insn (gen_movqi_parallel (tmp, src_mem, dst_mem, tmp));
+         emit_insn (gen_addqi3_noclobber (src, src, const1_rtx));      
+         emit_insn (gen_addqi3_noclobber (dst, dst, const1_rtx));      
+      }
+    emit_insn (gen_movqi (dst_mem, tmp));      
+    emit_insn (gen_addqi3_noclobber (dst, dst, const1_rtx));   
+    DONE;
+  }
+  ")
+
+
+;
+; BLOCK MOVE
+; We should probably get RC loaded when using RPTB automagically...
+; There's probably no need to call _memcpy() if we don't get
+; a immediate operand for the size.  We could do a better job here
+; than most memcpy() implementations.
+; operand 2 is the number of bytes
+; operand 3 is the shared alignment
+; operand 4 is a scratch register
+
+(define_insn "movstrqi_small"
+  [(set (mem:BLK (match_operand:QI 0 "addr_reg_operand" "a"))
+        (mem:BLK (match_operand:QI 1 "addr_reg_operand" "a")))
+   (use (match_operand:QI 2 "immediate_operand" "i"))
+   (use (match_operand:QI 3 "immediate_operand" ""))
+   (clobber (match_operand:QI 4 "ext_low_reg_operand" "=&q"))
+   (clobber (match_dup 0))
+   (clobber (match_dup 1))]
+  ""
+  "*
+ {
+   int i;
+   int len = INTVAL (operands[2]);
+   int first = 1;
+
+   for (i = 0; i < len; i++)
+    {
+      if (first)
+        output_asm_insn (\"ldiu\\t*%1++,%4\", operands);
+      else
+        output_asm_insn (\"|| ldi\\t*%1++,%4\", operands);
+      output_asm_insn (\"sti\\t%4,*%0++\", operands);
+      first = 0;
+    } 
+  return \"\";
+  }
+  "
+  [(set_attr "type" "multi")])
+
+(define_insn "movstrqi_large"
+  [(set (mem:BLK (match_operand:QI 0 "addr_reg_operand" "a"))
+        (mem:BLK (match_operand:QI 1 "addr_reg_operand" "a")))
+   (use (match_operand:QI 2 "immediate_operand" "i"))
+   (use (match_operand:QI 3 "immediate_operand" ""))
+   (clobber (match_operand:QI 4 "ext_low_reg_operand" "=&q"))
+   (clobber (match_dup 0))
+   (clobber (match_dup 1))
+   (clobber (reg:QI 25))
+   (clobber (reg:QI 26))
+   (clobber (reg:QI 27))]
+  ""
+  "*
+ {
+   int len = INTVAL (operands[2]);
+
+   output_asm_insn (\"ldiu\\t*%1++,%4\", operands);
+   if (TARGET_RPTS_CYCLES(len))
+     {
+        output_asm_insn (\"rpts\\t%2-2\", operands);  
+        output_asm_insn (\"sti\\t%4,*%0++\", operands);
+        output_asm_insn (\"|| ldi\\t*%1++,%4\", operands);
+        return \"sti\\t%4,*%0++\";
+     }
+   else
+     {
+        output_asm_insn (\"ldiu\\t%2-2,rc\", operands);
+        output_asm_insn (\"rptb\\t$+1\", operands);  
+        output_asm_insn (\"sti\\t%4,*%0++\", operands);
+        output_asm_insn (\"|| ldi\\t*%1++,%4\", operands);
+
+        return \"sti\\t%4,*%0++\";
+     }
+  }
+  "
+  [(set_attr "type" "repeat")])
+
+; Operand 2 is the count, operand 3 is the alignment.
+(define_expand "movstrqi"
+  [(parallel [(set (mem:BLK (match_operand:BLK 0 "src_operand" ""))
+                   (mem:BLK (match_operand:BLK 1 "src_operand" "")))
+              (use (match_operand:QI 2 "immediate_operand" ""))
+              (use (match_operand:QI 3 "immediate_operand" ""))])]
+  ""
+  "
+ {
+   rtx tmp;
+   if (GET_CODE (operands[2]) != CONST_INT 
+       || INTVAL (operands[2]) > 32767 
+       || INTVAL (operands[2]) <= 0)
+     {
+        FAIL;  /* Try to call _memcpy */
+     }
+
+   operands[0] = copy_to_mode_reg (Pmode, XEXP(operands[0], 0));
+   operands[1] = copy_to_mode_reg (Pmode, XEXP(operands[1], 0));
+   tmp = gen_reg_rtx (QImode);
+   if (INTVAL (operands[2]) < 8)
+     emit_insn (gen_movstrqi_small (operands[0], operands[1], operands[2],
+                                    operands[3], tmp));
+   else
+     {
+      emit_insn (gen_movstrqi_large (operands[0], operands[1], operands[2],
+                                     operands[3], tmp));
+     }
+   DONE;
+ }")
+
+
+(define_insn "*cmpstrqi"
+  [(set (match_operand:QI 0 "reg_operand" "=d")
+        (compare:QI (mem:BLK (match_operand:QI 1 "addr_reg_operand" "a"))
+                    (mem:BLK (match_operand:QI 2 "addr_reg_operand" "a"))))
+   (use (match_operand:QI 3 "immediate_operand" "i"))
+   (use (match_operand:QI 4 "immediate_operand" ""))
+   (clobber (match_operand:QI 5 "std_reg_operand" "=&c"))
+   (clobber (reg:QI 21))]
+  ""
+  "*
+ {
+    output_asm_insn (\"ldi\\t%3-1,%5\", operands);
+    output_asm_insn (\"$1:\tsubi3\\t*%1++,*%2++,%0\", operands);
+    output_asm_insn (\"dbeq\\t%5,$1\", operands);
+ }")
+
+(define_expand "cmpstrqi"
+  [(parallel [(set (match_operand:QI 0 "reg_operand" "")
+                   (compare:QI (match_operand:BLK 1 "general_operand" "")
+                               (match_operand:BLK 2 "general_operand" "")))
+              (use (match_operand:QI 3 "immediate_operand" ""))
+              (use (match_operand:QI 4 "immediate_operand" ""))
+              (clobber (match_dup 5))
+              (clobber (reg:QI 21))])]
+  ""
+  "
+{
+   if (GET_CODE (operands[3]) != CONST_INT
+       || INTVAL (operands[3]) > 32767 
+       || INTVAL (operands[3]) <= 0)
+     {
+        FAIL;
+     }
+   operands[1] = copy_to_mode_reg (Pmode, XEXP(operands[1], 0));
+   operands[2] = copy_to_mode_reg (Pmode, XEXP(operands[2], 0));
+   operands[5] = gen_reg_rtx (QImode);
+}")
+
+;
+; TWO OPERAND LONG DOUBLE INSTRUCTIONS
+;
+
+(define_expand "movhf"
+  [(set (match_operand:HF 0 "src_operand" "")
+        (match_operand:HF 1 "src_operand" ""))]
+ ""
+ "if (CONSTANT_P (operands[1]))
+    {
+      operands[1] = force_const_mem (HFmode, operands[1]); 
+      if (!memory_address_p (HFmode, XEXP (operands[1], 0))
+          && !reload_in_progress)
+        operands[1] = change_address (operands[1], HFmode,
+                                      XEXP (operands[1], 0));
+     }
+
+  /* Memory to memory copies must go through a register.  */
+  if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[0]) == MEM
+      && !reload_in_progress)
+    operands[1] = force_reg (HFmode, operands[1]); 
+")
+
+(define_insn "*movhf_noclobber_reg"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (match_operand:HF 1 "reg_operand" "h"))]
+ ""
+ "ldfu\\t%1,%0"
+  [(set_attr "type" "unary")])
+
+; The predicates could be tightened to disallow constants
+(define_insn "*movhf_noclobber"
+ [(set (match_operand:HF 0 "src_operand" "=h,m")
+       (match_operand:HF 1 "src_operand" "m,h"))]
+ "reg_operand (operands[0], HFmode) ^ reg_operand (operands[1], HFmode)"
+ "#"
+ [(set_attr "type" "multi,multi")])
+
+(define_insn "*movhf_test"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:HF 1 "reg_operand" "h")
+                    (const_int 0)))
+   (clobber (match_scratch:HF 0 "=h"))]
+ ""
+ "ldf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*movhf_set"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:HF 1 "reg_operand" "h")
+                    (match_operand:HF 2 "fp_zero_operand" "G")))
+    (set (match_operand:HF 0 "reg_operand" "=h")
+         (match_dup 1))]
+ ""
+ "ldf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_split
+ [(set (match_operand:HF 0 "reg_operand" "")
+       (match_operand:HF 1 "memory_operand" ""))]
+ "reload_completed"
+ [(set (match_dup 0) (float_extend:HF (match_dup 2)))
+  (set (match_dup 0) (unspec[(subreg:QI (match_dup 0) 0) (match_dup 3)] 8))]
+ "operands[2] = c4x_operand_subword (operands[1], 0, 1, HFmode);
+  operands[3] = c4x_operand_subword (operands[1], 1, 1, HFmode);
+  PUT_MODE (operands[2], QFmode);
+  PUT_MODE (operands[3], QImode);")
+
+(define_split
+ [(set (match_operand:HF 0 "reg_operand" "")
+       (match_operand:HF 1 "const_operand" ""))]
+ "reload_completed && 0"
+ [(set (match_dup 0) (float_extend:HF (match_dup 2)))
+  (set (match_dup 0) (unspec[(subreg:QI (match_dup 0) 0) (match_dup 3)] 8))]
+ "operands[2] = c4x_operand_subword (operands[1], 0, 1, HFmode);
+  operands[3] = c4x_operand_subword (operands[1], 1, 1, HFmode);
+  PUT_MODE (operands[2], QFmode);
+  PUT_MODE (operands[3], QImode);")
+
+(define_split
+ [(set (match_operand:HF 0 "memory_operand" "")
+       (match_operand:HF 1 "reg_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (float_truncate:QF (match_dup 1)))
+   (set (match_dup 3) (unspec [(match_dup 1)] 9))]
+ "operands[2] = c4x_operand_subword (operands[0], 0, 1, HFmode);
+  operands[3] = c4x_operand_subword (operands[0], 1, 1, HFmode);
+  PUT_MODE (operands[2], QFmode);
+  PUT_MODE (operands[3], QImode);")
+
+(define_insn "*loadhf_float"
+ [(set (match_operand:HF 0 "reg_operand" "=h")
+       (float_extend:HF (match_operand:QF 1 "src_operand" "fmH")))]
+ ""
+ "@
+  ldfu\\t%1,%0"
+  [(set_attr "type" "unary")])
+
+(define_insn "*loadhf_int"
+ [(set (match_operand:HF 0 "reg_operand" "=h")
+       (unspec[(subreg:QI (match_dup 0) 0)
+               (match_operand:QI 1 "src_operand" "g")] 8))]
+ ""
+ "@
+  ldiu\\t%1,%0"
+  [(set_attr "type" "unary")])
+
+(define_insn "*storehf_float"
+  [(set (match_operand:QF 0 "memory_operand" "=m")
+        (float_truncate:QF (match_operand:HF 1 "reg_operand" "h")))]
+  ""
+  "stf\\t%1,%0"
+  [(set_attr "type" "store")])
+
+(define_insn "*storehf_int"
+ [(set (match_operand:QI 0 "memory_operand" "=m")
+       (unspec [(match_operand:HF 1 "reg_operand" "h")] 9))]
+ ""
+ "@
+  sti\\t%1,%0"
+  [(set_attr "type" "store")])
+
+(define_insn "extendqfhf2"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (float_extend:HF (match_operand:QF 1 "reg_operand" "h")))]
+  ""
+  "ldfu\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "trunchfqf2"
+  [(set (match_operand:QF 0 "reg_operand" "=h")
+        (float_truncate:QF (match_operand:HF 1 "reg_operand" "0")))
+   (clobber (reg:CC 21))]
+  ""
+  "andn\\t0ffh,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; PUSH/POP
+;
+(define_insn "*pushhf"
+  [(set (mem:HF (pre_inc:QI (reg:QI 20)))
+        (match_operand:HF 0 "reg_operand" "h"))]
+ ""
+ "#"
+ [(set_attr "type" "multi")])
+
+(define_split
+ [(set (mem:HF (pre_inc:QI (reg:QI 20)))
+        (match_operand:HF 0 "reg_operand" ""))]
+  "reload_completed"
+  [(set (mem:QF (pre_inc:QI (reg:QI 20)))
+        (float_truncate:QF (match_dup 0)))
+   (set (mem:QI (pre_inc:QI (reg:QI 20)))
+        (unspec [(match_dup 0)] 9))]
+ "")
+
+(define_insn "pushhf_trunc"
+  [(set (mem:QF (pre_inc:QI (reg:QI 20)))
+        (float_truncate:QF (match_operand:HF 0 "reg_operand" "h")))]
+ ""
+ "pushf\\t%0"
+ [(set_attr "type" "push")])
+
+(define_insn "pushhf_int"
+  [(set (mem:QI (pre_inc:QI (reg:QI 20)))
+        (unspec [(match_operand:HF 0 "reg_operand" "h")] 9))]
+ ""
+ "push\\t%0"
+ [(set_attr "type" "push")])
+
+; we can not use this because the popf will destroy the low 8 bits
+;(define_insn "*pophf"
+;  [(set (match_operand:HF 0 "reg_operand" "=h")
+;        (mem:HF (post_dec:QI (reg:QI 20))))
+;   (clobber (reg:CC 21))]
+; ""
+; "#"
+; [(set_attr "type" "multi")])
+
+(define_split
+ [(set (match_operand:HF 0 "reg_operand" "")
+       (mem:HF (post_dec:QI (reg:QI 20))))
+   (clobber (reg:CC 21))]
+  "reload_completed"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "=h")
+                   (float_extend:HF (mem:QF (post_dec:QI (reg:QI 20)))))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 0)
+                   (unspec[(subreg:QI (match_dup 0) 0)
+                   (mem:QI (post_dec:QI (reg:QI 20)))] 8))
+              (clobber (reg:CC 21))])]
+ "")
+
+(define_insn "*pophf_int"
+ [(set (match_operand:HF 0 "reg_operand" "=h")
+       (unspec[(subreg:QI (match_dup 0) 0)
+               (mem:QI (post_dec:QI (reg:QI 20)))] 8))
+  (clobber (reg:CC 21))]
+ ""
+ "@
+  pop\\t%0"
+  [(set_attr "type" "pop")])
+
+(define_insn "*pophf_float"
+ [(set (match_operand:HF 0 "reg_operand" "=h")
+       (float_extend:HF (mem:QF (post_dec:QI (reg:QI 20)))))
+  (clobber (reg:CC 21))]
+ ""
+ "@
+  popf\\t%0"
+  [(set_attr "type" "unary")])
+
+;
+; FIX
+;
+(define_insn "fixhfqi_clobber"
+  [(set (match_operand:QI 0 "reg_operand" "=dc")
+        (fix:QI (match_operand:HF 1 "reg_or_const_operand" "hH")))
+   (clobber (reg:CC 21))]
+ ""
+ "fix\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; ABSF
+;
+(define_expand "abshf2"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "")
+                   (abs:HF (match_operand:HF 1 "reg_or_const_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+""
+"")
+
+(define_insn "*abshf2_clobber"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (abs:HF (match_operand:HF 1 "reg_or_const_operand" "hH")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "absf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*abshf2_test"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (abs:HF (match_operand:HF 1 "reg_operand" "h"))
+                         (match_operand:HF 2 "fp_zero_operand" "G")))
+   (clobber (match_scratch:HF 0 "=h"))]
+  ""
+  "absf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*abshf2_set"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (abs:HF (match_operand:HF 1 "reg_or_const_operand" "hH"))
+                         (match_operand:HF 2 "fp_zero_operand" "G")))
+   (set (match_operand:HF 0 "reg_operand" "=h")
+        (abs:HF (match_dup 1)))]
+
+  ""
+  "absf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; NEGF
+;
+(define_expand "neghf2"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "")
+                   (neg:HF (match_operand:HF 1 "reg_or_const_operand" "")))
+              (clobber (reg:CC 21))])]
+""
+"")
+
+(define_insn "*neghf2_clobber"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (neg:HF (match_operand:HF 1 "reg_or_const_operand" "hH")))
+   (clobber (reg:CC 21))]
+  ""
+  "negf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*neghf2_test"
+  [(set (reg:CC 21)
+        (compare:CC (neg:HF (match_operand:HF 1 "reg_or_const_operand" "hH"))
+                    (match_operand:HF 2 "fp_zero_operand" "G")))
+   (clobber (match_scratch:HF 0 "=h"))]
+  ""
+  "negf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+(define_insn "*neghf2_set"
+  [(set (reg:CC 21)
+        (compare:CC (neg:HF (match_operand:HF 1 "reg_or_const_operand" "hH"))
+                    (match_operand:HF 2 "fp_zero_operand" "G")))
+   (set (match_operand:HF 0 "reg_operand" "=h")
+        (neg:HF (match_dup 1)))]
+  ""
+  "negf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; RCPF
+;
+(define_insn "*rcpfhf_clobber"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (unspec [(match_operand:HF 1 "reg_or_const_operand" "hH")] 5))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X"
+  "rcpf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; RSQRF
+;
+(define_insn "*rsqrfhf_clobber"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (unspec [(match_operand:HF 1 "reg_or_const_operand" "hH")] 10))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X"
+  "rsqrf\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+;
+; RNDF
+;
+(define_insn "*rndhf_clobber"
+  [(set (match_operand:HF 0 "reg_operand" "=h")
+        (unspec [(match_operand:HF 1 "reg_or_const_operand" "hH")] 6))
+   (clobber (reg:CC_NOOV 21))]
+  "!TARGET_C3X"
+  "rnd\\t%1,%0"
+  [(set_attr "type" "unarycc")])
+
+
+; Inlined float square root for C4x
+(define_expand "sqrthf2_inline"
+  [(parallel [(set (match_dup 2)
+                  (unspec [(match_operand:HF 1 "reg_operand" "")] 10))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 3) (mult:HF (match_dup 5) (match_dup 1)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:HF (match_dup 6) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 2) (mult:HF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:HF (match_dup 6) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 2) (mult:HF (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_operand:HF 0 "reg_operand" "")
+                  (mult:HF (match_dup 2) (match_dup 1)))
+             (clobber (reg:CC_NOOV 21))])]
+  "!TARGET_C3X"
+  "
+  operands[2] = gen_reg_rtx (HFmode);
+  operands[3] = gen_reg_rtx (HFmode);
+  operands[4] = gen_reg_rtx (HFmode);
+  operands[5] = immed_real_const_1 (REAL_VALUE_ATOF (\"0.5\", HFmode), HFmode);
+  operands[6] = immed_real_const_1 (REAL_VALUE_ATOF (\"1.5\", HFmode), HFmode);
+  ")
+
+
+(define_expand "sqrthf2"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "")
+                   (sqrt:HF (match_operand:HF 1 "reg_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "if (TARGET_C3X || !TARGET_INLINE)
+     FAIL;
+   else
+     {
+       emit_insn (gen_sqrthf2_inline( operands[0], operands[1]));
+       DONE;
+     }
+  ")
+
+(define_expand "fix_trunchfhi2"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (fix:HI (match_operand:HF 1 "reg_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FIX_TRUNCHFHI2_LIBCALL, FIX, HImode, HFmode, 2, operands);
+   DONE;")
+
+(define_expand "fixuns_trunchfhi2"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (unsigned_fix:HI (match_operand:HF 1 "reg_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FIXUNS_TRUNCHFHI2_LIBCALL, UNSIGNED_FIX, 
+                     HImode, HFmode, 2, operands);
+   DONE;")
+
+;
+; THREE OPERAND LONG DOUBLE INSTRUCTIONS
+;
+
+;
+; ADDF
+;
+(define_insn "addhf3"
+  [(set (match_operand:HF 0 "reg_operand" "=?h,h")
+        (plus:HF (match_operand:HF 1 "reg_operand" "%h,0")
+                 (match_operand:HF 2 "reg_or_const_operand" "h,H")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "@
+   addf3\\t%2,%1,%0
+   addf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc")])
+
+;
+; SUBF
+;
+(define_insn "subhf3"
+  [(set (match_operand:HF 0 "reg_operand" "=?h,h,h")
+        (minus:HF (match_operand:HF 1 "reg_or_const_operand" "h,0,H")
+                  (match_operand:HF 2 "reg_or_const_operand" "h,H,0")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "@
+   subf3\\t%2,%1,%0
+   subf\\t%2,%0
+   subrf\\t%1,%0"
+  [(set_attr "type" "binarycc,binarycc,binarycc")])
+
+;
+; MULF
+;
+; The C3x MPYF only uses 24 bit precision while the C4x uses 32 bit precison.
+;
+(define_expand "mulhf3"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "=h")
+                   (mult:HF (match_operand:HF 1 "reg_operand" "h")
+                            (match_operand:HF 2 "reg_operand" "h")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "if (TARGET_C3X)
+     {
+       c4x_emit_libcall3 (MULHF3_LIBCALL, MULT, HFmode, operands);
+       DONE;
+     }
+  ")
+
+(define_insn "*mulhf3_c40"
+  [(set (match_operand:HF 0 "reg_operand" "=?h,h")
+        (mult:HF (match_operand:HF 1 "reg_operand" "%h,0")
+                 (match_operand:HF 2 "reg_or_const_operand" "h,hH")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "@
+   mpyf3\\t%2,%1,%0
+   mpyf\\t%2,%0"
+  [(set_attr "type" "binarycc,binarycc")])
+
+;
+; CMPF
+;
+(define_expand "cmphf"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:HF 0 "reg_operand" "")
+                    (match_operand:HF 1 "reg_or_const_operand" "")))]
+  ""
+  "c4x_compare_op0 = operands[0];
+   c4x_compare_op1 = operands[1];
+   DONE;")
+
+(define_insn "*cmphf"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:HF 0 "reg_operand" "h")
+                    (match_operand:HF 1 "reg_or_const_operand" "hH")))]
+  ""
+  "cmpf\\t%1,%0"
+  [(set_attr "type" "compare")])
+
+(define_insn "*cmphf_noov"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (match_operand:HF 0 "reg_operand" "h")
+                         (match_operand:HF 1 "reg_or_const_operand" "hH")))]
+  ""
+  "cmpf\\t%1,%0"
+  [(set_attr "type" "compare")])
+
+; Inlined float divide for C4x
+(define_expand "divhf3_inline"
+  [(parallel [(set (match_dup 3)
+                  (unspec [(match_operand:HF 2 "reg_operand" "")] 5))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:HF (match_dup 5) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 3) (mult:HF (match_dup 3) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 4) (minus:HF (match_dup 5) (match_dup 4)))
+              (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_dup 3) (mult:HF (match_dup 3) (match_dup 4)))
+             (clobber (reg:CC_NOOV 21))])
+   (parallel [(set (match_operand:HF 0 "reg_operand" "")
+                  (mult:HF (match_operand:HF 1 "reg_operand" "")
+                           (match_dup 3)))
+             (clobber (reg:CC_NOOV 21))])]
+  "!TARGET_C3X"
+  "
+  operands[3] = gen_reg_rtx (HFmode);
+  operands[4] = gen_reg_rtx (HFmode);
+  operands[5] = CONST2_RTX (HFmode);
+  ")
+
+(define_expand "divhf3"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "")
+                   (div:HF (match_operand:HF 1 "reg_operand" "")
+                           (match_operand:HF 2 "reg_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "if (TARGET_C3X || !TARGET_INLINE)
+     {
+       c4x_emit_libcall3 (DIVHF3_LIBCALL, DIV, HFmode, operands);
+       DONE;
+     }
+   else
+     {
+       emit_insn (gen_divhf3_inline( operands[0], operands[1], operands[2]));
+       DONE;
+     }
+  ")
+
+
+;
+; TWO OPERAND LONG LONG INSTRUCTIONS
+;
+
+; We could load some constants using define_splits for the C30
+; in the large memory model---these would emit shift and or insns.
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "src_operand" "")
+        (match_operand:HI 1 "src_operand" ""))]
+ ""
+ "if (CONSTANT_P (operands[1]))
+    {
+      /* We don't need to force all constants into memory.
+         This could be improved.... */
+      operands[1] = force_const_mem (HImode, operands[1]); 
+      if (!memory_address_p (HImode, XEXP (operands[1], 0))
+          && !reload_in_progress)
+        operands[1] = change_address (operands[1], HImode,
+                                      XEXP (operands[1], 0));
+     }
+
+  /* Memory to memory copies must go through a register.  */
+  if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[0]) == MEM
+      && !reload_in_progress)
+    operands[1] = force_reg (HImode, operands[1]); 
+")
+
+; The constraints for movhi must include 'r' if we don't
+; restrict HImode regnos to start on an even number, since
+; we can get RC, R8 allocated as a pair.  We want more
+; votes for FP_REGS so we use dr as the constraints.
+(define_insn "*movhi_noclobber"
+  [(set (match_operand:HI 0 "src_operand" "=dr,m")
+        (match_operand:HI 1 "src_operand" "drm,r"))]
+  "reg_operand (operands[0], HImode)
+   || reg_operand (operands[1], HImode)"
+  "#"
+  [(set_attr "type" "multi,multi")])
+
+(define_split
+  [(set (match_operand:HI 0 "src_operand" "")
+       (match_operand:HI 1 "src_operand" ""))]
+  "reload_completed
+   && (reg_operand (operands[0], HImode) || reg_operand (operands[1], HImode))"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 4) (match_dup 5))]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[3] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[1], 1, 1, HImode);")
+
+
+(define_insn "extendqihi2"
+  [(set (match_operand:HI 0 "reg_operand" "=dc")
+        (sign_extend:HI (match_operand:QI 1 "src_operand" "g")))
+   (clobber (reg:CC 21))]
+  ""
+  "#"
+  [(set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:HI 0 "reg_operand" "=?dc")
+        (sign_extend:HI (match_operand:QI 1 "src_operand" "g")))
+   (clobber (reg:CC 21))]
+  "reload_completed && TARGET_C3X"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 3) (match_dup 2))
+   (parallel [(set (match_dup 3) (ashiftrt:QI (match_dup 3) (const_int 31)))
+              (clobber (reg:CC 21))])]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode);
+   operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);")
+
+(define_split
+  [(set (match_operand:HI 0 "reg_operand" "=?dc")
+        (sign_extend:HI (match_operand:QI 1 "src_operand" "g")))
+   (clobber (reg:CC 21))]
+  "reload_completed && !TARGET_C3X"
+  [(set (match_dup 2) (match_dup 1))
+   (parallel [(set (match_dup 3) (ashiftrt:QI (match_dup 2) (const_int 31)))
+              (clobber (reg:CC 21))])]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode);
+   operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);")
+
+(define_insn "zero_extendqihi2"
+  [(set (match_operand:HI 0 "reg_operand" "=?dc")
+        (zero_extend:HI (match_operand:QI 1 "src_operand" "g")))
+   (clobber (reg:CC 21))]
+  ""
+  "#"
+  [(set_attr "type" "multi")])
+
+; If operand0 and operand1 are the same register we don't need
+; the first set.
+(define_split
+  [(set (match_operand:HI 0 "reg_operand" "=?dc")
+        (zero_extend:HI (match_operand:QI 1 "src_operand" "g")))
+   (clobber (reg:CC 21))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 3) (const_int 0))]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode);
+   operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);")
+
+;
+; PUSH/POP
+;
+(define_insn "*pushhi"
+  [(set (mem:HI (pre_inc:QI (reg:QI 20)))
+        (match_operand:HI 0 "reg_operand" "r"))]
+  ""
+  "#"
+  [(set_attr "type" "multi")])
+
+(define_split
+  [(set (mem:HI (pre_inc:QI (reg:QI 20)))
+        (match_operand:HI 0 "reg_operand" ""))]
+  "reload_completed"
+  [(set (mem:QI (pre_inc:QI (reg:QI 20))) (match_dup 2))
+   (set (mem:QI (pre_inc:QI (reg:QI 20))) (match_dup 3))]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode);
+   operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);")
+
+(define_insn "*pophi"
+  [(set (match_operand:HI 0 "reg_operand" "=r")
+        (mem:HI (post_dec:QI (reg:QI 20))))
+   (clobber (reg:CC 21))]
+  ""
+  "#"
+  [(set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:HI 0 "reg_operand" "")
+       (mem:HI (pre_inc:QI (reg:QI 20))))]
+  "reload_completed"
+  [(set (match_dup 2) (mem:QI (pre_inc:QI (reg:QI 20))))
+   (set (match_dup 3) (mem:QI (pre_inc:QI (reg:QI 20))))]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode);
+   operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);")
+
+;
+; NEG
+;
+(define_insn "neghi2"
+  [(set (match_operand:HI 0 "ext_reg_operand" "=d")
+        (neg:HI (match_operand:HI 1 "src_operand" "rm")))
+   (clobber (reg:CC_NOOV 21))]
+  ""
+  "#"
+  [(set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:HI 0 "ext_reg_operand" "")
+        (neg:HI (match_operand:HI 1 "src_operand" "")))
+   (clobber (reg:CC_NOOV 21))]
+  "reload_completed"
+   [(parallel [(set (reg:CC_NOOV 21)
+                    (compare:CC_NOOV (neg:QI (match_dup 3))
+                                     (const_int 0)))
+               (set (match_dup 2) (neg:QI (match_dup 3)))])
+   (parallel [(set (match_dup 4) (neg:QI (match_dup 5)))
+              (use (reg:CC_NOOV 21))
+              (clobber (reg:CC_NOOV 21))])]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[3] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[1], 1, 1, HImode);")
+
+(define_insn "one_cmplhi2"
+  [(set (match_operand:HI 0 "reg_operand" "=r")
+        (not:HI (match_operand:HI 1 "src_operand" "rm")))
+   (clobber (reg:CC 21))]
+  ""
+  "#"
+  [(set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:HI 0 "reg_operand" "")
+        (not:HI (match_operand:HI 1 "src_operand" "")))
+   (clobber (reg:CC 21))]
+  "reload_completed"
+   [(parallel [(set (match_dup 2) (not:QI (match_dup 3)))
+               (clobber (reg:CC 21))])
+    (parallel [(set (match_dup 4) (not:QI (match_dup 5)))
+               (clobber (reg:CC 21))])]
+  "operands[2] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[3] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[1], 1, 1, HImode);")
+
+(define_expand "floathiqf2"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (float:QF (match_operand:HI 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FLOATHIQF2_LIBCALL, FLOAT, QFmode, HImode, 2, operands);
+   DONE;")
+
+(define_expand "floatunshiqf2"
+  [(parallel [(set (match_operand:QF 0 "reg_operand" "")
+                   (unsigned_float:QF (match_operand:HI 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FLOATUNSHIQF2_LIBCALL, UNSIGNED_FLOAT,
+                     QFmode, HImode, 2, operands);
+   DONE;")
+
+(define_expand "floathihf2"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "")
+                   (float:HF (match_operand:HI 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FLOATHIHF2_LIBCALL, FLOAT, HFmode, HImode, 2, operands);
+   DONE;")
+
+(define_expand "floatunshihf2"
+  [(parallel [(set (match_operand:HF 0 "reg_operand" "")
+                   (unsigned_float:HF (match_operand:HI 1 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall (FLOATUNSHIHF2_LIBCALL, UNSIGNED_FLOAT,
+                     HFmode, HImode, 2, operands);
+   DONE;")
+
+
+;
+; THREE OPERAND LONG LONG INSTRUCTIONS
+;
+
+(define_expand "addhi3"
+  [(parallel [(set (match_operand:HI 0 "ext_reg_operand" "")
+                   (plus:HI (match_operand:HI 1 "src_operand" "")
+                            (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "legitimize_operands (PLUS, operands, HImode);")
+
+(define_insn "*addhi3_clobber"
+  [(set (match_operand:HI 0 "ext_reg_operand" "=d,?d,d")
+        (plus:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0")
+                 (match_operand:HI 2 "src_operand" "R,rS<>,rm")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (PLUS, operands, HImode)"
+  "#"
+  [(set_attr "type" "multi,multi,multi")])
+
+(define_split
+ [(set (match_operand:HI 0 "ext_reg_operand" "")
+       (plus:HI (match_operand:HI 1 "src_operand" "")
+                (match_operand:HI 2 "src_operand" "")))
+  (clobber (reg:CC_NOOV 21))]
+ "reload_completed"
+  [(parallel [(set (reg:CC_NOOV 21)
+                   (compare:CC_NOOV (plus:QI (match_dup 4) (match_dup 5))
+                                    (const_int 0)))
+              (set (match_dup 3) (plus:QI (match_dup 4) (match_dup 5)))])
+   (parallel [(set (match_dup 6) (plus:QI (match_dup 7) (match_dup 8)))
+              (use (reg:CC_NOOV 21))
+              (clobber (reg:CC_NOOV 21))])]
+  "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode);
+   operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode);
+   operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);")
+
+(define_expand "subhi3"
+  [(parallel [(set (match_operand:HI 0 "ext_reg_operand" "")
+                   (minus:HI (match_operand:HI 1 "src_operand" "")
+                             (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC_NOOV 21))])]
+  ""
+  "legitimize_operands (MINUS, operands, HImode);")
+
+
+(define_insn "*subhi3_clobber"
+  [(set (match_operand:HI 0 "ext_reg_operand" "=d,?d,d")
+        (minus:HI (match_operand:HI 1 "src_operand" "rR,rS<>,0")
+                  (match_operand:HI 2 "src_operand" "R,rS<>,rm")))
+   (clobber (reg:CC_NOOV 21))]
+  "valid_operands (MINUS, operands, HImode)"
+  "#"
+  [(set_attr "type" "multi,multi,multi")])
+
+(define_split
+ [(set (match_operand:HI 0 "ext_reg_operand" "")
+       (minus:HI (match_operand:HI 1 "src_operand" "")
+                 (match_operand:HI 2 "src_operand" "")))
+  (clobber (reg:CC_NOOV 21))]
+ "reload_completed"
+  [(parallel [(set (reg:CC_NOOV 21)
+                   (compare:CC_NOOV (minus:QI (match_dup 4) (match_dup 5))
+                                    (const_int 0)))
+              (set (match_dup 3) (minus:QI (match_dup 4) (match_dup 5)))])
+   (parallel [(set (match_dup 6) (minus:QI (match_dup 7) (match_dup 8)))
+              (use (reg:CC_NOOV 21))
+              (clobber (reg:CC_NOOV 21))])]
+  "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode);
+   operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode);
+   operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);")
+
+(define_expand "iorhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (ior:HI (match_operand:HI 1 "src_operand" "")
+                           (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "legitimize_operands (IOR, operands, HImode);")
+
+(define_insn "*iorhi3_clobber"
+  [(set (match_operand:HI 0 "reg_operand" "=d,?d,d")
+        (ior:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0")
+                (match_operand:HI 2 "src_operand" "R,rS<>,rm")))
+   (clobber (reg:CC 21))]
+  "valid_operands (IOR, operands, HImode)"
+  "#"
+  [(set_attr "type" "multi,multi,multi")])
+
+(define_split
+ [(set (match_operand:HI 0 "reg_operand" "")
+       (ior:HI (match_operand:HI 1 "src_operand" "")
+               (match_operand:HI 2 "src_operand" "")))
+  (clobber (reg:CC 21))]
+ "reload_completed"
+  [(parallel [(set (match_dup 3) (ior:QI (match_dup 4) (match_dup 5)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 6) (ior:QI (match_dup 7) (match_dup 8)))
+              (clobber (reg:CC 21))])]
+  "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode);
+   operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode);
+   operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);")
+
+(define_expand "andhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (and:HI (match_operand:HI 1 "src_operand" "")
+                           (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "legitimize_operands (AND, operands, HImode);")
+
+(define_insn "*andhi3_clobber"
+  [(set (match_operand:HI 0 "reg_operand" "=d,?d,d")
+        (and:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0")
+                (match_operand:HI 2 "src_operand" "R,rS<>,rm")))
+   (clobber (reg:CC 21))]
+  "valid_operands (AND, operands, HImode)"
+  "#"
+  [(set_attr "type" "multi,multi,multi")])
+
+(define_split
+ [(set (match_operand:HI 0 "reg_operand" "")
+       (and:HI (match_operand:HI 1 "src_operand" "")
+                (match_operand:HI 2 "src_operand" "")))
+  (clobber (reg:CC 21))]
+ "reload_completed"
+  [(parallel [(set (match_dup 3) (and:QI (match_dup 4) (match_dup 5)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 6) (and:QI (match_dup 7) (match_dup 8)))
+              (clobber (reg:CC 21))])]
+  "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode);
+   operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode);
+   operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);")
+
+(define_expand "xorhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (xor:HI (match_operand:HI 1 "src_operand" "")
+                           (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "legitimize_operands (AND, operands, HImode);")
+
+
+(define_insn "*xorhi3_clobber"
+  [(set (match_operand:HI 0 "reg_operand" "=d,?d,d")
+        (xor:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0")
+                (match_operand:HI 2 "src_operand" "R,rS<>,rm")))
+   (clobber (reg:CC 21))]
+  "valid_operands (XOR, operands, HImode)"
+  "#"
+  [(set_attr "type" "multi,multi,multi")])
+
+(define_split
+ [(set (match_operand:HI 0 "reg_operand" "")
+       (xor:HI (match_operand:HI 1 "src_operand" "")
+               (match_operand:HI 2 "src_operand" "")))
+  (clobber (reg:CC 21))]
+ "reload_completed"
+  [(parallel [(set (match_dup 3) (xor:QI (match_dup 4) (match_dup 5)))
+              (clobber (reg:CC 21))])
+   (parallel [(set (match_dup 6) (xor:QI (match_dup 7) (match_dup 8)))
+              (clobber (reg:CC 21))])]
+  "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode);
+   operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode);
+   operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode);
+   operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode);
+   operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode);
+   operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);")
+
+; This should do all the dirty work with define_split
+(define_expand "ashlhi3"
+ [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+             (ashift:HI (match_operand:HI 1 "src_operand" "")
+                        (match_operand:QI 2 "src_operand" "")))
+             (clobber (reg:CC 21))])]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32)
+    {
+       rtx op0hi = operand_subword (operands[0], 1, 0, HImode);
+       rtx op0lo = operand_subword (operands[0], 0, 0, HImode);
+       rtx op1lo = operand_subword (operands[1], 0, 0, HImode);
+       rtx count = gen_rtx (CONST_INT, VOIDmode, 
+                            (INTVAL (operands[2]) - 32));
+
+       if (INTVAL (count))
+         emit_insn (gen_ashlqi3 (op0hi, op1lo, count));
+       else
+         emit_insn (gen_movqi (op0hi, op1lo));
+       emit_insn (gen_movqi (op0lo, const0_rtx));
+       DONE;
+    }
+    emit_insn (gen_ashlhi3_reg (operands[0], operands[1], operands[2]));
+    DONE;")
+
+; %0.lo = %1.lo << %2
+; %0.hi = (%1.hi << %2 ) | (%1.lo >> (32 - %2))
+; This algorithm should work for shift counts greater than 32
+(define_expand "ashlhi3_reg" 
+ [(use (match_operand:HI 1 "src_operand" ""))
+  (use (match_operand:HI 0 "reg_operand" ""))
+  /* If the shift count is greater than 32 this will give zero.  */
+  (parallel [(set (match_dup 7)
+                  (ashift:QI (match_dup 3)
+                             (match_operand:QI 2 "reg_operand" "")))
+             (clobber (reg:CC 21))])
+  /* If the shift count is greater than 32 this will give zero.  */
+  (parallel [(set (match_dup 8)
+                  (ashift:QI (match_dup 4) (match_dup 2)))
+             (clobber (reg:CC 21))])
+  (parallel [(set (match_dup 10)
+                  (plus:QI (match_dup 2) (const_int -32)))
+             (clobber (reg:CC_NOOV 21))])
+  /* If the shift count is greater than 32 this will do a left shift.  */
+  (parallel [(set (match_dup 9)
+                  (lshiftrt:QI (match_dup 3) (neg:QI (match_dup 10))))
+             (clobber (reg:CC 21))])
+  (set (match_dup 5) (match_dup 7))
+  (parallel [(set (match_dup 6)
+                  (ior:QI (match_dup 8) (match_dup 9)))
+             (clobber (reg:CC 21))])]
+ ""
+ " 
+  operands[3] = operand_subword (operands[1], 0, 1, HImode); /* lo */
+  operands[4] = operand_subword (operands[1], 1, 1, HImode); /* hi */
+  operands[5] = operand_subword (operands[0], 0, 1, HImode); /* lo */
+  operands[6] = operand_subword (operands[0], 1, 1, HImode); /* hi */
+  operands[7] = gen_reg_rtx (QImode); /* lo << count */
+  operands[8] = gen_reg_rtx (QImode); /* hi << count */
+  operands[9] = gen_reg_rtx (QImode); /* lo >> (32 - count) */
+  operands[10] = gen_reg_rtx (QImode); /* 32 - count */
+ ")
+
+; This should do all the dirty work with define_split
+(define_expand "lshrhi3"
+ [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+             (lshiftrt:HI (match_operand:HI 1 "src_operand" "")
+                          (match_operand:QI 2 "src_operand" "")))
+             (clobber (reg:CC 21))])]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32)
+    {
+       rtx op0hi = operand_subword (operands[0], 1, 0, HImode);
+       rtx op0lo = operand_subword (operands[0], 0, 0, HImode);
+       rtx op1hi = operand_subword (operands[1], 1, 0, HImode);
+       rtx count = gen_rtx (CONST_INT, VOIDmode, 
+                            (INTVAL (operands[2]) - 32));
+
+       if (INTVAL (count))
+         emit_insn (gen_lshrqi3 (op0lo, op1hi, count));
+       else
+         emit_insn (gen_movqi (op0lo, op1hi));
+       emit_insn (gen_movqi (op0hi, const0_rtx));
+       DONE;
+    }
+    emit_insn (gen_lshrhi3_reg (operands[0], operands[1], operands[2]));
+    DONE;")
+
+; %0.hi = %1.hi >> %2
+; %0.lo = (%1.lo >> %2 ) | (%1.hi << (32 - %2))
+; This algorithm should work for shift counts greater than 32
+(define_expand "lshrhi3_reg" 
+ [(use (match_operand:HI 1 "src_operand" ""))
+  (use (match_operand:HI 0 "reg_operand" ""))
+  (parallel [(set (match_dup 11)
+                  (neg:QI (match_operand:QI 2 "reg_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  /* If the shift count is greater than 32 this will give zero.  */
+  (parallel [(set (match_dup 7)
+                  (lshiftrt:QI (match_dup 3)
+                               (neg:QI (match_dup 11))))
+             (clobber (reg:CC 21))])
+  /* If the shift count is greater than 32 this will give zero.  */
+  (parallel [(set (match_dup 8)
+                  (lshiftrt:QI (match_dup 4) 
+                               (neg:QI (match_dup 11))))
+             (clobber (reg:CC 21))])
+  (parallel [(set (match_dup 10)
+                  (plus:QI (match_dup 11) (const_int 32)))
+             (clobber (reg:CC_NOOV 21))])
+  /* If the shift count is greater than 32 this will do an arithmetic
+     right shift.  However, we need a logical right shift.  */
+  (parallel [(set (match_dup 9)
+                  (ashift:QI (match_dup 4) (unspec [(match_dup 10)] 3)))
+             (clobber (reg:CC 21))])
+  (set (match_dup 6) (match_dup 8))
+  (parallel [(set (match_dup 5)
+                  (ior:QI (match_dup 7) (match_dup 9)))
+             (clobber (reg:CC 21))])]
+ ""
+ " 
+  operands[3] = operand_subword (operands[1], 0, 1, HImode); /* lo */
+  operands[4] = operand_subword (operands[1], 1, 1, HImode); /* hi */
+  operands[5] = operand_subword (operands[0], 0, 1, HImode); /* lo */
+  operands[6] = operand_subword (operands[0], 1, 1, HImode); /* hi */
+  operands[7] = gen_reg_rtx (QImode); /* lo >> count */
+  operands[8] = gen_reg_rtx (QImode); /* hi >> count */
+  operands[9] = gen_reg_rtx (QImode); /* hi << (32 - count) */
+  operands[10] = gen_reg_rtx (QImode); /* 32 - count */
+  operands[11] = gen_reg_rtx (QImode); /* -count */
+ ")
+
+; This should do all the dirty work with define_split
+(define_expand "ashrhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+              (ashiftrt:HI (match_operand:HI 1 "src_operand" "")
+                           (match_operand:QI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32)
+    {
+       rtx op0hi = operand_subword (operands[0], 1, 0, HImode);
+       rtx op0lo = operand_subword (operands[0], 0, 0, HImode);
+       rtx op1hi = operand_subword (operands[1], 1, 0, HImode);
+       rtx count = gen_rtx (CONST_INT, VOIDmode, 
+                            (INTVAL (operands[2]) - 32));
+
+       if (INTVAL (count))
+         emit_insn (gen_ashrqi3 (op0lo, op1hi, count));
+       else
+         emit_insn (gen_movqi (op0lo, op1hi));
+       emit_insn (gen_ashrqi3 (op0hi, op1hi, gen_rtx (CONST_INT,
+                                                      VOIDmode, 31)));
+       DONE;
+    }
+    emit_insn (gen_ashrhi3_reg (operands[0], operands[1], operands[2]));
+    DONE;")
+
+; %0.hi = %1.hi >> %2
+; %0.lo = (%1.lo >> %2 ) | (%1.hi << (32 - %2))
+; This algorithm should work for shift counts greater than 32
+(define_expand "ashrhi3_reg" 
+ [(use (match_operand:HI 1 "src_operand" ""))
+  (use (match_operand:HI 0 "reg_operand" ""))
+  (parallel [(set (match_dup 11)
+                  (neg:QI (match_operand:QI 2 "reg_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  /* If the shift count is greater than 32 this will give zero.  */
+  (parallel [(set (match_dup 7)
+                  (lshiftrt:QI (match_dup 3)
+                               (neg:QI (match_dup 11))))
+             (clobber (reg:CC 21))])
+  /* If the shift count is greater than 32 this will give zero.  */
+  (parallel [(set (match_dup 8)
+                  (ashiftrt:QI (match_dup 4) 
+                               (neg:QI (match_dup 11))))
+             (clobber (reg:CC 21))])
+  (parallel [(set (match_dup 10)
+                  (plus:QI (match_dup 11) (const_int 32)))
+             (clobber (reg:CC_NOOV 21))])
+  /* If the shift count is greater than 32 this will do an arithmetic
+     right shift.  */
+  (parallel [(set (match_dup 9)
+                  (ashift:QI (match_dup 4) (match_dup 10)))
+             (clobber (reg:CC 21))])
+  (set (match_dup 6) (match_dup 8))
+  (parallel [(set (match_dup 5)
+                  (ior:QI (match_dup 7) (match_dup 9)))
+             (clobber (reg:CC 21))])]
+ ""
+ " 
+  operands[3] = operand_subword (operands[1], 0, 1, HImode); /* lo */
+  operands[4] = operand_subword (operands[1], 1, 1, HImode); /* hi */
+  operands[5] = operand_subword (operands[0], 0, 1, HImode); /* lo */
+  operands[6] = operand_subword (operands[0], 1, 1, HImode); /* hi */
+  operands[7] = gen_reg_rtx (QImode); /* lo >> count */
+  operands[8] = gen_reg_rtx (QImode); /* hi >> count */
+  operands[9] = gen_reg_rtx (QImode); /* hi << (32 - count) */
+  operands[10] = gen_reg_rtx (QImode); /* 32 - count */
+  operands[11] = gen_reg_rtx (QImode); /* -count */
+ ")
+
+(define_expand "cmphi"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:HI 0 "src_operand" "")
+                    (match_operand:HI 1 "src_operand" "")))]
+  ""
+  "legitimize_operands (COMPARE, operands, HImode);
+   c4x_compare_op0 = operands[0];
+   c4x_compare_op1 = operands[1];
+   DONE;")
+
+; This works only before reload because we need 2 extra registers.
+; Use unspec to avoid recursive split.
+(define_split
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:HI 0 "src_operand" "")
+                    (match_operand:HI 1 "src_operand" "")))]
+  "!reload_completed"
+  [(parallel [(set (reg:CC 21)
+                   (unspec [(compare:CC (match_dup 0)
+                                        (match_dup 1))] 4))
+              (clobber (match_scratch:QI 2 ""))
+             (clobber (match_scratch:QI 3 ""))])]
+  "")
+
+(define_split
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (match_operand:HI 0 "src_operand" "")
+                         (match_operand:HI 1 "src_operand" "")))]
+  "!reload_completed"
+  [(parallel [(set (reg:CC_NOOV 21)
+                   (unspec [(compare:CC_NOOV (match_dup 0)
+                                             (match_dup 1))] 4))
+              (clobber (match_scratch:QI 2 ""))
+             (clobber (match_scratch:QI 3 ""))])]
+  "")
+
+; This is normally not used. The define splits above are used first.
+(define_insn "*cmphi"
+  [(set (reg:CC 21)
+        (compare:CC (match_operand:HI 0 "src_operand" "rR,rS<>")
+                    (match_operand:HI 1 "src_operand" "R,rS<>")))]
+  "valid_operands (COMPARE, operands, HImode)"
+  "*
+   {
+     int use_ir1 = (reg_operand (operands[0], HImode)
+                   && REG_P (operands[0])
+                   && REGNO (operands[0]) == IR1_REGNO)
+                   || (reg_operand (operands[1], HImode)
+                       && REG_P (operands[1])
+                       && REGNO (operands[1]) == IR1_REGNO);
+
+     if (use_ir1)
+       output_asm_insn (\"push\\tir1\", operands);
+     else
+       output_asm_insn (\"push\\tbk\", operands);
+     output_asm_insn (\"push\\tr0\", operands);
+     output_asm_insn (\"subi3\\t%1,%0,r0\", operands);
+     if (use_ir1)
+       {
+         output_asm_insn (\"ldiu\\tst,ir1\", operands);
+         output_asm_insn (\"or\\t07bh,ir1\", operands);
+       }
+     else
+       {
+         output_asm_insn (\"ldiu\\tst,bk\", operands);
+         output_asm_insn (\"or\\t07bh,bk\", operands);
+       }
+     output_asm_insn (\"subb3\\t%O1,%O0,r0\", operands);
+     if (use_ir1)
+       output_asm_insn (\"and3\\tir1,st,ir1\", operands);
+     else
+       output_asm_insn (\"and3\\tbk,st,bk\", operands);
+     output_asm_insn (\"pop\\tr0\", operands);
+     if (use_ir1)
+       {
+         output_asm_insn (\"ldiu\\tir1,st\", operands);
+         output_asm_insn (\"pop\\tir1\", operands);
+       }
+     else
+       {
+         output_asm_insn (\"ldiu\\tbk,st\", operands);
+         output_asm_insn (\"pop\\tbk\", operands);
+       }
+     return \"\";
+   }"
+  [(set_attr "type" "multi")])
+(define_insn "*cmphi_noov"
+  [(set (reg:CC_NOOV 21)
+        (compare:CC_NOOV (match_operand:HI 0 "src_operand" "rR,rS<>")
+                    (match_operand:HI 1 "src_operand" "R,rS<>")))]
+  "valid_operands (COMPARE, operands, HImode)"
+  "*
+   {
+     int use_ir1 = (reg_operand (operands[0], HImode)
+                   && REG_P (operands[0])
+                   && REGNO (operands[0]) == IR1_REGNO)
+                   || (reg_operand (operands[1], HImode)
+                       && REG_P (operands[1])
+                       && REGNO (operands[1]) == IR1_REGNO);
+
+     if (use_ir1)
+       output_asm_insn (\"push\\tir1\", operands);
+     else
+       output_asm_insn (\"push\\tbk\", operands);
+     output_asm_insn (\"push\\tr0\", operands);
+     output_asm_insn (\"subi3\\t%1,%0,r0\", operands);
+     if (use_ir1)
+       {
+         output_asm_insn (\"ldiu\\tst,ir1\", operands);
+         output_asm_insn (\"or\\t07bh,ir1\", operands);
+       }
+     else
+       {
+         output_asm_insn (\"ldiu\\tst,bk\", operands);
+         output_asm_insn (\"or\\t07bh,bk\", operands);
+       }
+     output_asm_insn (\"subb3\\t%O1,%O0,r0\", operands);
+     if (use_ir1)
+       output_asm_insn (\"and3\\tir1,st,ir1\", operands);
+     else
+       output_asm_insn (\"and3\\tbk,st,bk\", operands);
+     output_asm_insn (\"pop\\tr0\", operands);
+     if (use_ir1)
+       {
+         output_asm_insn (\"ldiu\\tir1,st\", operands);
+         output_asm_insn (\"pop\\tir1\", operands);
+       }
+     else
+       {
+         output_asm_insn (\"ldiu\\tbk,st\", operands);
+         output_asm_insn (\"pop\\tbk\", operands);
+       }
+     return \"\";
+   }"
+  [(set_attr "type" "multi")])
+
+(define_insn "cmphi_cc"
+  [(set (reg:CC 21)
+        (unspec [(compare:CC (match_operand:HI 0 "src_operand" "rR,rS<>")
+                             (match_operand:HI 1 "src_operand" "R,rS<>"))] 4))
+   (clobber (match_scratch:QI 2 "=&d,&d"))
+   (clobber (match_scratch:QI 3 "=&c,&c"))]
+  "valid_operands (COMPARE, operands, HImode)"
+  "*
+   output_asm_insn (\"subi3\\t%1,%0,%2\", operands);
+   output_asm_insn (\"ldiu\\tst,%3\", operands);
+   output_asm_insn (\"or\\t07bh,%3\", operands);
+   output_asm_insn (\"subb3\\t%O1,%O0,%2\", operands);
+   output_asm_insn (\"and\\t%3,st\", operands);
+   return \"\";"
+  [(set_attr "type" "multi")])
+
+(define_insn "cmphi_cc_noov"
+  [(set (reg:CC_NOOV 21)
+        (unspec [(compare:CC_NOOV (match_operand:HI 0 "src_operand" "rR,rS<>")
+                                  (match_operand:HI 1 "src_operand" "R,rS<>"))] 4))
+   (clobber (match_scratch:QI 2 "=&d,&d"))
+   (clobber (match_scratch:QI 3 "=&c,&c"))]
+  "valid_operands (COMPARE, operands, HImode)"
+  "*
+   output_asm_insn (\"subi3\\t%1,%0,%2\", operands);
+   output_asm_insn (\"ldiu\\tst,%3\", operands);
+   output_asm_insn (\"or\\t07bh,%3\", operands);
+   output_asm_insn (\"subb3\\t%O1,%O0,%2\", operands);
+   output_asm_insn (\"and\\t%3,st\", operands);
+   return \"\";"
+  [(set_attr "type" "multi")])
+
+(define_expand "mulhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (mult:HI (match_operand:HI 1 "src_operand" "")
+                            (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (MULHI3_LIBCALL, MULT, HImode, operands);
+   DONE;")
+
+(define_expand "udivhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (udiv:HI (match_operand:HI 1 "src_operand" "")
+                            (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (UDIVHI3_LIBCALL, UDIV, HImode, operands);
+   DONE;")
+
+(define_expand "divhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (div:HI (match_operand:HI 1 "src_operand" "")
+                            (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (DIVHI3_LIBCALL, DIV, HImode, operands);
+   DONE;")
+
+(define_expand "umodhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (umod:HI (match_operand:HI 1 "src_operand" "")
+                            (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (UMODHI3_LIBCALL, UMOD, HImode, operands);
+   DONE;")
+
+(define_expand "modhi3"
+  [(parallel [(set (match_operand:HI 0 "reg_operand" "")
+                   (mod:HI (match_operand:HI 1 "src_operand" "")
+                            (match_operand:HI 2 "src_operand" "")))
+              (clobber (reg:CC 21))])]
+  ""
+  "c4x_emit_libcall3 (MODHI3_LIBCALL, MOD, HImode, operands);
+   DONE;")
+
+;
+; PEEPHOLES
+;
+
+; dbCC peepholes
+;
+; Turns
+;   loop:
+;           [ ... ]
+;           bCC label           ; abnormal loop termination
+;           dbu aN, loop        ; normal loop termination
+;
+; Into
+;   loop:
+;           [ ... ]
+;           dbCC aN, loop
+;           bCC label
+;
+; Which moves the bCC condition outside the inner loop for free.
+;
+(define_peephole
+  [(set (pc) (if_then_else (match_operator 3 "comparison_operator"
+                           [(reg:CC 21) (const_int 0)])
+                           (label_ref (match_operand 2 "" ""))
+                           (pc)))
+   (parallel
+    [(set (pc)
+          (if_then_else
+            (ge (plus:QI (match_operand:QI 0 "addr_reg_operand" "+a")
+                         (const_int -1))
+                (const_int 0))
+            (label_ref (match_operand 1 "" ""))
+            (pc)))
+     (set (match_dup 0)
+          (plus:QI (match_dup 0)
+                   (const_int -1)))])]
+  "!c4x_label_conflict (insn, operands[2], operands[1])"
+  "db%I3\\t%0,%l1\\n\\tb%3\\t%l2")
+
+(define_peephole
+  [(set (pc) (if_then_else (match_operator 3 "comparison_operator"
+                           [(reg:CC 21) (const_int 0)])
+                           (label_ref (match_operand 2 "" ""))
+                           (pc)))
+   (parallel
+    [(set (pc)
+          (if_then_else
+            (ne (match_operand:QI 0 "addr_reg_operand" "+a")
+                (const_int 0))
+            (label_ref (match_operand 1 "" ""))
+            (pc)))
+     (set (match_dup 0)
+          (plus:QI (match_dup 0)
+                   (const_int -1)))])]
+  "!c4x_label_conflict (insn, operands[2], operands[1])"
+  "db%I3\\t%0,%l1\\n\\tb%3\\t%l2")
+
+;
+; Peepholes to convert 'call label; rets' into jump label
+;
+(define_peephole
+  [(parallel [(call (match_operand:QI 0 "call_operand" "T,!o")
+                    (match_operand:QI 1 "general_operand" ""))
+              (clobber (reg:QI 31))])
+   (return)]
+  "c4x_null_epilogue_p ()"
+  "@
+   br%#\\t%C0
+   bu%#\\t%R0"
+  [(set_attr "type" "jump,jump")])
+
+(define_peephole
+  [(parallel [(set (match_operand 0 "" "")
+                   (call (match_operand:QI 1 "call_operand" "T,!o")
+                         (match_operand:QI 2 "general_operand" "")))
+              (clobber (reg:QI 31))])
+   (return)]
+  "c4x_null_epilogue_p ()"
+  "@
+   br%#\\t%C1
+   bu%#\\t%R1"
+  [(set_attr "type" "jump,jump")])
+
+;
+; Peepholes for parallel instructions
+;
+(define_peephole
+ [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+       (match_operand:QI 1 "par_ind_operand" ""))
+  (set (match_operand:QI 2 "ext_low_reg_operand" "")
+       (match_operand:QI 3 "par_ind_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[2])) 
+  && !c4x_address_conflict (operands[1], operands[3], 0, 0)"
+ "ldi1\\t%1,%0\\n||\\tldi2\\t%3,%2")
+
+; load occurs before store if 1 and 2 point to same address
+(define_peephole
+ [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+       (match_operand:QI 1 "par_ind_operand" ""))
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))
+  && !c4x_address_conflict (operands[1], operands[2], 0, 1)"
+ "ldi\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+; load occurs before store if 0 and 3 point to same address
+(define_peephole
+ [(set (match_operand:QI 0 "par_ind_operand" "")
+       (match_operand:QI 1 "ext_low_reg_operand" ""))
+  (set (match_operand:QI 2 "ext_low_reg_operand" "")
+       (match_operand:QI 3 "par_ind_operand" ""))]
+ "(REGNO (operands[1]) != REGNO (operands[2]))
+  && !c4x_address_conflict (operands[0], operands[3], 1, 0)"
+ "ldi\\t%3,%2\\n||\\tsti\\t%1,%0")
+
+(define_peephole
+ [(set (match_operand:QI 0 "par_ind_operand" "")
+       (match_operand:QI 1 "ext_low_reg_operand" ""))
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "!c4x_address_conflict (operands[0], operands[2], 1, 1)"
+ "sti\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+; This peephole should be unnecessary with my patches to flow.c
+; for better autoincrement detection
+(define_peephole
+ [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+       (mem:QF (match_operand:QI 1 "addr_reg_operand" "")))
+  (set (match_operand:QF 2 "ext_low_reg_operand" "")
+       (mem:QF (plus:QI (match_dup 1) (const_int 1))))
+  (parallel [(set (match_dup 1) (plus:QI (match_dup 1) (const_int 2)))
+             (clobber (reg:CC_NOOV 21))])]
+ ""
+ "ldf\\t*%1++,%0\\n\\tldf\\t*%1++,%2")
+
+(define_peephole
+ [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+       (match_operand:QF 1 "par_ind_operand" ""))
+  (set (match_operand:QF 2 "ext_low_reg_operand" "")
+       (match_operand:QF 3 "par_ind_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[2]))
+  && !c4x_address_conflict (operands[1], operands[3], 0, 1)"
+ "ldf1\\t%1,%0\\n||\\tldf2\\t%3,%2")
+
+; This peephole should be unnecessary with my patches to flow.c
+; for better autoincrement detection
+(define_peephole
+ [(set (mem:QF (match_operand:QI 0 "addr_reg_operand" ""))
+       (match_operand:QF 1 "ext_low_reg_operand" ""))
+  (set (mem:QF (plus:QI (match_dup 0) (const_int 1)))
+       (match_operand:QF 2 "ext_low_reg_operand" ""))
+  (parallel [(set (match_dup 0) (plus:QI (match_dup 0) (const_int 2)))
+             (clobber (reg:CC_NOOV 21))])]
+ ""
+ "stf\\t%1,*%0++\\n\\tstf\\t%2,*%0++")
+
+(define_peephole
+ [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+       (match_operand:QF 1 "par_ind_operand" ""))
+  (set (match_operand:QF 2 "par_ind_operand" "")
+       (match_operand:QF 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "ldf\\t%1,%0\\n||\\tstf\\t%3,%2")
+
+(define_peephole
+ [(set (match_operand:QF 0 "par_ind_operand" "")
+       (match_operand:QF 1 "ext_low_reg_operand" ""))
+  (set (match_operand:QF 2 "ext_low_reg_operand" "")
+       (match_operand:QF 3 "par_ind_operand" ""))]
+ "!c4x_address_conflict (operands[0], operands[3], 1, 1)"
+ "ldf\\t%3,%2\\n||\\tstf\\t%1,%0")
+
+(define_peephole
+ [(set (match_operand:QF 0 "par_ind_operand" "")
+       (match_operand:QF 1 "ext_low_reg_operand" ""))
+  (set (match_operand:QF 2 "par_ind_operand" "")
+       (match_operand:QF 3 "ext_low_reg_operand" ""))]
+ "!c4x_address_conflict (operands[0], operands[2], 1, 1)"
+ "stf1\\t%1,%0\\n||\\tstf2\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (abs:QF (match_operand:QF 1 "par_ind_operand" ""))
+                                  (match_operand:QF 2 "fp_zero_operand" "")))
+            (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                 (abs:QF (match_dup 1)))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "absf\\t%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (abs:QF (match_operand:QF 1 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QF 2 "par_ind_operand" "")
+       (match_operand:QF 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "absf\\t%1,%0\\n||\\tstf\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (abs:QI (match_operand:QI 1 "par_ind_operand" ""))
+                                  (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (abs:QI (match_dup 1)))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "absi\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (abs:QI (match_operand:QI 1 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "absi\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (plus:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                                            (match_operand:QI 2 "par_ind_operand" ""))
+                                  (const_int 0)))
+             (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (plus:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (plus:QI (match_operand:QI 1 "par_ind_operand" "")
+                                            (match_operand:QI 2 "ext_low_reg_operand" ""))
+                                  (const_int 0)))
+             (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (plus:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (plus:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                           (match_operand:QI 2 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (plus:QI (match_operand:QI 1 "par_ind_operand" "")
+                           (match_operand:QI 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (plus:QF (match_operand:QF 1 "ext_low_reg_operand" "")
+                                           (match_operand:QF 2 "par_ind_operand" ""))
+                                  (match_operand:QF 3 "fp_zero_operand" "")))
+            (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (plus:QF (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QF 4 "par_ind_operand" "")
+       (match_operand:QF 5 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[5]))"
+ "addf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (plus:QF (match_operand:QF 1 "par_ind_operand" "")
+                                           (match_operand:QF 2 "ext_low_reg_operand" ""))
+                                  (match_operand:QF 3 "fp_zero_operand" "")))
+            (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (plus:QF (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QF 4 "par_ind_operand" "")
+       (match_operand:QF 5 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[5]))"
+ "addf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (plus:QF (match_operand:QF 1 "ext_low_reg_operand" "")
+                           (match_operand:QF 2 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "addf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (plus:QF (match_operand:QF 1 "par_ind_operand" "")
+                           (match_operand:QF 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "addf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (and:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                                      (match_operand:QI 2 "par_ind_operand" ""))
+                             (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (and:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (and:QI (match_operand:QI 1 "par_ind_operand" "")
+                                      (match_operand:QI 2 "ext_low_reg_operand" ""))
+                             (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (and:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (and:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                          (match_operand:QI 2 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (and:QI (match_operand:QI 1 "par_ind_operand" "")
+                          (match_operand:QI 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (ashift:QI (match_operand:QI 1 "par_ind_operand" "")
+                             (match_operand:QI 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (ashiftrt:QI (match_operand:QI 1 "par_ind_operand" "")
+                               (neg:QI (match_operand:QI 2 "ext_low_reg_operand" ""))))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (fix:QI (match_operand:QF 1 "par_ind_operand" ""))
+                             (const_int 0)))
+             (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (fix:QI (match_dup 1)))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "fix\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (fix:QI (match_operand:QF 1 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "fix\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (float:QF (match_operand:QI 1 "par_ind_operand" ""))
+                              (match_operand:QF 2 "fp_zero_operand" "")))
+            (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                 (float:QF (match_dup 1)))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "float\\t%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (float:QF (match_operand:QI 1 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QF 2 "par_ind_operand" "")
+       (match_operand:QF 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "float\\t%1,%0\\n||\\tstf\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (mult:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                                            (match_operand:QI 2 "par_ind_operand" ""))
+                                  (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (mult:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (mult:QI (match_operand:QI 1 "par_ind_operand" "")
+                                            (match_operand:QI 2 "ext_low_reg_operand" ""))
+                                  (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (mult:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (mult:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                           (match_operand:QI 2 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (mult:QI (match_operand:QI 1 "par_ind_operand" "")
+                           (match_operand:QI 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (mult:QF (match_operand:QF 1 "ext_low_reg_operand" "")
+                                            (match_operand:QF 2 "par_ind_operand" ""))
+                                  (match_operand:QF 3 "fp_zero_operand" "")))
+             (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                 (mult:QF (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QF 4 "par_ind_operand" "")
+       (match_operand:QF 5 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[5]))"
+ "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (mult:QF (match_operand:QF 1 "par_ind_operand" "")
+                                            (match_operand:QF 2 "ext_low_reg_operand" ""))
+                                  (match_operand:QF 3 "fp_zero_operand" "")))
+             (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                 (mult:QF (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QF 4 "par_ind_operand" "")
+       (match_operand:QF 5 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[5]))"
+ "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (mult:QF (match_operand:QF 1 "ext_low_reg_operand" "")
+                           (match_operand:QF 2 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (mult:QF (match_operand:QF 1 "par_ind_operand" "")
+                           (match_operand:QF 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (neg:QF (match_operand:QF 1 "par_ind_operand" ""))
+                                  (match_operand:QF 2 "fp_zero_operand" "")))
+            (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (neg:QF (match_dup 1)))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "negf\\t%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (neg:QF (match_operand:QF 1 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QF 2 "par_ind_operand" "")
+       (match_operand:QF 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "negf\\t%1,%0\\n||\\tstf\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (neg:QI (match_operand:QI 1 "par_ind_operand" ""))
+                                  (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (neg:QI (match_dup 1)))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "negi\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (neg:QI (match_operand:QI 1 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "negi\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (not:QI (match_operand:QI 1 "par_ind_operand" ""))
+                             (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (not:QI (match_dup 1)))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "not\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (not:QI (match_operand:QI 1 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 2 "par_ind_operand" "")
+       (match_operand:QI 3 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[3]))"
+ "not\\t%1,%0\\n||\\tsti\\t%3,%2")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (ior:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                                     (match_operand:QI 2 "par_ind_operand" ""))
+                             (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (ior:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (ior:QI (match_operand:QI 1 "par_ind_operand" "")
+                                     (match_operand:QI 2 "ext_low_reg_operand" ""))
+                             (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (ior:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (ior:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                          (match_operand:QI 2 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (ior:QI (match_operand:QI 1 "par_ind_operand" "")
+                          (match_operand:QI 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                 (compare:CC_NOOV (minus:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                                            (match_operand:QI 2 "par_ind_operand" ""))
+                                  (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (minus:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "subi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (minus:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                            (match_operand:QI 2 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "subi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC_NOOV 21)
+                  (compare:CC_NOOV (minus:QF (match_operand:QF 1 "ext_low_reg_operand" "")
+                                            (match_operand:QF 2 "par_ind_operand" ""))
+                                  (match_operand:QF 3 "fp_zero_operand" "")))
+           (set (match_operand:QF 0 "ext_low_reg_operand" "")
+                (minus:QF (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QF 4 "par_ind_operand" "")
+       (match_operand:QF 5 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[5]))"
+ "subf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4")
+
+(define_peephole
+ [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "")
+                  (minus:QF (match_operand:QF 1 "ext_low_reg_operand" "")
+                            (match_operand:QF 2 "par_ind_operand" "")))
+             (clobber (reg:CC_NOOV 21))])
+  (set (match_operand:QF 3 "par_ind_operand" "")
+       (match_operand:QF 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "subf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (xor:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                                     (match_operand:QI 2 "par_ind_operand" ""))
+                             (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (xor:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (xor:QI (match_operand:QI 1 "par_ind_operand" "")
+                                     (match_operand:QI 2 "ext_low_reg_operand" ""))
+                             (const_int 0)))
+            (set (match_operand:QI 0 "ext_low_reg_operand" "")
+                 (xor:QI (match_dup 1) (match_dup 2)))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (xor:QI (match_operand:QI 1 "ext_low_reg_operand" "")
+                          (match_operand:QI 2 "par_ind_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+(define_peephole
+ [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "")
+                  (xor:QI (match_operand:QI 1 "par_ind_operand" "")
+                          (match_operand:QI 2 "ext_low_reg_operand" "")))
+             (clobber (reg:CC 21))])
+  (set (match_operand:QI 3 "par_ind_operand" "")
+       (match_operand:QI 4 "ext_low_reg_operand" ""))]
+ "(REGNO (operands[0]) != REGNO (operands[4]))"
+ "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3")
+
+
diff --git a/gcc/config/c4x/t-c4x b/gcc/config/c4x/t-c4x
new file mode 100644 (file)
index 0000000..e696474
--- /dev/null
@@ -0,0 +1,29 @@
+CROSS_LIBGCC1 = libgcc1-asm.a
+LIB1ASMSRC = c4x/libgcc.S
+LIB1ASMFUNCS = _divqf3 _divqi3 _udivqi3 _umodqi3 _modqi3 _mulqi3 \
+       _mulhf3 _divhf3 _unsfltconst _unsfltcompare \
+       _mulhi3 _umulhi3_high _smulhi3_high _divhi3 _modhi3 _umodhi3 _udivhi3 \
+       _fix_truncqfhi2 _ufix_truncqfhi2 _floathiqf2 _ufloathiqf2 \
+       _floathihf2 _ufloathihf2 _fix_trunchfhi2 _ufix_trunchfhi2 _ffs
+
+# We do not have DF or DI types (or SF and SI for that matter),
+# so fake out the libgcc2 compilation.
+LIBGCC2_CFLAGS = -O2 -Dexit=unused_exit $(GCC_CFLAGS) $(LIBGCC2_INCLUDES) -DDF=HF -DDI=HI -DSF=QF -DSI=QI
+
+MULTILIB_OPTIONS = m30 msmall mmemparm
+MULTILIB_DIRNAMES = c3x small mem
+MULTILIB_MATCHES = m30=mcpu?30 m30=mcpu?31 m30=mcpu?32 m30=m31 m30=m32
+MULTILIB_EXCEPTIONS =
+MULTILIB_EXTRA_OPTS =
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+# Don't make libgcc1-test since require crt0.o
+LIBGCC1_TEST =
+
+# Don't make objective C because we can't compile the libraries.
+LANGUAGES = c proto  c++
+
+# C[34]x has its own float and limits.h
+TARGET_FLOAT_H=config/c4x/c4x-float.h
+TARGET_LIMITS_H=config/c4x/c4x-limits.h
diff --git a/gcc/config/c4x/xm-c4x.h b/gcc/config/c4x/xm-c4x.h
new file mode 100644 (file)
index 0000000..dc329eb
--- /dev/null
@@ -0,0 +1,21 @@
+/* #defines that need visibility everywhere.  */
+#define FALSE 0
+#define TRUE 1
+
+/* This describes the machine the compiler is hosted on.  */
+#define HOST_BITS_PER_CHAR 32
+#define HOST_BITS_PER_SHORT 32
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+#define HOST_WORDS_BIG_ENDIAN
+
+/* target machine dependencies.
+   tm.h is a symbolic link to the actual target specific file.   */
+#include "tm.h"
+
+/* Arguments to use with `exit'.  */
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33
+
diff --git a/gcc/ginclude/va-c4x.h b/gcc/ginclude/va-c4x.h
new file mode 100644 (file)
index 0000000..c73c6d5
--- /dev/null
@@ -0,0 +1,34 @@
+/* GNU C varargs support for the TMS320C[34]x  */
+
+/* C[34]x arguments grow in weird ways (downwards) that the standard
+   varargs stuff can't handle. */
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+
+typedef void *__gnuc_va_list;
+
+#endif /* not __GNUC_VA_LIST */
+
+/* If this is for internal libc use, don't define anything but
+   __gnuc_va_list.  */
+#if defined (_STDARG_H) || defined (_VARARGS_H)
+
+#ifdef _STDARG_H /* stdarg.h support */
+
+#define va_start(AP,LASTARG) AP=(__gnuc_va_list) __builtin_next_arg (LASTARG)
+
+#else /* varargs.h support */
+
+#define        __va_ellipsis   ...
+#define        va_alist        __builtin_va_alist
+#define        va_dcl          int __builtin_va_alist; __va_ellipsis
+#define va_start(AP)   AP=(__gnuc_va_list) ((int *)&__builtin_va_alist +  1)
+
+#endif /* _STDARG_H */
+
+#define va_end(AP)     ((void) 0)
+#define va_arg(AP,TYPE)        (AP = (__gnuc_va_list) ((char *) (AP) - sizeof(TYPE)), \
+                        *((TYPE *) ((char *) (AP))))
+
+#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */